Merge branch 'dev' into analytical_cleanup

This commit is contained in:
Hunter Nichols 2019-08-06 14:51:30 -07:00
commit 2efc0a3983
105 changed files with 2331 additions and 2229 deletions

View File

@ -0,0 +1,43 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
class delay_data():
"""
This is the delay class to represent the delay information
Time is 50% of the signal to 50% of reference signal delay.
Slew is the 10% of the signal to 90% of signal
"""
def __init__(self, delay=0.0, slew=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.delay = delay
self.slew = slew
def __str__(self):
""" override print function output """
return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
def __add__(self, other):
"""
Override - function (left), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
other.slew)
def __radd__(self, other):
"""
Override - function (right), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
self.slew)

View File

@ -10,8 +10,9 @@ from vector import vector
from pin_layout import pin_layout from pin_layout import pin_layout
class timing_graph(): class timing_graph():
"""Implements a directed graph """
Nodes are currently just Strings. Implements a directed graph
Nodes are currently just Strings.
""" """
def __init__(self): def __init__(self):
@ -20,30 +21,34 @@ class timing_graph():
def add_edge(self, src_node, dest_node): def add_edge(self, src_node, dest_node):
"""Adds edge to graph. Nodes added as well if they do not exist.""" """Adds edge to graph. Nodes added as well if they do not exist."""
src_node = src_node.lower() src_node = src_node.lower()
dest_node = dest_node.lower() dest_node = dest_node.lower()
self.graph[src_node].add(dest_node) self.graph[src_node].add(dest_node)
def add_node(self, node): def add_node(self, node):
"""Add node to graph with no edges""" """Add node to graph with no edges"""
node = node.lower() node = node.lower()
if not node in self.graph: if not node in self.graph:
self.graph[node] = set() self.graph[node] = set()
def remove_edges(self, node): def remove_edges(self, node):
"""Helper function to remove edges, useful for removing vdd/gnd""" """Helper function to remove edges, useful for removing vdd/gnd"""
node = node.lower() node = node.lower()
self.graph[node] = set() self.graph[node] = set()
def get_all_paths(self, src_node, dest_node, rmv_rail_nodes=True): def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True):
"""Traverse all paths from source to destination""" """Traverse all paths from source to destination"""
src_node = src_node.lower() src_node = src_node.lower()
dest_node = dest_node.lower() dest_node = dest_node.lower()
#Remove vdd and gnd by default # Remove vdd and gnd by default
#Will require edits if separate supplies are implemented. # Will require edits if separate supplies are implemented.
if rmv_rail_nodes: if remove_rail_nodes:
#Names are also assumed. # Names are also assumed.
self.remove_edges('vdd') self.remove_edges('vdd')
self.remove_edges('gnd') self.remove_edges('gnd')
@ -57,11 +62,20 @@ class timing_graph():
# Call the recursive helper function to print all paths # Call the recursive helper function to print all paths
self.get_all_paths_util(src_node, dest_node, visited, path) self.get_all_paths_util(src_node, dest_node, visited, path)
debug.info(2, "Paths found={}".format(len(self.all_paths))) debug.info(2, "Paths found={}".format(len(self.all_paths)))
if reduce_paths:
self.reduce_paths()
return self.all_paths return self.all_paths
def reduce_paths(self):
""" Remove any path that is a subset of another path """
self.all_paths = [p1 for p1 in self.all_paths if not any(set(p1)<=set(p2) for p2 in self.all_paths if p1 is not p2)]
def get_all_paths_util(self, cur_node, dest_node, visited, path): def get_all_paths_util(self, cur_node, dest_node, visited, path):
"""Recursive function to find all paths in a Depth First Search manner""" """Recursive function to find all paths in a Depth First Search manner"""
# Mark the current node as visited and store in path # Mark the current node as visited and store in path
visited.add(cur_node) visited.add(cur_node)
path.append(cur_node) path.append(cur_node)
@ -72,7 +86,7 @@ class timing_graph():
self.all_paths.append(copy.deepcopy(path)) self.all_paths.append(copy.deepcopy(path))
else: else:
# If current vertex is not destination # If current vertex is not destination
#Recur for all the vertices adjacent to this vertex # Recur for all the vertices adjacent to this vertex
for node in self.graph[cur_node]: for node in self.graph[cur_node]:
if node not in visited: if node not in visited:
self.get_all_paths_util(node, dest_node, visited, path) self.get_all_paths_util(node, dest_node, visited, path)
@ -83,4 +97,5 @@ class timing_graph():
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph)
return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph)

View File

@ -10,6 +10,9 @@ import re
import os import os
import math import math
import tech import tech
from delay_data import *
from wire_spice_model import *
from power_data import *
class spice(): class spice():
@ -25,6 +28,7 @@ class spice():
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = [] self.mods = []
# Holds the pins for this module # Holds the pins for this module
@ -49,27 +53,32 @@ class spice():
def add_comment(self, comment): def add_comment(self, comment):
""" Add a comment to the spice file """ """ Add a comment to the spice file """
try: try:
self.commments self.commments
except: except:
self.comments = [] self.comments = []
else:
self.comments.append(comment) self.comments.append(comment)
def add_pin(self, name, pin_type="INOUT"): def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """ """ Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name) self.pins.append(name)
self.pin_type[name]=pin_type self.pin_type[name]=pin_type
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
def add_pin_list(self, pin_list, pin_type_list="INOUT"): def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """ """ Adds a pin_list to the pins list """
# The type list can be a single type for all pins # The type list can be a single type for all pins
# or a list that is the same length as the pin list. # or a list that is the same length as the pin list.
if type(pin_type_list)==str: if type(pin_type)==str:
for pin in pin_list: for pin in pin_list:
self.add_pin(pin,pin_type_list) debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type))
elif len(pin_type_list)==len(pin_list): self.add_pin(pin,pin_type)
for (pin,ptype) in zip(pin_list, pin_type_list):
elif len(pin_type)==len(pin_list):
for (pin,ptype) in zip(pin_list, pin_type):
debug.check(ptype in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,ptype))
self.add_pin(pin,ptype) self.add_pin(pin,ptype)
else: else:
debug.error("Mismatch in type and pin list lengths.", -1) debug.error("Mismatch in type and pin list lengths.", -1)
@ -87,7 +96,9 @@ class spice():
def get_pin_type(self, name): def get_pin_type(self, name):
""" Returns the type of the signal pin. """ """ Returns the type of the signal pin. """
return self.pin_type[name] pin_type = self.pin_type[name]
debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
return pin_type
def get_pin_dir(self, name): def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """ """ Returns the direction of the pin. (Supply/ground are INOUT). """
@ -238,9 +249,12 @@ class spice():
sp.write("\n.SUBCKT {0} {1}\n".format(self.name, sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
" ".join(self.pins))) " ".join(self.pins)))
for pin in self.pins:
sp.write("* {1:6}: {0} \n".format(pin,self.pin_type[pin]))
for line in self.comments: for line in self.comments:
sp.write("* {}\n".format(line)) sp.write("* {}\n".format(line))
# every instance must have a set of connections, even if it is empty. # every instance must have a set of connections, even if it is empty.
if len(self.insts)!=len(self.conns): if len(self.insts)!=len(self.conns):
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
@ -383,102 +397,3 @@ class spice():
def return_power(self, dynamic=0.0, leakage=0.0): def return_power(self, dynamic=0.0, leakage=0.0):
return power_data(dynamic, leakage) return power_data(dynamic, leakage)
class delay_data:
"""
This is the delay class to represent the delay information
Time is 50% of the signal to 50% of reference signal delay.
Slew is the 10% of the signal to 90% of signal
"""
def __init__(self, delay=0.0, slew=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.delay = delay
self.slew = slew
def __str__(self):
""" override print function output """
return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
def __add__(self, other):
"""
Override - function (left), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
other.slew)
def __radd__(self, other):
"""
Override - function (right), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
self.slew)
class power_data:
"""
This is the power class to represent the power information
Dynamic and leakage power are stored as a single object with this class.
"""
def __init__(self, dynamic=0.0, leakage=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.dynamic = dynamic
self.leakage = leakage
def __str__(self):
""" override print function output """
return "Power Data: Dynamic "+str(self.dynamic)+", Leakage "+str(self.leakage)+" in nW"
def __add__(self, other):
"""
Override - function (left), for power_data: a+b != b+a
"""
assert isinstance(other,power_data)
return power_data(other.dynamic + self.dynamic,
other.leakage + self.leakage)
def __radd__(self, other):
"""
Override - function (left), for power_data: a+b != b+a
"""
assert isinstance(other,power_data)
return power_data(other.dynamic + self.dynamic,
other.leakage + self.leakage)
class wire_spice_model:
"""
This is the spice class to represent a wire
"""
def __init__(self, lump_num, wire_length, wire_width):
self.lump_num = lump_num # the number of segment the wire delay has
self.wire_c = self.cal_wire_c(wire_length, wire_width) # c in each segment
self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
def cal_wire_c(self, wire_length, wire_width):
from tech import spice
total_c = spice["wire_unit_c"] * wire_length * wire_width
wire_c = total_c / self.lump_num
return wire_c
def cal_wire_r(self, wire_length, wire_width):
from tech import spice
total_r = spice["wire_unit_r"] * wire_length / wire_width
wire_r = total_r / self.lump_num
return wire_r
def return_input_cap(self):
return 0.5 * self.wire_c * self.lump_num
def return_delay_over_wire(self, slew, swing = 0.5):
# delay will be sum of arithmetic sequence start from
# rc to self.lump_num*rc with step of rc
swing_factor = abs(math.log(1-swing)) # time constant based on swing
sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
delay = sum_factor * swing_factor * self.wire_r * self.wire_c
slew = delay * 2 + slew
result= delay_data(delay, slew)
return result

View File

@ -0,0 +1,38 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
class power_data():
"""
This is the power class to represent the power information
Dynamic and leakage power are stored as a single object with this class.
"""
def __init__(self, dynamic=0.0, leakage=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.dynamic = dynamic
self.leakage = leakage
def __str__(self):
""" override print function output """
return "Power Data: Dynamic "+str(self.dynamic)+", Leakage "+str(self.leakage)+" in nW"
def __add__(self, other):
"""
Override - function (left), for power_data: a+b != b+a
"""
assert isinstance(other,power_data)
return power_data(other.dynamic + self.dynamic,
other.leakage + self.leakage)
def __radd__(self, other):
"""
Override - function (left), for power_data: a+b != b+a
"""
assert isinstance(other,power_data)
return power_data(other.dynamic + self.dynamic,
other.leakage + self.leakage)

View File

@ -0,0 +1,42 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
class wire_spice_model():
"""
This is the spice class to represent a wire
"""
def __init__(self, lump_num, wire_length, wire_width):
self.lump_num = lump_num # the number of segment the wire delay has
self.wire_c = self.cal_wire_c(wire_length, wire_width) # c in each segment
self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
def cal_wire_c(self, wire_length, wire_width):
from tech import spice
total_c = spice["wire_unit_c"] * wire_length * wire_width
wire_c = total_c / self.lump_num
return wire_c
def cal_wire_r(self, wire_length, wire_width):
from tech import spice
total_r = spice["wire_unit_r"] * wire_length / wire_width
wire_r = total_r / self.lump_num
return wire_r
def return_input_cap(self):
return 0.5 * self.wire_c * self.lump_num
def return_delay_over_wire(self, slew, swing = 0.5):
# delay will be sum of arithmetic sequence start from
# rc to self.lump_num*rc with step of rc
swing_factor = abs(math.log(1-swing)) # time constant based on swing
sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
delay = sum_factor * swing_factor * self.wire_r * self.wire_c
slew = delay * 2 + slew
result= delay_data(delay, slew)
return result

View File

@ -42,34 +42,41 @@ class bitcell(design.design):
cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
return logical_effort.logical_effort('bitline', size, cin, load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load, parasitic_delay, False)
def list_all_wl_names(self): def get_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
row_pins = ["wl"] row_pins = ["wl"]
return row_pins return row_pins
def list_all_bitline_names(self): def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """ """ Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl", "br"] column_pins = ["bl", "br"]
return column_pins return column_pins
def list_all_bl_names(self): def get_all_bl_names(self):
""" Creates a list of all bl pins names """ """ Creates a list of all bl pins names """
column_pins = ["bl"] column_pins = ["bl"]
return column_pins return column_pins
def list_all_br_names(self): def get_all_br_names(self):
""" Creates a list of all br pins names """ """ Creates a list of all br pins names """
column_pins = ["br"] column_pins = ["br"]
return column_pins return column_pins
def get_bl_name(self): def get_bl_name(self, port=0):
"""Get bl name""" """Get bl name"""
debug.check(port==0,"One port for bitcell only.")
return "bl" return "bl"
def get_br_name(self): def get_br_name(self, port=0):
"""Get bl name""" """Get bl name"""
debug.check(port==0,"One port for bitcell only.")
return "br" return "br"
def get_wl_name(self, port=0):
"""Get wl name"""
debug.check(port==0,"One port for bitcell only.")
return "wl"
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage.""" """Bitcell power in nW. Only characterizes leakage."""
from tech import spice from tech import spice
@ -96,4 +103,4 @@ class bitcell(design.design):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -43,7 +43,7 @@ class bitcell_1rw_1r(design.design):
read_port_load = 0.5 #min size NMOS gate load read_port_load = 0.5 #min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False)
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = ["bl0_{0}".format(col), bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col), "br0_{0}".format(col),
@ -55,53 +55,60 @@ class bitcell_1rw_1r(design.design):
"gnd"] "gnd"]
return bitcell_pins return bitcell_pins
def list_all_wl_names(self): def get_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
row_pins = ["wl0", "wl1"] row_pins = ["wl0", "wl1"]
return row_pins return row_pins
def list_all_bitline_names(self): def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """ """ Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl0", "br0", "bl1", "br1"] column_pins = ["bl0", "br0", "bl1", "br1"]
return column_pins return column_pins
def list_all_bl_names(self): def get_all_bl_names(self):
""" Creates a list of all bl pins names """ """ Creates a list of all bl pins names """
column_pins = ["bl0", "bl1"] column_pins = ["bl0", "bl1"]
return column_pins return column_pins
def list_all_br_names(self): def get_all_br_names(self):
""" Creates a list of all br pins names """ """ Creates a list of all br pins names """
column_pins = ["br0", "br1"] column_pins = ["br0", "br1"]
return column_pins return column_pins
def list_read_bl_names(self): def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """ """ Creates a list of bl pin names associated with read ports """
column_pins = ["bl0", "bl1"] column_pins = ["bl0", "bl1"]
return column_pins return column_pins
def list_read_br_names(self): def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """ """ Creates a list of br pin names associated with read ports """
column_pins = ["br0", "br1"] column_pins = ["br0", "br1"]
return column_pins return column_pins
def list_write_bl_names(self): def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """ """ Creates a list of bl pin names associated with write ports """
column_pins = ["bl0"] column_pins = ["bl0"]
return column_pins return column_pins
def list_write_br_names(self): def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports""" """ Creates a list of br pin names asscociated with write ports"""
column_pins = ["br0"] column_pins = ["br0"]
return column_pins return column_pins
def get_bl_name(self, port=0): def get_bl_name(self, port=0):
"""Get bl name by port""" """Get bl name by port"""
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
return "bl{}".format(port) return "bl{}".format(port)
def get_br_name(self, port=0): def get_br_name(self, port=0):
"""Get bl name by port""" """Get bl name by port"""
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
return "br{}".format(port) return "br{}".format(port)
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
return "wl{}".format(port)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage.""" """Bitcell power in nW. Only characterizes leakage."""

View File

@ -43,7 +43,7 @@ class bitcell_1w_1r(design.design):
read_port_load = 0.5 #min size NMOS gate load read_port_load = 0.5 #min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False)
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = ["bl0_{0}".format(col), bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col), "br0_{0}".format(col),
@ -55,42 +55,42 @@ class bitcell_1w_1r(design.design):
"gnd"] "gnd"]
return bitcell_pins return bitcell_pins
def list_all_wl_names(self): def get_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
row_pins = ["wl0", "wl1"] row_pins = ["wl0", "wl1"]
return row_pins return row_pins
def list_all_bitline_names(self): def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """ """ Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl0", "br0", "bl1", "br1"] column_pins = ["bl0", "br0", "bl1", "br1"]
return column_pins return column_pins
def list_all_bl_names(self): def get_all_bl_names(self):
""" Creates a list of all bl pins names """ """ Creates a list of all bl pins names """
column_pins = ["bl0", "bl1"] column_pins = ["bl0", "bl1"]
return column_pins return column_pins
def list_all_br_names(self): def get_all_br_names(self):
""" Creates a list of all br pins names """ """ Creates a list of all br pins names """
column_pins = ["br0", "br1"] column_pins = ["br0", "br1"]
return column_pins return column_pins
def list_read_bl_names(self): def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """ """ Creates a list of bl pin names associated with read ports """
column_pins = ["bl0", "bl1"] column_pins = ["bl0", "bl1"]
return column_pins return column_pins
def list_read_br_names(self): def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """ """ Creates a list of br pin names associated with read ports """
column_pins = ["br0", "br1"] column_pins = ["br0", "br1"]
return column_pins return column_pins
def list_write_bl_names(self): def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """ """ Creates a list of bl pin names associated with write ports """
column_pins = ["bl0"] column_pins = ["bl0"]
return column_pins return column_pins
def list_write_br_names(self): def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports""" """ Creates a list of br pin names asscociated with write ports"""
column_pins = ["br0"] column_pins = ["br0"]
return column_pins return column_pins
@ -103,6 +103,11 @@ class bitcell_1w_1r(design.design):
"""Get bl name by port""" """Get bl name by port"""
return "br{}".format(port) return "br{}".format(port)
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
return "wl{}".format(port)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage.""" """Bitcell power in nW. Only characterizes leakage."""
from tech import spice from tech import spice
@ -134,6 +139,6 @@ class bitcell_1w_1r(design.design):
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports. #Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges # Port 0 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
# Port 1 is a write port, so its timing is not considered here. # Port 1 is a write port, so its timing is not considered here.

View File

@ -0,0 +1,45 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import design
import debug
import utils
from tech import GDS,layer,drc,parameter
class dummy_bitcell_1rw_1r(design.design):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dummy_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1rw_1r", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "dummy_cell_1rw_1r")
debug.info(2, "Create dummy bitcell 1rw+1r object")
self.width = dummy_bitcell_1rw_1r.width
self.height = dummy_bitcell_1rw_1r.height
self.pin_map = dummy_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Dummy bitcells are cannot form a path and be part of the timing graph"""
return

View File

@ -0,0 +1,45 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import design
import debug
import utils
from tech import GDS,layer,drc,parameter
class dummy_bitcell_1w_1r(design.design):
"""
A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dummy_cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1w_1r", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "dummy_cell_1w_1r")
debug.info(2, "Create dummy bitcell 1w+1r object")
self.width = dummy_bitcell_1w_1r.width
self.height = dummy_bitcell_1w_1r.height
self.pin_map = dummy_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
#FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
def build_graph(self, graph, inst_name, port_nets):
"""Dummy bitcells are cannot form a path and be part of the timing graph"""
return

View File

@ -0,0 +1,91 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import design
from tech import drc, spice,parameter
from vector import vector
from globals import OPTS
from sram_factory import factory
class dummy_pbitcell(design.design):
"""
Creates a replica bitcell using pbitcell
"""
def __init__(self, name):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
design.design.__init__(self, name)
debug.info(1, "create a dummy bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports,
self.num_r_ports))
self.create_netlist()
self.create_layout()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
self.place_pbitcell()
self.route_rbc_connections()
self.DRC_LVS()
def add_pins(self):
for port in range(self.total_ports):
self.add_pin("bl{}".format(port))
self.add_pin("br{}".format(port))
for port in range(self.total_ports):
self.add_pin("wl{}".format(port))
self.add_pin("vdd")
self.add_pin("gnd")
def add_modules(self):
self.prbc = factory.create(module_type="pbitcell",dummy_bitcell=True)
self.add_mod(self.prbc)
self.height = self.prbc.height
self.width = self.prbc.width
def create_modules(self):
self.prbc_inst = self.add_inst(name="pbitcell",
mod=self.prbc)
temp = []
for port in range(self.total_ports):
temp.append("bl{}".format(port))
temp.append("br{}".format(port))
for port in range(self.total_ports):
temp.append("wl{}".format(port))
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_pbitcell(self):
self.prbc_inst.place(offset=vector(0,0))
def route_rbc_connections(self):
for port in range(self.total_ports):
self.copy_layout_pin(self.prbc_inst, "bl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "br{}".format(port))
for port in range(self.total_ports):
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd")
def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates"""
#This module is made using a pbitcell. Get the cin from that module
return self.prbc.get_wl_cin()

View File

@ -20,21 +20,30 @@ class pbitcell(design.design):
with a variable number of read/write, write, and read ports with a variable number of read/write, write, and read ports
""" """
def __init__(self, name, replica_bitcell=False): def __init__(self, name, replica_bitcell=False, dummy_bitcell=False):
self.num_rw_ports = OPTS.num_rw_ports self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
self.replica_bitcell = replica_bitcell self.replica_bitcell = replica_bitcell
self.dummy_bitcell = dummy_bitcell
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, info_string = "{0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,
self.num_r_ports)) self.num_r_ports)
debug.info(2, "create a multi-port bitcell with {}".format(info_string))
self.add_comment(info_string)
if self.dummy_bitcell:
self.add_comment("dummy bitcell")
if self.replica_bitcell:
self.add_comment("replica bitcell")
self.create_netlist() self.create_netlist()
# We must always create the bitcell layout because some transistor sizes in the other netlists depend on it # We must always create the bitcell layout
# because some transistor sizes in the other netlists depend on it
self.create_layout() self.create_layout()
self.add_boundary() self.add_boundary()
@ -376,14 +385,20 @@ class pbitcell(design.design):
# iterate over the number of read/write ports # iterate over the number of read/write ports
for k in range(0,self.num_rw_ports): for k in range(0,self.num_rw_ports):
bl_name = self.rw_bl_names[k]
br_name = self.rw_br_names[k]
if self.dummy_bitcell:
bl_name += "_noconn"
br_name += "_noconn"
# add read/write transistors # add read/write transistors
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
mod=self.readwrite_nmos) mod=self.readwrite_nmos)
self.connect_inst([self.rw_bl_names[k], self.rw_wl_names[k], self.Q, "gnd"]) self.connect_inst([bl_name, self.rw_wl_names[k], self.Q, "gnd"])
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k), self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos) mod=self.readwrite_nmos)
self.connect_inst([self.Q_bar, self.rw_wl_names[k], self.rw_br_names[k], "gnd"]) self.connect_inst([self.Q_bar, self.rw_wl_names[k], br_name, "gnd"])
def place_readwrite_ports(self): def place_readwrite_ports(self):
""" Places read/write ports in the bit cell """ """ Places read/write ports in the bit cell """
@ -450,14 +465,20 @@ class pbitcell(design.design):
# iterate over the number of write ports # iterate over the number of write ports
for k in range(0,self.num_w_ports): for k in range(0,self.num_w_ports):
bl_name = self.w_bl_names[k]
br_name = self.w_br_names[k]
if self.dummy_bitcell:
bl_name += "_noconn"
br_name += "_noconn"
# add write transistors # add write transistors
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
mod=self.write_nmos) mod=self.write_nmos)
self.connect_inst([self.w_bl_names[k], self.w_wl_names[k], self.Q, "gnd"]) self.connect_inst([bl_name, self.w_wl_names[k], self.Q, "gnd"])
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k), self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos) mod=self.write_nmos)
self.connect_inst([self.Q_bar, self.w_wl_names[k], self.w_br_names[k], "gnd"]) self.connect_inst([self.Q_bar, self.w_wl_names[k], br_name, "gnd"])
def place_write_ports(self): def place_write_ports(self):
""" Places write ports in the bit cell """ """ Places write ports in the bit cell """
@ -532,6 +553,12 @@ class pbitcell(design.design):
# iterate over the number of read ports # iterate over the number of read ports
for k in range(0,self.num_r_ports): for k in range(0,self.num_r_ports):
bl_name = self.r_bl_names[k]
br_name = self.r_br_names[k]
if self.dummy_bitcell:
bl_name += "_noconn"
br_name += "_noconn"
# add read-access transistors # add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
mod=self.read_nmos) mod=self.read_nmos)
@ -544,11 +571,11 @@ class pbitcell(design.design):
# add read transistors # add read transistors
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
mod=self.read_nmos) mod=self.read_nmos)
self.connect_inst([self.r_bl_names[k], self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"]) self.connect_inst([bl_name, self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"])
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k), self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k),
mod=self.read_nmos) mod=self.read_nmos)
self.connect_inst(["RA_to_R_right{}".format(k), self.r_wl_names[k], self.r_br_names[k], "gnd"]) self.connect_inst(["RA_to_R_right{}".format(k), self.r_wl_names[k], br_name, "gnd"])
def place_read_ports(self): def place_read_ports(self):
""" Places the read ports in the bit cell """ """ Places the read ports in the bit cell """
@ -686,8 +713,10 @@ class pbitcell(design.design):
port_contact_offest = left_port_transistors[k].get_pin("S").center() port_contact_offest = left_port_transistors[k].get_pin("S").center()
bl_offset = vector(bl_positions[k].x, port_contact_offest.y) bl_offset = vector(bl_positions[k].x, port_contact_offest.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), # Leave bitline disconnected if a dummy cell
offset=port_contact_offest) if not self.dummy_bitcell:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height) self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height)
@ -695,8 +724,10 @@ class pbitcell(design.design):
port_contact_offest = right_port_transistors[k].get_pin("D").center() port_contact_offest = right_port_transistors[k].get_pin("D").center()
br_offset = vector(br_positions[k].x, port_contact_offest.y) br_offset = vector(br_positions[k].x, port_contact_offest.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), # Leave bitline disconnected if a dummy cell
offset=port_contact_offest) if not self.dummy_bitcell:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height) self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height)
@ -846,7 +877,7 @@ class pbitcell(design.design):
implant_type="n", implant_type="n",
well_type="n") well_type="n")
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
for port in range(self.total_ports): for port in range(self.total_ports):
@ -858,12 +889,12 @@ class pbitcell(design.design):
bitcell_pins.append("gnd") bitcell_pins.append("gnd")
return bitcell_pins return bitcell_pins
def list_all_wl_names(self): def get_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_names wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_names
return wordline_names return wordline_names
def list_all_bitline_names(self): def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """ """ Creates a list of all bitline pin names (both bl and br) """
bitline_pins = [] bitline_pins = []
for port in range(self.total_ports): for port in range(self.total_ports):
@ -871,15 +902,13 @@ class pbitcell(design.design):
bitline_pins.append("br{0}".format(port)) bitline_pins.append("br{0}".format(port))
return bitline_pins return bitline_pins
def list_all_bl_names(self): def get_all_bl_names(self):
""" Creates a list of all bl pins names """ """ Creates a list of all bl pins names """
bl_pins = self.rw_bl_names + self.w_bl_names + self.r_bl_names return self.rw_bl_names + self.w_bl_names + self.r_bl_names
return bl_pins
def list_all_br_names(self): def get_all_br_names(self):
""" Creates a list of all br pins names """ """ Creates a list of all br pins names """
br_pins = self.rw_br_names + self.w_br_names + self.r_br_names return self.rw_br_names + self.w_br_names + self.r_br_names
return br_pins
def route_rbc_short(self): def route_rbc_short(self):
""" route the short from Q_bar to gnd necessary for the replica bitcell """ """ route the short from Q_bar to gnd necessary for the replica bitcell """
@ -897,7 +926,13 @@ class pbitcell(design.design):
def get_br_name(self, port=0): def get_br_name(self, port=0):
"""Get bl name by port""" """Get bl name by port"""
return "br{}".format(port) return "br{}".format(port)
def get_wl_name(self, port=0):
"""Get wl name by port"""
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
return "wl{}".format(port)
def analytical_delay(self, corner, slew, load=0, swing = 0.5): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1
@ -927,11 +962,16 @@ class pbitcell(design.design):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph for pbitcell. Only readwrite and read ports.""" """Adds edges to graph for pbitcell. Only readwrite and read ports."""
if self.dummy_bitcell:
return
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
# Edges added wl->bl, wl->br for every port except write ports # Edges added wl->bl, wl->br for every port except write ports
rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names) rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names)
r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names) r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names)
for pin_zip in zip(rw_pin_names, r_pin_names):
for pin_zip in [rw_pin_names, r_pin_names]:
for wl,bl,br in pin_zip: for wl,bl,br in pin_zip:
graph.add_edge(pin_dict[wl],pin_dict[bl]) graph.add_edge(pin_dict[wl],pin_dict[bl])
graph.add_edge(pin_dict[wl],pin_dict[br]) graph.add_edge(pin_dict[wl],pin_dict[br])

View File

@ -43,9 +43,10 @@ class replica_bitcell_1w_1r(design.design):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex """Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function.""" to use the add_graph_edges function."""
debug.info(1,'Adding edges for {}'.format(inst_name))
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
#Edges hardcoded here. Essentially wl->bl/br for both ports. #Edges hardcoded here. Essentially wl->bl/br for the read port.
# Port 0 edges # Port 1 edges
graph.add_edge(pin_dict["wl0"], pin_dict["bl0"]) graph.add_edge(pin_dict["wl1"], pin_dict["bl1"])
graph.add_edge(pin_dict["wl0"], pin_dict["br0"]) graph.add_edge(pin_dict["wl1"], pin_dict["br1"])
# Port 1 is a write port, so its timing is not considered here. # Port 0 is a write port, so its timing is not considered here.

View File

@ -13,7 +13,6 @@ from .lib import *
from .delay import * from .delay import *
from .setup_hold import * from .setup_hold import *
from .functional import * from .functional import *
from .worst_case import *
from .simulation import * from .simulation import *
from .measurements import * from .measurements import *
from .model_check import * from .model_check import *

View File

@ -0,0 +1,14 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from enum import Enum
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1

View File

@ -8,17 +8,7 @@
import re import re
import debug import debug
from globals import OPTS from globals import OPTS
from enum import Enum
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1
def relative_compare(value1,value2,error_tolerance=0.001): def relative_compare(value1,value2,error_tolerance=0.001):
""" This is used to compare relative values for convergence. """ """ This is used to compare relative values for convergence. """
@ -102,4 +92,4 @@ def check_dict_values_is_float(dict):
for key, value in dict.items(): for key, value in dict.items():
if type(value)!=float: if type(value)!=float:
return False return False
return True return True

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import sys,re,shutil import sys,re,shutil
import collections
from design import design from design import design
import debug import debug
import math import math
@ -15,9 +16,10 @@ from .stimuli import *
from .charutils import * from .charutils import *
import utils import utils
from globals import OPTS from globals import OPTS
from .simulation import simulation from .simulation import simulation
from .delay import delay from .delay import delay
import graph_util
from sram_factory import factory
class functional(simulation): class functional(simulation):
""" """
@ -39,17 +41,24 @@ class functional(simulation):
self.set_corner(corner) self.set_corner(corner)
self.set_spice_constants() self.set_spice_constants()
#self.set_feasible_period(sram, spfile, corner)
self.set_stimulus_variables() self.set_stimulus_variables()
# For the debug signal names
self.create_signal_names() self.create_signal_names()
self.add_graph_exclusions()
self.create_graph()
self.set_internal_spice_names()
self.initialize_wmask() self.initialize_wmask()
# Number of checks can be changed # Number of checks can be changed
self.num_cycles = 2 self.num_cycles = 15
self.stored_words = {} # This is to have ordered keys for random selection
self.stored_words = collections.OrderedDict()
self.write_check = [] self.write_check = []
self.read_check = [] self.read_check = []
def initialize_wmask(self): def initialize_wmask(self):
self.wmask = "" self.wmask = ""
if self.write_size is not None: if self.write_size is not None:
@ -132,7 +141,6 @@ class functional(simulation):
elif op == "write": elif op == "write":
addr = self.gen_addr() addr = self.gen_addr()
word = self.gen_data() word = self.gen_data()
# print("write",self.t_current,addr,word)
# two ports cannot write to the same address # two ports cannot write to the same address
if addr in w_addrs: if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
@ -154,7 +162,6 @@ class functional(simulation):
lower = bit * self.write_size lower = bit * self.write_size
upper = lower + self.write_size - 1 upper = lower + self.write_size - 1
new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:] new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:]
# print("partial_w",self.t_current,addr,wmask,word, "partial_w_word:", new_word)
# two ports cannot write to the same address # two ports cannot write to the same address
if addr in w_addrs: if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
@ -165,7 +172,6 @@ class functional(simulation):
w_addrs.append(addr) w_addrs.append(addr)
else: else:
(addr,word) = random.choice(list(self.stored_words.items())) (addr,word) = random.choice(list(self.stored_words.items()))
# print("read",self.t_current,addr,word)
# cannot read from an address that is currently being written to # cannot read from an address that is currently being written to
if addr in w_addrs: if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
@ -241,23 +247,14 @@ class functional(simulation):
def gen_data(self): def gen_data(self):
""" Generates a random word to write. """ """ Generates a random word to write. """
rand = random.randint(0,(2**self.word_size)-1) random_value = random.randint(0,(2**self.word_size)-1)
data_bits = self.convert_to_bin(rand,False) data_bits = self.convert_to_bin(random_value,False)
return data_bits return data_bits
def gen_data_all_bits(self):
""" Generates a random word, either all 0's or all 1's, to write. """
rand = random.randint(0,1)
bits = []
for bit in range(self.word_size):
bits.append(rand)
data_bits = ''.join(map(str,bits))
return data_bits
def gen_addr(self): def gen_addr(self):
""" Generates a random address value to write to. """ """ Generates a random address value to write to. """
rand = random.randint(0,(2**self.addr_size)-1) random_value = random.randint(0,(2**self.addr_size)-1)
addr_bits = self.convert_to_bin(rand,True) addr_bits = self.convert_to_bin(random_value,True)
return addr_bits return addr_bits
def get_data(self): def get_data(self):
@ -273,6 +270,7 @@ class functional(simulation):
if(is_addr): if(is_addr):
expected_value = self.addr_size expected_value = self.addr_size
else: else:
expected_value = self.word_size expected_value = self.word_size
for i in range (expected_value - len(new_value)): for i in range (expected_value - len(new_value)):
new_value = "0" + new_value new_value = "0" + new_value
@ -288,9 +286,7 @@ class functional(simulation):
self.stim = stimuli(self.sf,self.corner) self.stim = stimuli(self.sf,self.corner)
#Write include statements #Write include statements
self.sram_sp_file = "{}sram.sp".format(OPTS.openram_temp) self.stim.write_include(self.sp_file)
shutil.copy(self.sp_file, self.sram_sp_file)
self.stim.write_include(self.sram_sp_file)
#Write Vdd/Gnd statements #Write Vdd/Gnd statements
self.sf.write("\n* Global Power Supplies\n") self.sf.write("\n* Global Power Supplies\n")
@ -307,9 +303,17 @@ class functional(simulation):
for bit in range(self.word_size): for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.dout_name, port, bit) sig_name="{0}{1}_{2} ".format(self.dout_name, port, bit)
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(port, bit, sig_name, self.load)) self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(port, bit, sig_name, self.load))
# Write important signals to stim file
self.sf.write("\n\n* Important signals for debug\n")
self.sf.write("* bl: {}\n".format(self.bl_name))
self.sf.write("* br: {}\n".format(self.br_name))
self.sf.write("* s_en: {}\n".format(self.sen_name))
self.sf.write("* q: {}\n".format(self.q_name))
self.sf.write("* qbar: {}\n".format(self.qbar_name))
# Write debug comments to stim file # Write debug comments to stim file
self.sf.write("\n\n * Sequence of operations\n") self.sf.write("\n\n* Sequence of operations\n")
for comment in self.fn_cycle_comments: for comment in self.fn_cycle_comments:
self.sf.write("*{}\n".format(comment)) self.sf.write("*{}\n".format(comment))
@ -369,4 +373,117 @@ class functional(simulation):
self.stim.write_control(self.cycle_times[-1] + self.period) self.stim.write_control(self.cycle_times[-1] + self.period)
self.sf.close() self.sf.close()
# FIXME: refactor to share with delay.py
def add_graph_exclusions(self):
"""Exclude portions of SRAM from timing graph which are not relevant"""
# other initializations can only be done during analysis when a bit has been selected
# for testing.
self.sram.bank.graph_exclude_precharge()
self.sram.graph_exclude_addr_dff()
self.sram.graph_exclude_data_dff()
self.sram.graph_exclude_ctrl_dffs()
self.sram.bank.bitcell_array.graph_exclude_replica_col_bits()
# FIXME: refactor to share with delay.py
def create_graph(self):
"""Creates timing graph to generate the timing paths for the SRAM output."""
self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
# Does wordline=0 and column=0 just for debug names
self.sram.bank.bitcell_array.graph_exclude_bits(0, 0)
# Generate new graph every analysis as edges might change depending on test bit
self.graph = graph_util.timing_graph()
self.sram_spc_name = "X{}".format(self.sram.name)
self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
# FIXME: refactor to share with delay.py
def set_internal_spice_names(self):
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
# For now, only testing these using first read port.
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port),
'{}{}_{}'.format(self.dout_name, port, 0).lower())
self.sen_name = self.get_sen_name(self.graph.all_paths)
debug.info(2,"s_en name = {}".format(self.sen_name))
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port)
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
self.q_name,self.qbar_name = self.get_bit_name()
debug.info(2,"q name={}\nqbar name={}".format(self.q_name,self.qbar_name))
def get_bit_name(self):
""" Get a bit cell name """
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0)
storage_names = cell_inst.mod.get_storage_net_names()
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
"supported for characterization. Storage nets={}").format(storage_names))
q_name = cell_name+'.'+str(storage_names[0])
qbar_name = cell_name+'.'+str(storage_names[1])
return (q_name,qbar_name)
# FIXME: refactor to share with delay.py
def get_sen_name(self, paths):
"""
Gets the signal name associated with the sense amp enable from input paths.
Only expects a single path to contain the sen signal name.
"""
sa_mods = factory.get_mods(OPTS.sense_amp)
# Any sense amp instantiated should be identical, any change to that
# will require some identification to determine the mod desired.
debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
enable_name = sa_mods[0].get_enable_name()
sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
return sen_name
# FIXME: refactor to share with delay.py
def get_bl_name(self, paths, port):
"""Gets the signal name associated with the bitlines in the bank."""
cell_mod = factory.create(module_type=OPTS.bitcell)
cell_bl = cell_mod.get_bl_name(port)
cell_br = cell_mod.get_br_name(port)
bl_found = False
# Only a single path should contain a single s_en name. Anything else is an error.
bl_names = []
exclude_set = self.get_bl_name_search_exclusions()
for int_net in [cell_bl, cell_br]:
bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
return bl_names[0], bl_names[1]
def get_bl_name_search_exclusions(self):
"""Gets the mods as a set which should be excluded while searching for name."""
# Exclude the RBL as it contains bitcells which are not in the main bitcell array
# so it makes the search awkward
return set(factory.get_mods(OPTS.replica_bitline))
def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None):
"""
Finds a single alias for the int_net in given paths.
More or less hits cause an error
"""
net_found = False
for path in paths:
aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
if net_found and len(aliases) >= 1:
debug.error('Found multiple paths with {} net.'.format(int_net),1)
elif len(aliases) > 1:
debug.error('Found multiple {} nets in single path.'.format(int_net),1)
elif not net_found and len(aliases) == 1:
path_net_name = aliases[0]
net_found = True
if not net_found:
debug.error("Could not find {} net in timing paths.".format(int_net),1)
return path_net_name

View File

@ -25,9 +25,6 @@ class simulation():
self.word_size = self.sram.word_size self.word_size = self.sram.word_size
self.addr_size = self.sram.addr_size self.addr_size = self.sram.addr_size
self.write_size = self.sram.write_size self.write_size = self.sram.write_size
self.num_cols = self.sram.num_cols
self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks
self.sp_file = spfile self.sp_file = spfile
self.all_ports = self.sram.all_ports self.all_ports = self.sram.all_ports
@ -262,19 +259,21 @@ class simulation():
t_current+self.period) t_current+self.period)
elif op == "partial_write": elif op == "partial_write":
comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word, comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word,
addr, addr,
wmask, wmask,
port, port,
int(t_current / self.period), int(t_current / self.period),
t_current, t_current,
t_current + self.period) t_current + self.period)
else: else:
comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
addr, addr,
port, port,
int(t_current/self.period), int(t_current/self.period),
t_current, t_current,
t_current+self.period) t_current+self.period)
return comment return comment
def gen_pin_names(self, port_signal_names, port_info, abits, dbits): def gen_pin_names(self, port_signal_names, port_info, abits, dbits):

View File

@ -0,0 +1,15 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from enum import Enum
class sram_op(Enum):
READ_ZERO = 0
READ_ONE = 1
WRITE_ZERO = 2
WRITE_ONE = 3

View File

@ -1,84 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys,re,shutil
import debug
import tech
import math
from .stimuli import *
from .trim_spice import *
from .charutils import *
import utils
from globals import OPTS
from .delay import delay
class worst_case(delay):
"""Functions to test for the worst case delay in a target SRAM
The current worst case determines a feasible period for the SRAM then tests
several bits and record the delay and differences between the bits.
"""
def __init__(self, sram, spfile, corner):
delay.__init__(self,sram,spfile,corner)
def analyze(self,probe_address, probe_data, slews, loads):
"""
Main function to test the delays of different bits.
"""
debug.check(OPTS.num_rw_ports < 2 and OPTS.num_w_ports < 1 and OPTS.num_r_ports < 1 ,
"Bit testing does not currently support multiport.")
#Dict to hold all characterization values
char_sram_data = {}
self.set_probe(probe_address, probe_data)
#self.prepare_netlist()
self.load=max(loads)
self.slew=max(slews)
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
feasible_delays = self.find_feasible_period()
# 2) Find the delays of several bits
test_bits = self.get_test_bits()
bit_delays = self.simulate_for_bit_delays(test_bits)
for i in range(len(test_bits)):
debug.info(1, "Bit tested: addr {0[0]} data_pos {0[1]}\n Values {1}".format(test_bits[i], bit_delays[i]))
def simulate_for_bit_delays(self, test_bits):
"""Simulates the delay of the sram of over several bits."""
bit_delays = [{} for i in range(len(test_bits))]
#Assumes a bitcell with only 1 rw port. (6t, port 0)
port = 0
self.targ_read_ports = [self.read_ports[port]]
self.targ_write_ports = [self.write_ports[port]]
for i in range(len(test_bits)):
(bit_addr, bit_data) = test_bits[i]
self.set_probe(bit_addr, bit_data)
debug.info(1,"Delay bit test: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data))
(success, results)=self.run_delay_simulation()
debug.check(success, "Bit Test Failed: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data))
bit_delays[i] = results[port]
return bit_delays
def get_test_bits(self):
"""Statically determines address and bit values to test"""
#First and last address, first middle, and last bit. Last bit is repeated twice with different data position.
bit_addrs = ["0"*self.addr_size, "0"+"1"*(self.addr_size-1), "1"*self.addr_size, "1"*self.addr_size]
data_positions = [0, (self.word_size-1)//2, 0, self.word_size-1]
#Return them in a tuple form
return [(bit_addrs[i], data_positions[i]) for i in range(len(bit_addrs))]

View File

@ -169,11 +169,12 @@ def setup_bitcell():
# If we have non-1rw ports, # If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually, # and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use # figure out the right bitcell to use
if (OPTS.bitcell=="bitcell" and OPTS.replica_bitcell=="replica_bitcell"): if (OPTS.bitcell=="bitcell"):
if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0): if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0):
OPTS.bitcell = "bitcell" OPTS.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell" OPTS.replica_bitcell = "replica_bitcell"
OPTS.dummy_bitcell = "dummy_bitcell"
else: else:
ports = "" ports = ""
if OPTS.num_rw_ports>0: if OPTS.num_rw_ports>0:
@ -185,21 +186,26 @@ def setup_bitcell():
OPTS.bitcell = "bitcell_"+ports OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports OPTS.replica_bitcell = "replica_bitcell_"+ports
OPTS.dummy_bitcell = "dummy_bitcell_"+ports
# See if a custom bitcell exists else:
from importlib import find_loader OPTS.replica_bitcell = "replica_" + OPTS.bitcell
try: OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
# See if bitcell exists
from importlib import find_loader
try:
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
__import__(OPTS.dummy_bitcell)
except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1,"Using bitcell: {}".format(OPTS.bitcell)) debug.info(1,"Using bitcell: {}".format(OPTS.bitcell))

View File

@ -40,6 +40,7 @@ class bank(design.design):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
# The local control signals are gated when we have bank select logic, # The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create # so this prefix will be added to all of the input signals to create
# the internal gated signals. # the internal gated signals.
@ -57,8 +58,8 @@ class bank(design.design):
def create_netlist(self): def create_netlist(self):
self.compute_sizes() self.compute_sizes()
self.add_pins()
self.add_modules() self.add_modules()
self.add_pins() # Must create the replica bitcell array first
self.create_instances() self.create_instances()
@ -80,10 +81,14 @@ class bank(design.design):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for port in self.read_ports: for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}_{1}".format(port,bit),"OUT") self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
for port in self.read_ports:
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
for port in self.read_ports:
self.add_pin(self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port]),"INPUT")
for port in self.write_ports: for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"IN") self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
for port in self.all_ports: for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("addr{0}_{1}".format(port,bit),"INPUT") self.add_pin("addr{0}_{1}".format(port,bit),"INPUT")
@ -95,7 +100,7 @@ class bank(design.design):
self.add_pin("bank_sel{}".format(port),"INPUT") self.add_pin("bank_sel{}".format(port),"INPUT")
for port in self.read_ports: for port in self.read_ports:
self.add_pin("s_en{0}".format(port), "INPUT") self.add_pin("s_en{0}".format(port), "INPUT")
for port in self.read_ports: for port in self.all_ports:
self.add_pin("p_en_bar{0}".format(port), "INPUT") self.add_pin("p_en_bar{0}".format(port), "INPUT")
for port in self.write_ports: for port in self.write_ports:
self.add_pin("w_en{0}".format(port), "INPUT") self.add_pin("w_en{0}".format(port), "INPUT")
@ -113,6 +118,7 @@ class bank(design.design):
for port in self.all_ports: for port in self.all_ports:
self.route_bitlines(port) self.route_bitlines(port)
self.route_rbl(port)
self.route_port_address(port) self.route_port_address(port)
self.route_column_address_lines(port) self.route_column_address_lines(port)
self.route_control_lines(port) self.route_control_lines(port)
@ -121,6 +127,20 @@ class bank(design.design):
self.route_supplies() self.route_supplies()
def route_rbl(self,port):
""" Route the rbl_bl and rbl_wl """
if self.port_data[port].has_rbl():
bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name)
self.add_layout_pin(text="rbl_bl{0}".format(port),
layer=bl_pin.layer,
offset=bl_pin.ll(),
height=bl_pin.height(),
width=bl_pin.width())
def route_bitlines(self, port): def route_bitlines(self, port):
""" Route the bitlines depending on the port type rw, w, or r. """ """ Route the bitlines depending on the port type rw, w, or r. """
@ -154,11 +174,17 @@ class bank(design.design):
# The center point for these cells are the upper-right corner of # The center point for these cells are the upper-right corner of
# the bitcell array. # the bitcell array.
# The decoder/driver logic is placed on the right and mirrored on Y-axis. # The port address decoder/driver logic is placed on the right and mirrored on Y-axis.
# The write/sense/precharge/mux is placed on the top and mirrored on the X-axis. # The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
self.bitcell_array_top = self.bitcell_array.height self.bitcell_array_top = self.bitcell_array.height
self.bitcell_array_right = self.bitcell_array.width + self.m1_width + self.m2_gap self.bitcell_array_right = self.bitcell_array.width
# These are the offsets of the main array (excluding dummy and replica rows/cols)
self.main_bitcell_array_top = self.bitcell_array.bitcell_array_inst.uy()
# Just past the dummy column
self.main_bitcell_array_left = self.bitcell_array.bitcell_array_inst.lx()
# Just past the dummy row and replica row
self.main_bitcell_array_bottom = self.bitcell_array.bitcell_array_inst.by()
self.compute_instance_port0_offsets() self.compute_instance_port0_offsets()
if len(self.all_ports)==2: if len(self.all_ports)==2:
@ -167,7 +193,7 @@ class bank(design.design):
def compute_instance_port0_offsets(self): def compute_instance_port0_offsets(self):
""" """
Compute the instance offsets for port0. Compute the instance offsets for port0 on the left/bottom of the bank.
""" """
port = 0 port = 0
@ -178,25 +204,27 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# Below the bitcell array # Below the bitcell array
self.port_data_offsets[port] = vector(0,0) if self.port_data[port].has_rbl():
self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0)
else:
self.port_data_offsets[port] = vector(self.main_bitcell_array_left,0)
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.m2_gap + self.port_address.width x_offset = self.m2_gap + self.port_address.width
self.port_address_offsets[port] = vector(-x_offset,0) self.port_address_offsets[port] = vector(-x_offset,self.main_bitcell_array_bottom)
# LOWER LEFT QUADRANT # LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver plus halfway under row decoder # Place the col decoder left aligned with wordline driver
# Place the col decoder left aligned with row decoder (x_offset doesn't change) # This is also placed so that it's supply rails do not align with the SRAM-level
# Below the bitcell array with well spacing # control logic to allow control signals to easily pass over in M3
# by placing 1/2 a cell pitch down
x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.m2_gap + self.column_decoder.height y_offset = 0.5*self.dff.height + self.column_decoder.height
else: else:
y_offset = 0 y_offset = 0
y_offset += 2*drc("well_to_well")
self.column_decoder_offsets[port] = vector(-x_offset,-y_offset) self.column_decoder_offsets[port] = vector(-x_offset,-y_offset)
# Bank select gets placed below the column decoder (x_offset doesn't change) # Bank select gets placed below the column decoder (x_offset doesn't change)
@ -210,7 +238,7 @@ class bank(design.design):
def compute_instance_port1_offsets(self): def compute_instance_port1_offsets(self):
""" """
Compute the instance offsets for port1 on the top of the bank. Compute the instance offsets for port1 on the right/top of the bank.
""" """
port=1 port=1
@ -220,24 +248,22 @@ class bank(design.design):
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# Above the bitcell array # Above the bitcell array
self.port_data_offsets[port] = vector(0,self.bitcell_array_top) self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top)
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
self.port_address_offsets[port] = vector(x_offset,0) self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom)
# UPPER RIGHT QUADRANT # UPPER RIGHT QUADRANT
# Place the col decoder right aligned with wordline driver plus halfway under row decoder # Place the col decoder right aligned with wordline driver
# Above the bitcell array with a well spacing # Above the bitcell array with a well spacing
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height y_offset = self.bitcell_array_top + 0.5*self.dff.height + self.column_decoder.height
else: else:
y_offset = self.bitcell_array_top y_offset = self.bitcell_array_top
y_offset += 2*drc("well_to_well")
self.column_decoder_offsets[port] = vector(x_offset,y_offset) self.column_decoder_offsets[port] = vector(x_offset,y_offset)
# Bank select gets placed above the column decoder (x_offset doesn't change) # Bank select gets placed above the column decoder (x_offset doesn't change)
@ -253,16 +279,12 @@ class bank(design.design):
self.compute_instance_offsets() self.compute_instance_offsets()
# UPPER RIGHT QUADRANT
self.place_bitcell_array(self.bitcell_array_offset) self.place_bitcell_array(self.bitcell_array_offset)
# LOWER RIGHT QUADRANT
self.place_port_data(self.port_data_offsets) self.place_port_data(self.port_data_offsets)
# UPPER LEFT QUADRANT
self.place_port_address(self.port_address_offsets) self.place_port_address(self.port_address_offsets)
# LOWER LEFT QUADRANT
self.place_column_decoder(self.column_decoder_offsets) self.place_column_decoder(self.column_decoder_offsets)
self.place_bank_select(self.bank_select_offsets) self.place_bank_select(self.bank_select_offsets)
@ -280,22 +302,17 @@ class bank(design.design):
debug.check(self.num_rows*self.num_cols==self.word_size*self.num_words,"Invalid bank sizes.") debug.check(self.num_rows*self.num_cols==self.word_size*self.num_words,"Invalid bank sizes.")
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,"Invalid address break down.") debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,"Invalid address break down.")
# Width for the vdd/gnd rails
self.supply_rail_width = 4*self.m2_width
# FIXME: This spacing should be width dependent...
self.supply_rail_pitch = self.supply_rail_width + 4*self.m2_space
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.input_control_signals = [] self.input_control_signals = []
port_num = 0 port_num = 0
for port in range(OPTS.num_rw_ports): for port in range(OPTS.num_rw_ports):
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)]) self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
port_num += 1 port_num += 1
for port in range(OPTS.num_w_ports): for port in range(OPTS.num_w_ports):
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num)]) self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "p_en_bar{}".format(port_num)])
port_num += 1 port_num += 1
for port in range(OPTS.num_r_ports): for port in range(OPTS.num_r_ports):
self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)]) self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
port_num += 1 port_num += 1
# Number of control lines in the bus for each port # Number of control lines in the bus for each port
@ -329,15 +346,10 @@ class bank(design.design):
# create arrays of bitline and bitline_bar names for read, write, or all ports # create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.list_all_bl_names() self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.list_all_br_names() self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.list_all_wl_names() self.wl_names = self.bitcell.get_all_wl_names()
self.bitline_names = self.bitcell.list_all_bitline_names() self.bitline_names = self.bitcell.get_all_bitline_names()
self.bitcell_array = factory.create(module_type="bitcell_array",
cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.port_data = [] self.port_data = []
for port in self.all_ports: for port in self.all_ports:
@ -352,7 +364,41 @@ class bank(design.design):
cols=self.num_cols, cols=self.num_cols,
rows=self.num_rows) rows=self.num_rows)
self.add_mod(self.port_address) self.add_mod(self.port_address)
# The number of replica lines depends on the port configuration
rbl_counts = [self.read_ports.count(p) for p in self.all_ports]
self.num_rbl = sum(rbl_counts)
# The replica array indices always start at 0, so this will map them to
# the correct SRAM port
# (e.g. if port 0 is w, then port 1 will use RBL 0 in replica bitcell array
# because write ports don't use an RBL)
self.port_rbl_map = {}
index = 0
for (i,num) in enumerate(rbl_counts):
if num>0:
self.port_rbl_map[i]=index
index += 1
if len(rbl_counts)<2:
rbl_counts.append(0)
# Which bitcell port should be used in the RBL
# For now (since only 2 ports), if port 0 is not a read port, skip it in the RBLs
bitcell_ports=list(range(len(self.read_ports)))
if 0 not in self.read_ports:
bitcell_ports = [x+1 for x in bitcell_ports]
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols,
rows=self.num_rows,
left_rbl=rbl_counts[0],
right_rbl=rbl_counts[1],
bitcell_ports=bitcell_ports)
self.add_mod(self.bitcell_array)
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select") self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select) self.add_mod(self.bank_select)
@ -361,17 +407,24 @@ class bank(design.design):
def create_bitcell_array(self): def create_bitcell_array(self):
""" Creating Bitcell Array """ """ Creating Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="bitcell_array", self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
mod=self.bitcell_array) mod=self.bitcell_array)
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
for bitline in self.bitline_names: for bitline in self.bitline_names:
temp.append(bitline+"_{0}".format(col)) temp.append("{0}_{1}".format(bitline,col))
for rbl in range(self.num_rbl):
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(rbl)
temp.append(rbl_bl_name)
rbl_br_name=self.bitcell_array.get_rbl_br_name(rbl)
temp.append(rbl_br_name)
for row in range(self.num_rows): for row in range(self.num_rows):
for wordline in self.wl_names: for wordline in self.wl_names:
temp.append(wordline+"_{0}".format(row)) temp.append("{0}_{1}".format(wordline,row))
for rbl in range(self.num_rbl):
rbl_wl_name=self.bitcell_array.get_rbl_wl_name(rbl)
temp.append(rbl_wl_name)
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
@ -391,6 +444,11 @@ class bank(design.design):
mod=self.port_data[port]) mod=self.port_data[port])
temp = [] temp = []
if self.port_data[port].has_rbl():
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
temp.append(rbl_bl_name)
temp.append(rbl_br_name)
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append("{0}_{1}".format(self.bl_names[port],col)) temp.append("{0}_{1}".format(self.bl_names[port],col))
temp.append("{0}_{1}".format(self.br_names[port],col)) temp.append("{0}_{1}".format(self.br_names[port],col))
@ -405,8 +463,7 @@ class bank(design.design):
temp.extend(sel_names) temp.extend(sel_names)
if port in self.read_ports: if port in self.read_ports:
temp.append("s_en{0}".format(port)) temp.append("s_en{0}".format(port))
if port in self.read_ports: temp.append("p_en_bar{0}".format(port))
temp.append("p_en_bar{0}".format(port))
if port in self.write_ports: if port in self.write_ports:
temp.append("w_en{0}".format(port)) temp.append("w_en{0}".format(port))
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
@ -440,7 +497,7 @@ class bank(design.design):
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size)) temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size))
temp.append("wl_en{0}".format(port)) temp.append("wl_en{0}".format(port))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append(self.wl_names[port]+"_{0}".format(row)) temp.append("{0}_{1}".format(self.wl_names[port],row))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -457,7 +514,7 @@ class bank(design.design):
# The address flop and decoder are aligned in the x coord. # The address flop and decoder are aligned in the x coord.
for port in self.all_ports: for port in self.all_ports:
if port%2 == 1: if port%2:
mirror = "MY" mirror = "MY"
else: else:
mirror = "R0" mirror = "R0"
@ -469,16 +526,16 @@ class bank(design.design):
Create a 2:4 or 3:8 column address decoder. Create a 2:4 or 3:8 column address decoder.
""" """
dff = factory.create(module_type="dff") self.dff = factory.create(module_type="dff")
if self.col_addr_size == 0: if self.col_addr_size == 0:
return return
elif self.col_addr_size == 1: elif self.col_addr_size == 1:
self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height) self.column_decoder = factory.create(module_type="pinvbuf", height=self.dff.height)
elif self.col_addr_size == 2: elif self.col_addr_size == 2:
self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height) self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=self.dff.height)
elif self.col_addr_size == 3: elif self.col_addr_size == 3:
self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height) self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height)
else: else:
# No error checking before? # No error checking before?
debug.error("Invalid column decoder?",-1) debug.error("Invalid column decoder?",-1)
@ -560,8 +617,8 @@ class bank(design.design):
bank_sel_signals = ["clk_buf", "w_en", "s_en", "p_en_bar", "bank_sel"] bank_sel_signals = ["clk_buf", "w_en", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_s_en", "gated_p_en_bar"] gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_s_en", "gated_p_en_bar"]
elif self.port_id[port] == "w": elif self.port_id[port] == "w":
bank_sel_signals = ["clk_buf", "w_en", "bank_sel"] bank_sel_signals = ["clk_buf", "w_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en"] gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_p_en_bar"]
else: else:
bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"] bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"] gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"]
@ -615,9 +672,9 @@ class bank(design.design):
# Port 0 # Port 0
# The bank is at (0,0), so this is to the left of the y-axis. # The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs # 2 pitches on the right for vias/jogs to access the inputs
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_width, self.min_y_offset) control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_pitch, self.min_y_offset)
# The control bus is routed up to two pitches below the bitcell array # The control bus is routed up to two pitches below the bitcell array
control_bus_length = -2*self.m1_pitch - self.min_y_offset control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2*self.m1_pitch
self.bus_xoffset[0] = self.create_bus(layer="metal2", self.bus_xoffset[0] = self.create_bus(layer="metal2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=control_bus_offset, offset=control_bus_offset,
@ -629,14 +686,14 @@ class bank(design.design):
# Port 1 # Port 1
if len(self.all_ports)==2: if len(self.all_ports)==2:
# The other control bus is routed up to two pitches above the bitcell array # The other control bus is routed up to two pitches above the bitcell array
control_bus_length = self.max_y_offset - self.bitcell_array_top - 2*self.m1_pitch control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch
control_bus_offset = vector(self.bitcell_array_right, control_bus_offset = vector(self.bitcell_array_right + self.m2_pitch,
self.max_y_offset - control_bus_length) self.max_y_offset - control_bus_length)
# The bus for the right port is reversed so that the rbl_wl is closest to the array
self.bus_xoffset[1] = self.create_bus(layer="metal2", self.bus_xoffset[1] = self.create_bus(layer="metal2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=control_bus_offset, offset=control_bus_offset,
names=self.control_signals[1], names=list(reversed(self.control_signals[1])),
length=control_bus_length, length=control_bus_length,
vertical=True, vertical=True,
make_pins=(self.num_banks==1)) make_pins=(self.num_banks==1))
@ -645,12 +702,22 @@ class bank(design.design):
def route_port_data_to_bitcell_array(self, port): def route_port_data_to_bitcell_array(self, port):
""" Routing of BL and BR between port data and bitcell array """ """ Routing of BL and BR between port data and bitcell array """
# Connect the regular bitlines
inst2 = self.port_data_inst[port] inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}" inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}" inst1_br_name = self.br_names[port]+"_{}"
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols, self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
# Connect the replica bitlines
if self.port_data[port].has_rbl():
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl")
self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br")
def route_port_data_out(self, port): def route_port_data_out(self, port):
@ -710,12 +777,9 @@ class bank(design.design):
route_map = list(zip(bottom_names, top_names)) route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset) self.create_horizontal_channel_route(route_map, offset)
def connect_bitline(self, inst1, inst2, inst1_name, inst2_name):
def connect_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
""" """
Connect the bl and br of two modules. Connect two pins of two modules.
This assumes that they have sufficient space to create a jog This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed). in the middle between the two modules (if needed).
""" """
@ -723,23 +787,34 @@ class bank(design.design):
# determine top and bottom automatically. # determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate. # since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by(): if inst1.by() < inst2.by():
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name) (bottom_inst, bottom_name) = (inst1, inst1_name)
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name) (top_inst, top_name) = (inst2, inst2_name)
else: else:
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) (bottom_inst, bottom_name) = (inst2, inst2_name)
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) (top_inst, top_name) = (inst1, inst1_name)
bottom_pin = bottom_inst.get_pin(bottom_name)
top_pin = top_inst.get_pin(top_name)
debug.check(bottom_pin.layer == top_pin.layer, "Pin layers do not match.")
bottom_loc = bottom_pin.uc()
top_loc = top_pin.bc()
yoffset = 0.5*(top_loc.y+bottom_loc.y)
self.add_path(top_pin.layer,[bottom_loc, vector(bottom_loc.x,yoffset),
vector(top_loc.x,yoffset), top_loc])
def connect_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
"""
Connect the bl and br of two modules.
"""
for col in range(num_bits): for col in range(num_bits):
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col)).uc() self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col))
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col)).uc() self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col))
top_bl = top_inst.get_pin(top_bl_name.format(col)).bc()
top_br = top_inst.get_pin(top_br_name.format(col)).bc()
yoffset = 0.5*(top_bl.y+bottom_bl.y)
self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset),
vector(top_bl.x,yoffset), top_bl])
self.add_path("metal2",[bottom_br, vector(bottom_br.x,yoffset),
vector(top_br.x,yoffset), top_br])
def route_port_address(self, port): def route_port_address(self, port):
@ -868,21 +943,26 @@ class bank(design.design):
read_inst = 0 read_inst = 0
connection = [] connection = []
connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc()))
if port in self.read_ports: if port in self.read_ports:
connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc())) rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
connection.append((self.prefix+"rbl_wl{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
if port in self.write_ports: if port in self.write_ports:
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc())) connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
if port in self.read_ports: if port in self.read_ports:
connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc())) connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
for (control_signal, pin_pos) in connection: for (control_signal, pin_pos) in connection:
control_mid_pos = self.bus_xoffset[port][control_signal]
control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y) control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos]) self.add_wire(("metal1","via1","metal2"), [control_mid_pos, control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos) offset=control_pos)
# clk to wordline_driver # clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port) control_signal = self.prefix+"wl_en{}".format(port)
if port%2: if port%2:

View File

@ -73,32 +73,32 @@ class bitcell_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
row_list = self.cell.list_all_wl_names() row_list = self.cell.get_all_wl_names()
column_list = self.cell.list_all_bitline_names() column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in column_list: for cell_column in column_list:
self.add_pin(cell_column+"_{0}".format(col)) self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size): for row in range(self.row_size):
for cell_row in row_list: for cell_row in row_list:
self.add_pin(cell_row+"_{0}".format(row)) self.add_pin(cell_row+"_{0}".format(row), "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
self.add_mod(self.cell) self.add_mod(self.cell)
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, """ Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """ indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
pin_names = self.cell.list_all_bitline_names() pin_names = self.cell.get_all_bitline_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col)) bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.list_all_wl_names() pin_names = self.cell.get_all_wl_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row)) bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
@ -115,13 +115,13 @@ class bitcell_array(design.design):
name = "bit_r{0}_c{1}".format(row, col) name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name, self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell) mod=self.cell)
self.connect_inst(self.list_bitcell_pins(col, row)) self.connect_inst(self.get_bitcell_pins(col, row))
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
row_list = self.cell.list_all_wl_names() row_list = self.cell.get_all_wl_names()
column_list = self.cell.list_all_bitline_names() column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in column_list: for cell_column in column_list:
@ -215,4 +215,4 @@ class bitcell_array(design.design):
def get_cell_name(self, inst_name, row, col): def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell.""" """Gets the spice name of the target bitcell."""
return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col] return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col]

View File

@ -39,7 +39,7 @@ class control_logic(design.design):
self.num_cols = word_size*words_per_row self.num_cols = word_size*words_per_row
self.num_words = num_rows*words_per_row self.num_words = num_rows*words_per_row
self.enable_delay_chain_resizing = True self.enable_delay_chain_resizing = False
self.inv_parasitic_delay = logical_effort.logical_effort.pinv self.inv_parasitic_delay = logical_effort.logical_effort.pinv
#Determines how much larger the sen delay should be. Accounts for possible error in model. #Determines how much larger the sen delay should be. Accounts for possible error in model.
@ -73,10 +73,8 @@ class control_logic(design.design):
def add_pins(self): def add_pins(self):
""" Add the pins to the control logic module. """ """ Add the pins to the control logic module. """
for pin in self.input_list + ["clk"]: self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
self.add_pin(pin,"INPUT") self.add_pin_list(self.output_list,"OUTPUT")
for pin in self.output_list:
self.add_pin(pin,"OUTPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
@ -96,6 +94,12 @@ class control_logic(design.design):
size=4, size=4,
height=dff_height) height=dff_height)
self.add_mod(self.and2) self.add_mod(self.and2)
self.rbl_driver = factory.create(module_type="pbuf",
size=self.num_cols,
height=dff_height)
self.add_mod(self.rbl_driver)
# clk_buf drives a flop for every address and control bit # clk_buf drives a flop for every address and control bit
# plus about 5 fanouts for the control logic # plus about 5 fanouts for the control logic
@ -115,16 +119,16 @@ class control_logic(design.design):
self.add_mod(self.wl_en_driver) self.add_mod(self.wl_en_driver)
# w_en drives every write driver # w_en drives every write driver
self.w_en_driver = factory.create(module_type="pdriver", self.wen_and2 = factory.create(module_type="pand2",
fanout=self.word_size+8, size=self.word_size+8,
height=dff_height) height=dff_height)
self.add_mod(self.w_en_driver) self.add_mod(self.wen_and2)
# s_en drives every sense amp # s_en drives every sense amp
self.s_en_driver = factory.create(module_type="pdriver", self.sen_and2 = factory.create(module_type="pand2",
fanout=self.word_size, size=self.word_size,
height=dff_height) height=dff_height)
self.add_mod(self.s_en_driver) self.add_mod(self.sen_and2)
# used to generate inverted signals with low fanout # used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv", self.inv = factory.create(module_type="pinv",
@ -132,53 +136,58 @@ class control_logic(design.design):
height=dff_height) height=dff_height)
self.add_mod(self.inv) self.add_mod(self.inv)
# p_en_bar drives every column in the bicell array # p_en_bar drives every column in the bitcell array
self.p_en_bar_driver = factory.create(module_type="pdriver", self.p_en_bar_driver = factory.create(module_type="pdriver",
neg_polarity=True, neg_polarity=True,
fanout=self.num_cols, fanout=self.num_cols,
height=dff_height) height=dff_height)
self.add_mod(self.p_en_bar_driver) self.add_mod(self.p_en_bar_driver)
if (self.port_type == "rw") or (self.port_type == "r"):
from importlib import reload # if (self.port_type == "rw") or (self.port_type == "r"):
self.delay_chain_resized = False # from importlib import reload
c = reload(__import__(OPTS.replica_bitline)) # self.delay_chain_resized = False
replica_bitline = getattr(c, OPTS.replica_bitline) # c = reload(__import__(OPTS.replica_bitline))
bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage)) # replica_bitline = getattr(c, OPTS.replica_bitline)
#Use a model to determine the delays with that heuristic # bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage))
if OPTS.use_tech_delay_chain_size: #Use tech parameters if set. # #Use a model to determine the delays with that heuristic
fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage] # if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list)) # fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage]
self.replica_bitline = factory.create(module_type="replica_bitline", # debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
delay_fanout_list=fanout_list, # self.replica_bitline = factory.create(module_type="replica_bitline",
bitcell_loads=bitcell_loads) # delay_fanout_list=fanout_list,
if self.sram != None: #Calculate model value even for specified sizes # bitcell_loads=bitcell_loads)
self.set_sen_wl_delays() # if self.sram != None: #Calculate model value even for specified sizes
# self.set_sen_wl_delays()
else: #Otherwise, use a heuristic and/or model based sizing. # else: #Otherwise, use a heuristic and/or model based sizing.
#First use a heuristic # #First use a heuristic
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() # delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
self.replica_bitline = factory.create(module_type="replica_bitline", # self.replica_bitline = factory.create(module_type="replica_bitline",
delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, # delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
bitcell_loads=bitcell_loads) # bitcell_loads=bitcell_loads)
#Resize if necessary, condition depends on resizing method # #Resize if necessary, condition depends on resizing method
if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match(): # if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
#This resizes to match fall and rise delays, can make the delay chain weird sizes. # #This resizes to match fall and rise delays, can make the delay chain weird sizes.
stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic) # stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
self.replica_bitline = factory.create(module_type="replica_bitline", # self.replica_bitline = factory.create(module_type="replica_bitline",
delay_fanout_list=stage_list, # delay_fanout_list=stage_list,
bitcell_loads=bitcell_loads) # bitcell_loads=bitcell_loads)
#This resizes based on total delay. # #This resizes based on total delay.
# delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) # # delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
# self.replica_bitline = factory.create(module_type="replica_bitline", # # self.replica_bitline = factory.create(module_type="replica_bitline",
# delay_fanout_list=[delay_fanout]*delay_stages, # # delay_fanout_list=[delay_fanout]*delay_stages,
# bitcell_loads=bitcell_loads) # # bitcell_loads=bitcell_loads)
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing # self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
self.delay_chain_resized = True # self.delay_chain_resized = True
self.add_mod(self.replica_bitline) debug.check(OPTS.delay_chain_stages%2, "Must use odd number of delay chain stages for inverting delay chain.")
self.delay_chain=factory.create(module_type="delay_chain",
fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage])
self.add_mod(self.delay_chain)
def get_heuristic_delay_chain_size(self): def get_heuristic_delay_chain_size(self):
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """ """Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
@ -312,8 +321,13 @@ class control_logic(design.design):
# List of input control signals # List of input control signals
if self.port_type == "rw": if self.port_type == "rw":
self.input_list = ["csb", "web"] self.input_list = ["csb", "web"]
self.rbl_list = ["rbl_bl"]
elif self.port_type == "r":
self.input_list = ["csb"]
self.rbl_list = ["rbl_bl"]
else: else:
self.input_list = ["csb"] self.input_list = ["csb"]
self.rbl_list = []
if self.port_type == "rw": if self.port_type == "rw":
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"] self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
@ -332,11 +346,12 @@ class control_logic(design.design):
# Outputs to the bank # Outputs to the bank
if self.port_type == "rw": if self.port_type == "rw":
self.output_list = ["s_en", "w_en", "p_en_bar"] self.output_list = ["rbl_wl", "s_en", "w_en"]
elif self.port_type == "r": elif self.port_type == "r":
self.output_list = ["s_en", "p_en_bar"] self.output_list = ["rbl_wl", "s_en"]
else: else:
self.output_list = ["w_en"] self.output_list = ["w_en"]
self.output_list.append("p_en_bar")
self.output_list.append("wl_en") self.output_list.append("wl_en")
self.output_list.append("clk_buf") self.output_list.append("clk_buf")
@ -360,12 +375,12 @@ class control_logic(design.design):
self.create_wlen_row() self.create_wlen_row()
if (self.port_type == "rw") or (self.port_type == "w"): if (self.port_type == "rw") or (self.port_type == "w"):
self.create_wen_row() self.create_wen_row()
if self.port_type == "rw": if (self.port_type == "rw") or (self.port_type == "r"):
self.create_rbl_in_row() self.create_rbl_row()
if (self.port_type == "rw") or (self.port_type == "r"):
self.create_pen_row()
self.create_sen_row() self.create_sen_row()
self.create_rbl() self.create_delay()
self.create_pen_row()
def place_instances(self): def place_instances(self):
@ -392,20 +407,20 @@ class control_logic(design.design):
row += 1 row += 1
if (self.port_type == "rw") or (self.port_type == "w"): if (self.port_type == "rw") or (self.port_type == "w"):
self.place_wen_row(row) self.place_wen_row(row)
height = self.w_en_inst.uy() height = self.w_en_gate_inst.uy()
control_center_y = self.w_en_inst.uy() control_center_y = self.w_en_gate_inst.uy()
row += 1 row += 1
if self.port_type == "rw": if (self.port_type == "rw") or (self.port_type == "r"):
self.place_rbl_in_row(row) self.place_rbl_row(row)
row += 1 row += 1
self.place_pen_row(row)
row += 1
if (self.port_type == "rw") or (self.port_type == "r"): if (self.port_type == "rw") or (self.port_type == "r"):
self.place_pen_row(row)
row += 1
self.place_sen_row(row) self.place_sen_row(row)
row += 1 row += 1
self.place_rbl(row) self.place_delay(row)
height = self.rbl_inst.uy() height = self.delay_inst.uy()
control_center_y = self.rbl_inst.by() 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)
@ -415,7 +430,7 @@ class control_logic(design.design):
# Max of modules or logic rows # Max of modules or logic rows
self.width = max([inst.rx() for inst in self.row_end_inst]) self.width = max([inst.rx() for inst in self.row_end_inst])
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() , self.width) self.width = max(self.delay_inst.rx() , self.width)
self.width += self.m2_pitch self.width += self.m2_pitch
def route_all(self): def route_all(self):
@ -426,33 +441,29 @@ class control_logic(design.design):
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()
if (self.port_type == "rw") or (self.port_type == "r"): if (self.port_type == "rw") or (self.port_type == "r"):
self.route_rbl_in() self.route_rbl()
self.route_pen()
self.route_sen() self.route_sen()
self.route_pen()
self.route_clk_buf() self.route_clk_buf()
self.route_gated_clk_bar() self.route_gated_clk_bar()
self.route_gated_clk_buf() self.route_gated_clk_buf()
self.route_supply() self.route_supply()
def create_rbl(self): def create_delay(self):
""" Create the replica bitline """ """ Create the replica bitline """
if self.port_type == "r": self.delay_inst=self.add_inst(name="delay_chain",
input_name = "gated_clk_bar" mod=self.delay_chain)
else: self.connect_inst(["rbl_bl", "pre_s_en", "vdd", "gnd"])
input_name = "rbl_in"
self.rbl_inst=self.add_inst(name="replica_bitline",
mod=self.replica_bitline)
self.connect_inst([input_name, "pre_s_en", "vdd", "gnd"])
def place_rbl(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 y_off = row * self.and2.height + 2*self.m1_pitch
# 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(0, y_off) offset = vector(self.delay_chain.width, y_off)
self.rbl_inst.place(offset) self.delay_inst.place(offset, mirror="MY")
def create_clk_buf_row(self): def create_clk_buf_row(self):
@ -588,44 +599,31 @@ class control_logic(design.design):
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets) self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
self.connect_output(self.wl_en_inst, "Z", "wl_en") self.connect_output(self.wl_en_inst, "Z", "wl_en")
def create_rbl_in_row(self): def create_rbl_row(self):
# input: gated_clk_bar, we_bar, output: rbl_in
self.rbl_in_inst=self.add_inst(name="and2_rbl_in",
mod=self.and2)
self.connect_inst(["gated_clk_bar", "we_bar", "rbl_in", "vdd", "gnd"])
def place_rbl_in_row(self,row): self.rbl_inst=self.add_inst(name="rbl_driver",
mod=self.rbl_driver)
# input: gated_clk_bar, output: rbl_wl
self.connect_inst(["gated_clk_bar", "rbl_wl", "vdd", "gnd"])
def place_rbl_row(self,row):
x_off = self.control_x_offset x_off = self.control_x_offset
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
offset = vector(x_off, y_off) offset = vector(x_off, y_off)
self.rbl_in_inst.place(offset, mirror) self.rbl_inst.place(offset, mirror)
self.row_end_inst.append(self.rbl_in_inst) self.row_end_inst.append(self.rbl_inst)
def route_rbl_in(self): def route_rbl(self):
""" Connect the logic for the rbl_in generation """ """ Connect the logic for the rbl_in generation """
if self.port_type == "rw": rbl_in_map = zip(["A"], ["gated_clk_bar"])
input_name = "we_bar" self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets)
# Connect the NAND gate inputs to the bus self.connect_output(self.rbl_inst, "Z", "rbl_wl")
rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"])
self.connect_vertical_bus(rbl_in_map, self.rbl_in_inst, self.rail_offsets) # Input from RBL goes to the delay line for futher delay
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
# Connect the output of the precharge enable to the RBL input
if self.port_type == "rw":
out_pos = self.rbl_in_inst.get_pin("Z").center()
else:
out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch)
in_pos = self.rbl_inst.get_pin("en").center()
mid1 = vector(in_pos.x,out_pos.y)
self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=out_pos)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=out_pos)
def create_pen_row(self): def create_pen_row(self):
input_name = "gated_clk_buf" input_name = "gated_clk_buf"
@ -639,7 +637,6 @@ class control_logic(design.design):
def place_pen_row(self,row): def place_pen_row(self,row):
x_off = self.control_x_offset x_off = self.control_x_offset
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
offset = vector(x_off,y_off) offset = vector(x_off,y_off)
self.p_en_bar_inst.place(offset, mirror) self.p_en_bar_inst.place(offset, mirror)
@ -647,17 +644,21 @@ class control_logic(design.design):
def route_pen(self): def route_pen(self):
in_map = zip(["A"], ["gated_clk_buf"]) in_map = zip(["A"], ["gated_clk_buf"])
self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets) self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets)
self.connect_output(self.p_en_bar_inst, "Z", "p_en_bar") self.connect_output(self.p_en_bar_inst, "Z", "p_en_bar")
def create_sen_row(self): def create_sen_row(self):
""" Create the sense enable buffer. """ """ Create the sense enable buffer. """
# BUFFER FOR S_EN if self.port_type=="rw":
# input: pre_s_en, output: s_en input_name = "we_bar"
self.s_en_inst=self.add_inst(name="buf_s_en", else:
mod=self.s_en_driver) input_name = "cs_bar"
self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"]) # GATE FOR S_EN
self.s_en_gate_inst = self.add_inst(name="buf_s_en_and",
mod=self.sen_and2)
self.connect_inst(["pre_s_en", input_name, "s_en", "vdd", "gnd"])
def place_sen_row(self,row): def place_sen_row(self,row):
""" """
@ -668,19 +669,27 @@ class control_logic(design.design):
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
offset = vector(x_off, y_off) offset = vector(x_off, y_off)
self.s_en_inst.place(offset, mirror) self.s_en_gate_inst.place(offset, mirror)
self.row_end_inst.append(self.s_en_inst) self.row_end_inst.append(self.s_en_gate_inst)
def route_sen(self): def route_sen(self):
if self.port_type=="rw":
input_name = "we_bar"
else:
input_name = "cs_bar"
sen_map = zip(["B"], [input_name])
self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets)
out_pos = self.rbl_inst.get_pin("out").bc() out_pos = self.delay_inst.get_pin("out").bc()
in_pos = self.s_en_inst.get_pin("A").lc() in_pos = self.s_en_gate_inst.get_pin("A").lc()
mid1 = vector(out_pos.x,in_pos.y) mid1 = vector(out_pos.x,in_pos.y)
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos]) self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
self.connect_output(self.s_en_inst, "Z", "s_en") self.connect_output(self.s_en_gate_inst, "Z", "s_en")
def create_wen_row(self): def create_wen_row(self):
@ -690,34 +699,33 @@ class control_logic(design.design):
else: else:
# No we for write-only reports, so use cs # No we for write-only reports, so use cs
input_name = "cs" input_name = "cs"
# BUFFER FOR W_EN
self.w_en_inst = self.add_inst(name="buf_w_en_buf",
mod=self.w_en_driver)
self.connect_inst([input_name, "w_en", "vdd", "gnd"])
# GATE THE W_EN
self.w_en_gate_inst = self.add_inst(name="w_en_and",
mod=self.wen_and2)
self.connect_inst([input_name, "gated_clk_bar", "w_en", "vdd", "gnd"])
def place_wen_row(self,row): def place_wen_row(self,row):
x_off = self.ctrl_dff_inst.width + self.internal_bus_width x_off = self.ctrl_dff_inst.width + self.internal_bus_width
(y_off,mirror)=self.get_offset(row) (y_off,mirror)=self.get_offset(row)
offset = vector(x_off, y_off) offset = vector(x_off, y_off)
self.w_en_inst.place(offset, mirror) self.w_en_gate_inst.place(offset, mirror)
self.row_end_inst.append(self.w_en_inst) self.row_end_inst.append(self.w_en_gate_inst)
def route_wen(self): def route_wen(self):
if self.port_type == "rw": if self.port_type == "rw":
input_name = "we" input_name = "we"
else: else:
# No we for write-only reports, so use cs # No we for write-only reports, so use cs
input_name = "cs" input_name = "cs"
wen_map = zip(["A"], [input_name]) wen_map = zip(["A", "B"], [input_name, "gated_clk_bar"])
self.connect_vertical_bus(wen_map, self.w_en_inst, self.rail_offsets) self.connect_vertical_bus(wen_map, self.w_en_gate_inst, self.rail_offsets)
self.connect_output(self.w_en_inst, "Z", "w_en") self.connect_output(self.w_en_gate_inst, "Z", "w_en")
def create_dffs(self): def create_dffs(self):
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs", self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
@ -794,8 +802,8 @@ class control_logic(design.design):
self.add_path("metal1", [row_loc, pin_loc]) self.add_path("metal1", [row_loc, pin_loc])
if (self.port_type == "rw") or (self.port_type == "r"): if (self.port_type == "rw") or (self.port_type == "r"):
self.copy_layout_pin(self.rbl_inst,"gnd") self.copy_layout_pin(self.delay_inst,"gnd")
self.copy_layout_pin(self.rbl_inst,"vdd") self.copy_layout_pin(self.delay_inst,"vdd")
self.copy_layout_pin(self.ctrl_dff_inst,"gnd") self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
self.copy_layout_pin(self.ctrl_dff_inst,"vdd") self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
@ -821,7 +829,7 @@ class control_logic(design.design):
# height=pin.height(), # height=pin.height(),
# width=pin.width()) # width=pin.width())
pin=self.rbl_inst.get_pin("out") pin=self.delay_inst.get_pin("out")
self.add_label_pin(text="out", self.add_label_pin(text="out",
layer=pin.layer, layer=pin.layer,
offset=pin.ll(), offset=pin.ll(),
@ -882,7 +890,7 @@ class control_logic(design.design):
last_stage_rise = stage_effort_list[-1].is_rise last_stage_rise = stage_effort_list[-1].is_rise
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en #Replica bitline stage, rbl_in -(rbl)-> pre_s_en
stage2_cout = self.s_en_driver.get_cin() stage2_cout = self.sen_and2.get_cin()
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise) stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise last_stage_rise = stage_effort_list[-1].is_rise
@ -895,6 +903,7 @@ class control_logic(design.design):
def get_wl_sen_delays(self): def get_wl_sen_delays(self):
"""Gets a list of the stages and delays in order of their path.""" """Gets a list of the stages and delays in order of their path."""
if self.sen_stage_efforts == None or self.wl_stage_efforts == None: if self.sen_stage_efforts == None or self.wl_stage_efforts == None:
debug.error("Model delays not calculated for SRAM.", 1) debug.error("Model delays not calculated for SRAM.", 1)
wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts) wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts)
@ -903,6 +912,7 @@ class control_logic(design.design):
def analytical_delay(self, corner, slew, load): def analytical_delay(self, corner, slew, load):
"""Gets the analytical delay from clk input to wl_en output""" """Gets the analytical delay from clk input to wl_en output"""
stage_effort_list = [] stage_effort_list = []
#Calculate the load on clk_buf_bar #Calculate the load on clk_buf_bar
ext_clk_buf_cout = self.sram.get_clk_bar_cin() ext_clk_buf_cout = self.sram.get_clk_bar_cin()
@ -930,8 +940,10 @@ class control_logic(design.design):
return stage_effort_list return stage_effort_list
def get_clk_buf_cin(self): def get_clk_buf_cin(self):
"""Get the loads that are connected to the buffered clock. """
Includes all the DFFs and some logic.""" Get the loads that are connected to the buffered clock.
Includes all the DFFs and some logic.
"""
#Control logic internal load #Control logic internal load
int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin() int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin()
@ -943,6 +955,7 @@ class control_logic(design.design):
def get_gated_clk_bar_cin(self): def get_gated_clk_bar_cin(self):
"""Get intermediates net gated_clk_bar's capacitance""" """Get intermediates net gated_clk_bar's capacitance"""
total_cin = 0 total_cin = 0
total_cin += self.wl_en_driver.get_cin() total_cin += self.wl_en_driver.get_cin()
if self.port_type == 'rw': if self.port_type == 'rw':
@ -951,4 +964,7 @@ class control_logic(design.design):
def graph_exclude_dffs(self): def graph_exclude_dffs(self):
"""Exclude dffs from graph as they do not represent critical path""" """Exclude dffs from graph as they do not represent critical path"""
self.graph_inst_exclude.add(self.ctrl_dff_inst) self.graph_inst_exclude.add(self.ctrl_dff_inst)
if self.port_type=="rw" or self.port_type=="w":
self.graph_inst_exclude.add(self.w_en_gate_inst)

View File

@ -57,10 +57,10 @@ class delay_chain(design.design):
def add_pins(self): def add_pins(self):
""" Add the pins of the delay chain""" """ Add the pins of the delay chain"""
self.add_pin("in") self.add_pin("in", "INPUT")
self.add_pin("out") self.add_pin("out", "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.inv = factory.create(module_type="pinv", route_output=False) self.inv = factory.create(module_type="pinv", route_output=False)

View File

@ -54,13 +54,13 @@ class dff_array(design.design):
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_din_name(row,col)) self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_dout_name(row,col)) self.add_pin(self.get_dout_name(row,col), "OUTPUT")
self.add_pin("clk") self.add_pin("clk", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_dff_array(self): def create_dff_array(self):
self.dff_insts={} self.dff_insts={}

View File

@ -75,12 +75,12 @@ class dff_buf(design.design):
def add_pins(self): def add_pins(self):
self.add_pin("D") self.add_pin("D", "INPUT")
self.add_pin("Q") self.add_pin("Q", "OUTPUT")
self.add_pin("Qb") self.add_pin("Qb", "OUTPUT")
self.add_pin("clk") self.add_pin("clk", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_instances(self): def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff", self.dff_inst=self.add_inst(name="dff_buf_dff",

View File

@ -55,14 +55,14 @@ class dff_buf_array(design.design):
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_din_name(row,col)) self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_dout_name(row,col)) self.add_pin(self.get_dout_name(row,col), "OUTPUT")
self.add_pin(self.get_dout_bar_name(row,col)) self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT")
self.add_pin("clk") self.add_pin("clk", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.dff = factory.create(module_type="dff_buf", self.dff = factory.create(module_type="dff_buf",

View File

@ -59,14 +59,14 @@ class dff_inv_array(design.design):
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_din_name(row,col)) self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows): for row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
self.add_pin(self.get_dout_name(row,col)) self.add_pin(self.get_dout_name(row,col), "OUTPUT")
self.add_pin(self.get_dout_bar_name(row,col)) self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT")
self.add_pin("clk") self.add_pin("clk", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_dff_array(self): def create_dff_array(self):
self.dff_insts={} self.dff_insts={}

View File

@ -15,13 +15,14 @@ class dummy_array(design.design):
""" """
Generate a dummy row/column for the replica array. Generate a dummy row/column for the replica array.
""" """
def __init__(self, cols, rows, name): def __init__(self, cols, rows, mirror=0, name=""):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols self.column_size = cols
self.row_size = rows self.row_size = rows
self.mirror = mirror
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -46,7 +47,7 @@ class dummy_array(design.design):
for row in range(self.row_size): for row in range(self.row_size):
name = "dummy_r{0}_c{1}".format(row, col) name = "dummy_r{0}_c{1}".format(row, col)
if row % 2: if (row+self.mirror) % 2:
tempy = yoffset + self.dummy_cell.height tempy = yoffset + self.dummy_cell.height
dir_key = "MX" dir_key = "MX"
else: else:
@ -65,16 +66,16 @@ class dummy_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
row_list = self.cell.list_all_wl_names() row_list = self.cell.get_all_wl_names()
column_list = self.cell.list_all_bitline_names() column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in column_list: for cell_column in column_list:
self.add_pin(cell_column+"_{0}".format(col)) self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size): for row in range(self.row_size):
for cell_row in row_list: for cell_row in row_list:
self.add_pin(cell_row+"_{0}".format(row)) self.add_pin(cell_row+"_{0}".format(row), "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
@ -83,16 +84,16 @@ class dummy_array(design.design):
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, """ Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """ indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
pin_names = self.cell.list_all_bitline_names() pin_names = self.cell.get_all_bitline_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col)) bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.list_all_wl_names() pin_names = self.cell.get_all_wl_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row)) bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
@ -109,13 +110,13 @@ class dummy_array(design.design):
name = "bit_r{0}_c{1}".format(row, col) name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name, self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.dummy_cell) mod=self.dummy_cell)
self.connect_inst(self.list_bitcell_pins(col, row)) self.connect_inst(self.get_bitcell_pins(col, row))
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
row_list = self.cell.list_all_wl_names() row_list = self.cell.get_all_wl_names()
column_list = self.cell.list_all_bitline_names() column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in column_list: for cell_column in column_list:

View File

@ -231,12 +231,12 @@ class hierarchical_decoder(design.design):
""" Add the module pins """ """ Add the module pins """
for i in range(self.num_inputs): for i in range(self.num_inputs):
self.add_pin("addr_{0}".format(i)) self.add_pin("addr_{0}".format(i), "INPUT")
for j in range(self.rows): for j in range(self.rows):
self.add_pin("decode_{0}".format(j)) self.add_pin("decode_{0}".format(j), "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_pre_decoder(self): def create_pre_decoder(self):

View File

@ -26,11 +26,11 @@ class hierarchical_predecode(design.design):
def add_pins(self): def add_pins(self):
for k in range(self.number_of_inputs): for k in range(self.number_of_inputs):
self.add_pin("in_{0}".format(k)) self.add_pin("in_{0}".format(k), "INPUT")
for i in range(self.number_of_outputs): for i in range(self.number_of_outputs):
self.add_pin("out_{0}".format(i)) self.add_pin("out_{0}".format(i), "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
""" Add the INV and NAND gate modules """ """ Add the INV and NAND gate modules """

View File

@ -83,8 +83,7 @@ class port_address(design.design):
driver_name = "wl_{}".format(row) driver_name = "wl_{}".format(row)
self.copy_layout_pin(self.wordline_driver_inst, driver_name) self.copy_layout_pin(self.wordline_driver_inst, driver_name)
# FIXME: Is this still inverted!? self.copy_layout_pin(self.wordline_driver_inst, "en", "wl_en")
self.copy_layout_pin(self.wordline_driver_inst, "en_bar", "wl_en")
def route_internal(self): def route_internal(self):
for row in range(self.num_rows): for row in range(self.num_rows):

View File

@ -15,6 +15,7 @@ from globals import OPTS
class port_data(design.design): class port_data(design.design):
""" """
Create the data port (column mux, sense amps, write driver, etc.) for the given port number. Create the data port (column mux, sense amps, write driver, etc.) for the given port number.
Port 0 always has the RBL on the left while port 1 is on the right.
""" """
def __init__(self, sram_config, port, name=""): def __init__(self, sram_config, port, name=""):
@ -80,9 +81,13 @@ class port_data(design.design):
def add_pins(self): def add_pins(self):
""" Adding pins for port address module""" """ Adding pins for port address module"""
if self.has_rbl():
self.add_pin("rbl_bl","INOUT")
self.add_pin("rbl_br","INOUT")
for bit in range(self.num_cols): for bit in range(self.num_cols):
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT") self.add_pin("{0}_{1}".format(self.bl_names[self.port], bit),"INOUT")
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT") self.add_pin("{0}_{1}".format(self.br_names[self.port], bit),"INOUT")
if self.port in self.read_ports: if self.port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout_{}".format(bit),"OUTPUT") self.add_pin("dout_{}".format(bit),"OUTPUT")
@ -95,8 +100,7 @@ class port_data(design.design):
self.add_pin(pin_name,"INPUT") self.add_pin(pin_name,"INPUT")
if self.port in self.read_ports: if self.port in self.read_ports:
self.add_pin("s_en", "INPUT") self.add_pin("s_en", "INPUT")
if self.port in self.read_ports: self.add_pin("p_en_bar", "INPUT")
self.add_pin("p_en_bar", "INPUT")
if self.port in self.write_ports: if self.port in self.write_ports:
self.add_pin("w_en", "INPUT") self.add_pin("w_en", "INPUT")
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
@ -132,12 +136,14 @@ class port_data(design.design):
self.route_sense_amp_to_column_mux_or_precharge_array(self.port) self.route_sense_amp_to_column_mux_or_precharge_array(self.port)
self.route_column_mux_to_precharge_array(self.port) self.route_column_mux_to_precharge_array(self.port)
else: else:
# write_driver -> (column_mux) -> bitcell_array # write_driver -> (column_mux ->) precharge -> bitcell_array
self.route_write_driver_in(self.port) self.route_write_driver_in(self.port)
self.route_write_driver_to_column_mux_or_bitcell_array(self.port) self.route_write_driver_to_column_mux_or_precharge_array(self.port)
self.route_column_mux_to_precharge_array(self.port)
def route_supplies(self): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
for inst in self.insts: for inst in self.insts:
self.copy_power_pins(inst,"vdd") self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd") self.copy_power_pins(inst,"gnd")
@ -145,8 +151,10 @@ class port_data(design.design):
def add_modules(self): def add_modules(self):
if self.port in self.read_ports: if self.port in self.read_ports:
# Extra column +1 is for RBL
# Precharge will be shifted left if needed
self.precharge_array = factory.create(module_type="precharge_array", self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols, columns=self.num_cols + 1,
bitcell_bl=self.bl_names[self.port], bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port]) bitcell_br=self.br_names[self.port])
self.add_mod(self.precharge_array) self.add_mod(self.precharge_array)
@ -156,8 +164,17 @@ class port_data(design.design):
words_per_row=self.words_per_row) words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array) self.add_mod(self.sense_amp_array)
else: else:
self.precharge_array = None # Precharge is needed when we have a column mux or for byte writes
# to prevent corruption of half-selected cells, so just always add it
# This is a little power inefficient for write ports without a column mux,
# but it is simpler.
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
self.add_mod(self.precharge_array)
self.sense_amp_array = None self.sense_amp_array = None
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.column_mux_array = factory.create(module_type="column_mux_array", self.column_mux_array = factory.create(module_type="column_mux_array",
@ -206,9 +223,9 @@ class port_data(design.design):
# create arrays of bitline and bitline_bar names for read, write, or all ports # create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.list_all_bl_names() self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.list_all_br_names() self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.list_all_wl_names() self.wl_names = self.bitcell.get_all_wl_names()
def create_precharge_array(self): def create_precharge_array(self):
""" Creating Precharge """ """ Creating Precharge """
@ -218,21 +235,32 @@ class port_data(design.design):
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array) mod=self.precharge_array)
temp = [] temp = []
# Use left BLs for RBL
if self.has_rbl() and self.port==0:
temp.append("rbl_bl")
temp.append("rbl_br")
for bit in range(self.num_cols): for bit in range(self.num_cols):
temp.append(self.bl_names[self.port]+"_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_{0}".format(bit))
temp.append(self.br_names[self.port]+"_{0}".format(bit)) temp.append(self.br_names[self.port]+"_{0}".format(bit))
# Use right BLs for RBL
if self.has_rbl() and self.port==1:
temp.append("rbl_bl")
temp.append("rbl_br")
temp.extend(["p_en_bar", "vdd"]) temp.extend(["p_en_bar", "vdd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_precharge_array(self, offset): def place_precharge_array(self, offset):
""" Placing Precharge """ """ Placing Precharge """
self.precharge_array_inst.place(offset=offset, mirror="MX") self.precharge_array_inst.place(offset=offset, mirror="MX")
def create_column_mux_array(self): def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """ """ Creating Column Mux when words_per_row > 1 . """
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port), self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array) mod=self.column_mux_array)
@ -248,7 +276,6 @@ class port_data(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_column_mux_array(self, offset): def place_column_mux_array(self, offset):
""" Placing Column Mux when words_per_row > 1 . """ """ Placing Column Mux when words_per_row > 1 . """
@ -272,7 +299,7 @@ class port_data(design.design):
else: else:
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
temp.extend(["s_en", "vdd", "gnd"]) temp.extend(["s_en", "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -292,7 +319,7 @@ class port_data(design.design):
temp.append("din_{}".format(bit)) temp.append("din_{}".format(bit))
for bit in range(self.word_size): for bit in range(self.word_size):
if (self.words_per_row == 1): if (self.words_per_row == 1):
temp.append(self.bl_names[self.port]+"_{0}".format(bit)) temp.append(self.bl_names[self.port]+"_{0}".format(bit))
temp.append(self.br_names[self.port]+"_{0}".format(bit)) temp.append(self.br_names[self.port]+"_{0}".format(bit))
else: else:
@ -305,6 +332,7 @@ class port_data(design.design):
else: else:
temp.append("w_en") temp.append("w_en")
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -339,21 +367,32 @@ class port_data(design.design):
vertical_port_order.append(self.sense_amp_array_inst) vertical_port_order.append(self.sense_amp_array_inst)
vertical_port_order.append(self.write_driver_array_inst) vertical_port_order.append(self.write_driver_array_inst)
# Add one column for the the RBL
if self.has_rbl() and self.port==0:
x_offset = self.bitcell.width
else:
x_offset = 0
vertical_port_offsets = 4*[None] vertical_port_offsets = 4*[None]
self.width = 0 self.width = x_offset
self.height = 0 self.height = 0
for i,p in enumerate(vertical_port_order): for i,p in enumerate(vertical_port_order):
if p==None: if p==None:
continue continue
self.height += (p.height + self.m2_gap) self.height += (p.height + self.m2_gap)
self.width = max(self.width, p.width) self.width = max(self.width, p.width)
vertical_port_offsets[i]=vector(0,self.height) vertical_port_offsets[i]=vector(x_offset,self.height)
# Reversed order # Reversed order
self.write_driver_offset = vertical_port_offsets[3] self.write_driver_offset = vertical_port_offsets[3]
self.sense_amp_offset = vertical_port_offsets[2] self.sense_amp_offset = vertical_port_offsets[2]
self.column_mux_offset = vertical_port_offsets[1] self.column_mux_offset = vertical_port_offsets[1]
self.precharge_offset = vertical_port_offsets[0] self.precharge_offset = vertical_port_offsets[0]
# Shift the precharge left if port 0
if self.precharge_offset and self.port==0:
self.precharge_offset -= vector(x_offset,0)
@ -399,30 +438,39 @@ class port_data(design.design):
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst2 = self.precharge_array_inst inst2 = self.precharge_array_inst
self.connect_bitlines(inst1, inst2, self.num_cols) if self.has_rbl() and self.port==0:
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1)
else:
self.connect_bitlines(inst1, inst2, self.num_cols)
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 """
inst2 = self.sense_amp_array_inst inst2 = self.sense_amp_array_inst
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
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bl_name = "bl_out_{}"
inst1_br_name = "br_out_{}" inst1_br_name = "br_out_{}"
start_bit = 0
else: else:
# Sense amp is directly connected to the precharge array # Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}" inst1_bl_name = "bl_{}"
inst1_br_name = "br_{}" inst1_br_name = "br_{}"
if self.has_rbl() and self.port==0:
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, start_bit=1
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) else:
start_bit=0
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 """ 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, inst1_start_bit=start_bit)
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 """
inst2 = self.write_driver_array_inst inst2 = self.write_driver_array_inst
if self.col_addr_size>0: if self.col_addr_size>0:
@ -430,12 +478,19 @@ class port_data(design.design):
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bl_name = "bl_out_{}"
inst1_br_name = "br_out_{}" inst1_br_name = "br_out_{}"
start_bit = 0
else: else:
# Write driver is directly connected to the bitcell array # Sense amp is directly connected to the precharge array
return inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}"
inst1_br_name = "br_{}"
if self.has_rbl() and self.port==0:
start_bit=1
else:
start_bit=0
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, 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) inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
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 """
@ -451,16 +506,25 @@ class port_data(design.design):
def route_bitline_pins(self): def route_bitline_pins(self):
""" Add the bitline pins for the given port """ """ Add the bitline pins for the given port """
# Connect one bitline to the RBL and offset the indices for the other BLs
if self.has_rbl() and self.port==0:
self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
bit_offset=1
elif self.has_rbl() and self.port==1:
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br")
bit_offset=0
else:
bit_offset=0
for bit in range(self.num_cols): for bit in range(self.num_cols):
if self.port in self.read_ports: if self.precharge_array_inst:
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit)) self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit+bit_offset), "bl_{}".format(bit))
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit)) self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit+bit_offset), "br_{}".format(bit))
elif self.column_mux_array_inst:
self.copy_layout_pin(self.column_mux_array_inst, "bl_{}".format(bit))
self.copy_layout_pin(self.column_mux_array_inst, "br_{}".format(bit))
else: else:
self.copy_layout_pin(self.write_driver_array_inst, "bl_{}".format(bit)) debug.error("Didn't find precharge arra.")
self.copy_layout_pin(self.write_driver_array_inst, "br_{}".format(bit))
def route_control_pins(self): def route_control_pins(self):
""" Add the control pins: s_en, p_en_bar, w_en """ """ Add the control pins: s_en, p_en_bar, w_en """
@ -477,8 +541,8 @@ class port_data(design.design):
def channel_route_bitlines(self, inst1, inst2, num_bits, def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
inst2_bl_name="bl_{}", inst2_br_name="br_{}"): inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
""" """
Route the bl and br of two modules using the channel router. Route the bl and br of two modules using the channel router.
""" """
@ -486,26 +550,27 @@ class port_data(design.design):
# determine top and bottom automatically. # determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate. # since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by(): if inst1.by() < inst2.by():
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name) (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name) (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
else: else:
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
# Channel route each mux separately since we don't minimize the number # 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! # 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) offset = bottom_inst.ul() + vector(0,self.m1_pitch)
for bit in range(num_bits): for bit in range(num_bits):
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit)), bottom_inst.get_pin(bottom_br_name.format(bit))] bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))]
top_names = [top_inst.get_pin(top_bl_name.format(bit)), top_inst.get_pin(top_br_name.format(bit))] top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))]
route_map = list(zip(bottom_names, top_names)) route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset) self.create_horizontal_channel_route(route_map, 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_{}", inst1_start_bit=0,
inst2_bl_name="bl_{}", inst2_br_name="br_{}"): inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
""" """
Connect the bl and br of two modules. Connect the bl and br of two modules.
This assumes that they have sufficient space to create a jog This assumes that they have sufficient space to create a jog
@ -515,17 +580,17 @@ class port_data(design.design):
# determine top and bottom automatically. # determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate. # since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by(): if inst1.by() < inst2.by():
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name) (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name) (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
else: else:
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
for col in range(num_bits): for col in range(num_bits):
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col)).uc() bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc()
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col)).uc() bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc()
top_bl = top_inst.get_pin(top_bl_name.format(col)).bc() top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc()
top_br = top_inst.get_pin(top_br_name.format(col)).bc() top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc()
yoffset = 0.5*(top_bl.y+bottom_bl.y) yoffset = 0.5*(top_bl.y+bottom_bl.y)
self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset), self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset),
@ -537,3 +602,6 @@ class port_data(design.design):
"""Precharge adds a loop between bitlines, can be excluded to reduce complexity""" """Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
if self.precharge_array_inst: if self.precharge_array_inst:
self.graph_inst_exclude.add(self.precharge_array_inst) self.graph_inst_exclude.add(self.precharge_array_inst)
def has_rbl(self):
return self.port in self.read_ports

View File

@ -35,10 +35,11 @@ class precharge_array(design.design):
def add_pins(self): def add_pins(self):
"""Adds pins for spice file""" """Adds pins for spice file"""
for i in range(self.columns): for i in range(self.columns):
self.add_pin("bl_{0}".format(i)) # These are outputs from the precharge only
self.add_pin("br_{0}".format(i)) self.add_pin("bl_{0}".format(i), "OUTPUT")
self.add_pin("en_bar") self.add_pin("br_{0}".format(i), "OUTPUT")
self.add_pin("vdd") self.add_pin("en_bar", "INPUT")
self.add_pin("vdd", "POWER")
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
@ -115,4 +116,4 @@ class precharge_array(design.design):
#Assume single port #Assume single port
precharge_en_cin = self.pc_cell.get_en_cin() precharge_en_cin = self.pc_cell.get_en_cin()
return precharge_en_cin*self.columns return precharge_en_cin*self.columns

View File

@ -17,18 +17,30 @@ import dummy_array
class replica_bitcell_array(design.design): class replica_bitcell_array(design.design):
""" """
Creates a bitcell arrow of cols x rows and then adds the replica and dummy columns Creates a bitcell arrow of cols x rows and then adds the replica
and rows for one or two read ports. Replica columns are on the left and right, respectively. and dummy columns and rows. Replica columns are on the left and
right, respectively and connected to the given bitcell ports.
Dummy are the outside columns/rows with WL and BL tied to gnd. Dummy are the outside columns/rows with WL and BL tied to gnd.
Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). Requires a regular bitcell array, replica bitcell, and dummy
bitcell (Bl/BR disconnected).
""" """
def __init__(self, cols, rows, name): def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols self.column_size = cols
self.row_size = rows self.row_size = rows
self.left_rbl = left_rbl
self.right_rbl = right_rbl
self.bitcell_ports = bitcell_ports
debug.check(left_rbl+right_rbl==len(self.read_ports),"Invalid number of RBLs for port configuration.")
debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.")
# Two dummy rows/cols plus replica for each port
self.extra_rows = 2 + left_rbl + right_rbl
self.extra_cols = 2 + left_rbl + right_rbl
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -78,127 +90,201 @@ class replica_bitcell_array(design.design):
rows=self.row_size) rows=self.row_size)
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
# Replica bitline # Replica bitlines
self.replica_column = factory.create(module_type="replica_column", self.replica_columns = {}
rows=self.row_size + 4) for bit in range(self.left_rbl+self.right_rbl):
self.add_mod(self.replica_column) if bit<self.left_rbl:
replica_bit = bit+1
else:
replica_bit = bit+self.row_size+1
self.replica_columns[bit] = factory.create(module_type="replica_column",
rows=self.row_size,
left_rbl=self.left_rbl,
right_rbl=self.right_rbl,
replica_bit=replica_bit)
self.add_mod(self.replica_columns[bit])
# Dummy row # Dummy row
self.dummy_row = factory.create(module_type="dummy_array", self.dummy_row = factory.create(module_type="dummy_array",
cols=self.column_size,
rows=1, rows=1,
cols=self.column_size) mirror=0)
self.add_mod(self.dummy_row) self.add_mod(self.dummy_row)
# Dummy col # Dummy col (mirror starting at first if odd replica+dummy rows)
self.dummy_col = factory.create(module_type="dummy_array", self.dummy_col = factory.create(module_type="dummy_array",
cols=1, cols=1,
rows=self.row_size + 4) rows=self.row_size + self.extra_rows,
mirror=(self.left_rbl+1)%2)
self.add_mod(self.dummy_col) self.add_mod(self.dummy_col)
def add_pins(self): def add_pins(self):
self.wl_names = [x for x in self.bitcell_array.pins if x.startswith("w")] self.bitcell_array_wl_names = [x for x in self.bitcell_array.pins if x.startswith("w")]
self.bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")] self.bitcell_array_bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")]
# top/bottom rows (in the middle) # These are the non-indexed names
self.replica_wl_names = ["replica_"+x for x in self.cell.pins if x.startswith("w")] self.dummy_cell_wl_names = ["dummy_"+x for x in self.cell.get_all_wl_names()]
self.dummy_wl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("w")] self.dummy_cell_bl_names = ["dummy_"+x for x in self.cell.get_all_bitline_names()]
self.dummy_bl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("b")] self.dummy_row_bl_names = self.bitcell_array_bl_names
self.dummy_row_bl_names = self.bl_names
# dummy row and replica on each side of the bitcell rows # A dictionary because some ports may have nothing
self.replica_col_wl_names = [x+"_0" for x in self.dummy_wl_names] \ self.rbl_bl_names = {}
+ ["replica_"+x+"_0" for x in self.cell.list_all_wl_names()] \ self.rbl_br_names = {}
+ self.wl_names \ self.rbl_wl_names = {}
+ ["replica_"+x+"_1" for x in self.cell.list_all_wl_names()] \
+ [x+"_1" for x in self.dummy_wl_names]
self.replica_bl_names = ["replica_"+x for x in self.cell.pins if x.startswith("b")]
# left/right rows # Create the full WL names include dummy, replica, and regular bit cells
self.replica_col_wl_names = []
self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names])
# Left port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names)
# Regular WLs
self.replica_col_wl_names.extend(self.bitcell_array_wl_names)
# Right port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl,self.left_rbl+self.right_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names)
self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names])
# Left/right dummy columns are connected identically to the replica column
self.dummy_col_wl_names = self.replica_col_wl_names self.dummy_col_wl_names = self.replica_col_wl_names
self.add_pin_list(self.bl_names)
self.add_pin_list([x+"_0" for x in self.replica_bl_names])
self.add_pin_list([x+"_1" for x in self.replica_bl_names])
self.add_pin_list([x for x in self.replica_col_wl_names if not x.startswith("dummy")])
self.add_pin("vdd")
self.add_pin("gnd") # Per port bitline names
self.replica_bl_names = {}
self.replica_wl_names = {}
# Array of all port bitline names
for port in range(self.left_rbl+self.right_rbl):
left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x),port) for x in range(len(self.all_ports))]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the left pins that are the RBL
self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]]
self.rbl_br_names[port]=right_names[self.bitcell_ports[port]]
# Interleave the left and right lists
bl_names = [x for t in zip(left_names, right_names) for x in t]
self.replica_bl_names[port] = bl_names
wl_names = ["rbl_{0}_{1}".format(x,port) for x in self.cell.get_all_wl_names()]
#wl_names[port] = "rbl_wl{}".format(port)
self.replica_wl_names[port] = wl_names
# External pins
self.add_pin_list(self.bitcell_array_bl_names, "INOUT")
# Need to sort by port order since dictionary values may not be in order
bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())]
br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())]
for (bl_name,br_name) in zip(bl_names,br_names):
self.add_pin(bl_name,"OUTPUT")
self.add_pin(br_name,"OUTPUT")
self.add_pin_list(self.bitcell_array_wl_names, "INPUT")
# Need to sort by port order since dictionary values may not be in order
wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())]
for pin_name in wl_names:
self.add_pin(pin_name,"INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
supplies = ["vdd", "gnd"] supplies = ["vdd", "gnd"]
# Used for names/dimensions only
self.cell = factory.create(module_type="bitcell")
# Main array # Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array", self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.bitcell_array) mod=self.bitcell_array)
self.connect_inst(self.bitcell_array.pins) self.connect_inst(self.bitcell_array_bl_names + self.bitcell_array_wl_names + supplies)
# Replica columns (two even if one port for now) # Replica columns
self.replica_col_left_inst=self.add_inst(name="replica_col_left", self.replica_col_inst = {}
mod=self.replica_column) for port in range(self.left_rbl+self.right_rbl):
self.connect_inst([x+"_0" for x in self.replica_bl_names] + self.replica_col_wl_names + supplies) self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port])
self.replica_col_right_inst=self.add_inst(name="replica_col_right", self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies)
mod=self.replica_column)
self.connect_inst([x+"_1" for x in self.replica_bl_names] + self.replica_col_wl_names[::-1] + supplies)
# Replica rows with replica bitcell
self.dummy_row_bottop_inst=self.add_inst(name="dummy_row_bottop", # Dummy rows under the bitcell array (connected with with the replica cell wl)
mod=self.dummy_row) self.dummy_row_replica_inst = {}
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.replica_wl_names] + supplies) for port in range(self.left_rbl+self.right_rbl):
self.dummy_row_topbot_inst=self.add_inst(name="dummy_row_topbot", self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row) mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.replica_wl_names] + supplies) self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies)
# Dummy rows without replica bitcell # Top/bottom dummy rows
self.dummy_row_botbot_inst=self.add_inst(name="dummy_row_botbot", self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
mod=self.dummy_row) mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.dummy_wl_names] + supplies) self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies)
self.dummy_row_toptop_inst=self.add_inst(name="dummy_row_toptop", self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
mod=self.dummy_row) mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.dummy_wl_names] + supplies) self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies)
# Dummy columns # Left/right Dummy columns
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
mod=self.dummy_col) mod=self.dummy_col)
self.connect_inst([x+"_0" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies) self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right", self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
mod=self.dummy_col) mod=self.dummy_col)
self.connect_inst([x+"_1" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies) self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
def create_layout(self): def create_layout(self):
self.height = (self.row_size+4)*self.dummy_row.height self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
self.width = (self.column_size+4)*self.replica_column.width self.width = (self.column_size+self.extra_cols)*self.cell.width
# This is a bitcell x bitcell offset to scale # This is a bitcell x bitcell offset to scale
offset = vector(self.replica_column.width, self.dummy_row.height) offset = vector(self.cell.width, self.cell.height)
self.bitcell_array_inst.place(offset=[0,0]) self.bitcell_array_inst.place(offset=[0,0])
self.replica_col_left_inst.place(offset=offset.scale(-1,-2))
self.replica_col_right_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ur(),
mirror="MX")
self.dummy_row_toptop_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ul(),
mirror="MX")
self.dummy_row_topbot_inst.place(offset=offset.scale(0,0)+self.bitcell_array_inst.ul())
self.dummy_row_bottop_inst.place(offset=offset.scale(0,0),
mirror="MX")
self.dummy_row_botbot_inst.place(offset=offset.scale(0,-2))
self.dummy_col_left_inst.place(offset=offset.scale(-2,-2)) # To the left of the bitcell array
self.dummy_col_right_inst.place(offset=offset.scale(1,-2)+self.bitcell_array_inst.lr()) for bit in range(self.left_rbl):
self.replica_col_inst[bit].place(offset=offset.scale(-bit-1,-self.left_rbl-1))
# To the right of the bitcell array
for bit in range(self.right_rbl):
self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr())
self.translate_all(offset.scale(-2,-2)) # Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.right_rbl%2
self.dummy_row_top_inst.place(offset=offset.scale(0,self.right_rbl+flip_dummy)+self.bitcell_array_inst.ul(),
mirror="MX" if flip_dummy else "R0")
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.left_rbl+1)%2
self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy),
mirror="MX" if flip_dummy else "R0")
# Far left dummy col
self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl-1,-self.left_rbl-1))
# Far right dummy col
self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl,-self.left_rbl-1)+self.bitcell_array_inst.lr())
# Replica dummy rows
for bit in range(self.left_rbl):
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2),
mirror="R0" if bit%2 else "MX")
for bit in range(self.right_rbl):
self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(),
mirror="MX" if bit%2 else "R0")
self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl))
self.add_layout_pins() self.add_layout_pins()
@ -216,90 +302,77 @@ class replica_bitcell_array(design.design):
if pin_name.startswith("wl"): if pin_name.startswith("wl"):
pin_list = self.bitcell_array_inst.get_pins(pin_name) pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_layout_pin_rect_center(text=pin_name, self.add_layout_pin(text=pin_name,
layer=pin.layer, layer=pin.layer,
offset=pin.center(), offset=pin.ll().scale(0,1),
width=self.width, width=self.width,
height=pin.height()) height=pin.height())
elif pin_name.startswith("bl") or pin_name.startswith("br"): elif pin_name.startswith("bl") or pin_name.startswith("br"):
pin_list = self.bitcell_array_inst.get_pins(pin_name) pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_layout_pin_rect_center(text=pin_name, self.add_layout_pin(text=pin_name,
layer=pin.layer, layer=pin.layer,
offset=pin.center(), offset=pin.ll().scale(1,0),
width=pin.width(), width=pin.width(),
height=self.height) height=self.height)
for index,(side1,side2) in enumerate([("bottop","left"),("topbot","right")]): # Replica wordlines
inst = getattr(self, "dummy_row_{}_inst".format(side1)) for port in range(self.left_rbl+self.right_rbl):
pin_names = inst.mod.get_pin_names() inst = self.replica_col_inst[port]
for pin_name in pin_names: for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]):
if pin_name.startswith("wl"): # +1 for dummy row
pin_list = inst.get_pins(pin_name) pin_bit = port+1
for pin in pin_list: # +row_size if above the array
name = "replica_{0}_{1}".format(pin_name,index) if port>=self.left_rbl:
self.add_layout_pin_rect_center(text=name, pin_bit += self.row_size
layer=pin.layer,
offset=pin.center(), pin_name += "_{}".format(pin_bit)
width=self.width, pin = inst.get_pin(pin_name)
height=pin.height()) if wl_name in self.rbl_wl_names.values():
self.add_layout_pin(text=wl_name,
layer=pin.layer,
offset=pin.ll().scale(0,1),
width=self.width,
height=pin.height())
# Replica columns
for index,side in enumerate(["left","right"]): # Replica bitlines
inst = getattr(self, "replica_col_{}_inst".format(side)) for port in range(self.left_rbl+self.right_rbl):
pin_names = inst.mod.get_pin_names() inst = self.replica_col_inst[port]
for pin_name in pin_names: for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(),self.replica_bl_names[port]):
if pin_name.startswith("bl") or pin_name.startswith("br"): pin = inst.get_pin(pin_name)
pin_list = inst.get_pins(pin_name) if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names:
for pin in pin_list: name = bl_name
name = "replica_{0}_{1}".format(pin_name,index) else:
self.add_layout_pin(text=name, name = "rbl_{0}_{1}".format(pin_name,port)
layer=pin.layer, self.add_layout_pin(text=name,
offset=pin.ll().scale(1,0), layer=pin.layer,
width=pin.width(), offset=pin.ll().scale(1,0),
height=self.height) width=pin.width(),
height=self.height)
for pin_name in ["vdd","gnd"]: for pin_name in ["vdd","gnd"]:
for inst in [self.bitcell_array_inst, for inst in self.insts:
self.replica_col_left_inst, self.replica_col_right_inst,
self.dummy_col_left_inst, self.dummy_col_right_inst,
self.dummy_row_toptop_inst, self.dummy_row_topbot_inst,
self.dummy_row_bottop_inst, self.dummy_row_botbot_inst]:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
# Non-pins
for side in ["botbot", "toptop"]:
inst = getattr(self, "dummy_row_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("wl"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_rect_center(layer=pin.layer,
offset=pin.center(),
width=self.width,
height=pin.height())
for side in ["left", "right"]:
inst = getattr(self, "dummy_col_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("b"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_rect_center(layer=pin.layer,
offset=pin.center(),
width=pin.width(),
height=self.height)
def get_rbl_wl_name(self, port):
""" Return the WL for the given RBL port """
return self.rbl_wl_names[port]
def get_rbl_bl_name(self, port):
""" Return the BL for the given RBL port """
return self.rbl_bl_names[port]
def get_rbl_br_name(self, port):
""" Return the BR for the given RBL port """
return self.rbl_br_names[port]
def analytical_delay(self, corner, slew, load): def analytical_delay(self, corner, slew, load):
"""Returns relative delay of the bitline in the bitcell array""" """Returns relative delay of the bitline in the bitcell array"""
@ -307,7 +380,7 @@ class replica_bitcell_array(design.design):
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux. #The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics. #The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
wire_unit_load = .05 * drain_load #Wires add 5% to this. wire_unit_load = 0.05 * drain_load #Wires add 5% to this.
bitline_load = (drain_load+wire_unit_load)*self.row_size bitline_load = (drain_load+wire_unit_load)*self.row_size
return [self.cell.analytical_delay(corner, slew, load+bitline_load)] return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
@ -318,7 +391,7 @@ class replica_bitcell_array(design.design):
# Dynamic Power from Bitline # Dynamic Power from Bitline
bl_wire = self.gen_bl_wire() bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() cell_load = 2 * bl_wire.return_input_cap()
bl_swing = parameter["rbl_height_percentage"] bl_swing = OPTS.rbl_delay_percentage
freq = spice["default_event_rate"] freq = spice["default_event_rate"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
@ -346,3 +419,17 @@ class replica_bitcell_array(design.design):
bitcell_wl_cin = self.cell.get_wl_cin() bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size total_cin = bitcell_wl_cin * self.column_size
return total_cin return total_cin
def graph_exclude_bits(self, targ_row, targ_col):
"""Excludes bits in column from being added to graph except target"""
self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
def graph_exclude_replica_col_bits(self):
"""Exclude all replica/dummy cells in the replica columns except the replica bit."""
for port in range(self.left_rbl+self.right_rbl):
self.replica_columns[port].exclude_all_but_replica()
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col)

View File

@ -1,621 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import design
from tech import drc
import contact
from sram_factory import factory
from vector import vector
from globals import OPTS
class replica_bitline(design.design):
"""
Generate a module that simulates the delay of control logic
and bit line charging. Stages is the depth of the delay
line and rows is the height of the replica bit loads.
"""
def __init__(self, name, delay_fanout_list, bitcell_loads):
design.design.__init__(self, name)
self.bitcell_loads = bitcell_loads
self.delay_fanout_list = delay_fanout_list
if len(delay_fanout_list) == 0 or len(delay_fanout_list)%2 == 1:
debug.error('Delay chain must contain an even amount of stages to maintain polarity.',1)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_instances()
def create_layout(self):
self.calculate_module_offsets()
self.place_instances()
self.route()
self.add_layout_pins()
self.offset_all_coordinates()
#self.add_lvs_correspondence_points()
# Extra pitch on top and right
self.width = self.replica_column_inst.rx() - self.delay_chain_inst.lx() + self.m2_pitch
self.height = max(self.replica_column_inst.uy(), self.delay_chain_inst.uy()) + self.m3_pitch
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
def calculate_module_offsets(self):
""" Calculate all the module offsets """
# These aren't for instantiating, but we use them to get the dimensions
self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
# Quadrant 1: Replica bitline and such are not rotated, but they must be placed far enough
# away from the delay chain/inverter with space for three M2 tracks
self.bitcell_offset = vector(0,self.replica_bitcell.height)
self.rbl_offset = self.bitcell_offset
# Gap between the delay chain and RBL
gap_width = 2*self.m2_pitch
# Quadrant 4: with some space below it and tracks on the right for vdd/gnd
self.delay_chain_offset = vector(-self.delay_chain.width-gap_width,self.replica_bitcell.height)
# Will be flipped vertically below the delay chain
# Align it with the inverters in the delay chain to simplify supply connections
self.rbl_inv_offset = self.delay_chain_offset + vector(2*self.inv.width, 0)
# Placed next to the replica bitcell
self.access_tx_offset = vector(-gap_width-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
def add_modules(self):
""" Add the modules for later usage """
self.replica_bitcell = factory.create(module_type="replica_bitcell")
self.add_mod(self.replica_bitcell)
# This is the replica bitline load column that is the height of our array
self.rbl = factory.create(module_type="bitcell_array",
cols=1,
rows=self.bitcell_loads)
self.add_mod(self.rbl)
# FIXME: The FO and depth of this should be tuned
self.delay_chain = factory.create(module_type="delay_chain",
fanout_list=self.delay_fanout_list)
self.add_mod(self.delay_chain)
self.inv = factory.create(module_type="pinv")
self.add_mod(self.inv)
self.access_tx = factory.create(module_type="ptx",
tx_type="pmos")
self.add_mod(self.access_tx)
def create_instances(self):
""" Create all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
mod=self.inv)
self.connect_inst(["bl0_0", "out", "vdd", "gnd"])
self.tx_inst=self.add_inst(name="rbl_access_tx",
mod=self.access_tx)
# D, G, S, B
self.connect_inst(["vdd", "delayed_en", "bl0_0", "vdd"])
# add the well and poly contact
self.delay_chain_inst=self.add_inst(name="delay_chain",
mod=self.delay_chain)
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
self.replica_cell_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell)
temp = []
for port in self.all_ports:
temp.append("bl{}_0".format(port))
temp.append("br{}_0".format(port))
for port in self.all_ports:
temp.append("delayed_en")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
self.replica_column_inst=self.add_inst(name="load",
mod=self.rbl)
temp = []
for port in self.all_ports:
temp.append("bl{}_0".format(port))
temp.append("br{}_0".format(port))
for wl in range(self.bitcell_loads):
for port in self.all_ports:
temp.append("gnd")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
self.wl_list = self.rbl.cell.list_all_wl_names()
self.bl_list = self.rbl.cell.list_all_bl_names()
def place_instances(self):
""" Add all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL
self.rbl_inv_inst.place(offset=self.rbl_inv_offset,
rotate=180)
self.tx_inst.place(self.access_tx_offset)
self.delay_chain_inst.place(self.delay_chain_offset)
self.replica_cell_inst.place(offset=self.bitcell_offset,
mirror="MX")
self.replica_column_inst.place(self.rbl_offset)
def route(self):
""" Connect all the signals together """
self.route_supplies()
self.route_wl()
self.route_access_tx()
def route_wl(self):
""" Connect the RBL word lines to gnd """
# Connect the WL and gnd pins directly to the center and right gnd rails
for row in range(self.bitcell_loads):
wl = self.wl_list[0]+"_{}".format(row)
pin = self.replica_column_inst.get_pin(wl)
# Route the connection to the right so that it doesn't interfere with the cells
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
pin_right = pin.rc()
pin_extension = pin_right + vector(self.m3_pitch,0)
if pin.layer != "metal1":
continue
pin_width_ydir = pin.uy()-pin.by()
#Width is set to pin y width to avoid DRC issues with m1 gaps
self.add_path("metal1", [pin_right, pin_extension], pin_width_ydir)
self.add_power_pin("gnd", pin_extension)
# for multiport, need to short wordlines to each other so they all connect to gnd.
wl_last = self.wl_list[-1]+"_{}".format(row)
pin_last = self.replica_column_inst.get_pin(wl_last)
self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None):
"""Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins."""
#Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord.
#This is my (Hunter) first time editing layout in openram so this function is likely not optimal.
if len(self.all_ports) > 1:
#1. Create vertical metal for all the bitlines to connect to
#m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped
correct_y = vector(0, 0.5*drc("minwidth_metal1"))
#x spacing depends on the side being drawn. Unknown to me (Hunter) why the size of the space differs by the side.
#I assume this is related to how a wire is draw, but I have not investigated the issue.
if pin_side == "right":
correct_x = vector(0.5*drc("minwidth_metal1"), 0)
if offset_x_vec != None:
correct_x = offset_x_vec
else:
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
if wl_pin_a.uy() > wl_pin_b.uy():
self.add_path("metal1", [wl_pin_a.rc()+correct_x+correct_y, wl_pin_b.rc()+correct_x-correct_y])
else:
self.add_path("metal1", [wl_pin_a.rc()+correct_x-correct_y, wl_pin_b.rc()+correct_x+correct_y])
elif pin_side == "left":
if offset_x_vec != None:
correct_x = offset_x_vec
else:
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
if wl_pin_a.uy() > wl_pin_b.uy():
self.add_path("metal1", [wl_pin_a.lc()-correct_x+correct_y, wl_pin_b.lc()-correct_x-correct_y])
else:
self.add_path("metal1", [wl_pin_a.lc()-correct_x-correct_y, wl_pin_b.lc()-correct_x+correct_y])
else:
debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1)
#2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this.
for port in self.all_ports:
if is_replica_cell:
wl = self.wl_list[port]
pin = self.replica_cell_inst.get_pin(wl)
else:
wl = self.wl_list[port]+"_{}".format(cell_row)
pin = self.replica_column_inst.get_pin(wl)
if pin_side == "left":
self.add_path("metal1", [pin.lc()-correct_x, pin.lc()])
elif pin_side == "right":
self.add_path("metal1", [pin.rc()+correct_x, pin.rc()])
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has
top_instances = [self.replica_column_inst,
self.delay_chain_inst]
for inst in top_instances:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
# Route the inverter supply pin from M1
# Only vdd is needed because gnd shares a rail with the delay chain
pin = self.rbl_inv_inst.get_pin("vdd")
self.add_power_pin("vdd", pin.lc())
for pin in self.replica_cell_inst.get_pins("vdd"):
self.add_power_pin(name="vdd", loc=pin.center(), vertical=True, start_layer=pin.layer)
for pin in self.replica_cell_inst.get_pins("gnd"):
self.add_power_pin("gnd", pin.center(), vertical=True, start_layer=pin.layer)
def route_access_tx(self):
# GATE ROUTE
# 1. Add the poly contact and nwell enclosure
# Determines the y-coordinate of where to place the gate input poly pin
# (middle in between the pmos and nmos)
poly_pin = self.tx_inst.get_pin("G")
poly_offset = poly_pin.uc()
# This centers the contact above the poly by one pitch
contact_offset = poly_offset + vector(0,self.m2_pitch)
self.add_via_center(layers=("poly", "contact", "metal1"),
offset=contact_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=contact_offset)
self.add_segment_center(layer="poly",
start=poly_offset,
end=contact_offset)
nwell_offset = self.rbl_inv_offset + vector(-self.inv.height,self.inv.width)
# self.add_rect(layer="nwell",
# offset=nwell_offset,
# width=0.5*self.inv.height,
# height=self.delay_chain_offset.y-nwell_offset.y)
# 2. Route delay chain output to access tx gate
delay_en_offset = self.delay_chain_inst.get_pin("out").bc()
self.add_path("metal2", [delay_en_offset,contact_offset])
# 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL
wl_offset = self.replica_cell_inst.get_pin(self.wl_list[0]).lc()
wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0)
wl_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
#wl_mid1 = vector(xmid_point,contact_offset.y)
#wl_mid2 = vector(xmid_point,wl_offset.y)
self.add_path("metal1", [wl_offset, wl_mid1, wl_mid2, contact_offset])
# 4. Short wodlines if multiport
wl = self.wl_list[0]
wl_last = self.wl_list[-1]
pin = self.replica_cell_inst.get_pin(wl)
pin_last = self.replica_cell_inst.get_pin(wl_last)
x_offset = self.short_wordlines(pin, pin_last, "left", True)
#correct = vector(0.5*drc("minwidth_metal1"), 0)
#self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
# DRAIN ROUTE
# Route the drain to the vdd rail
drain_offset = self.tx_inst.get_pin("D").center()
self.add_power_pin("vdd", drain_offset, vertical=True)
# SOURCE ROUTE
# Route the drain to the RBL inverter input
source_offset = self.tx_inst.get_pin("S").center()
inv_A_offset = self.rbl_inv_inst.get_pin("A").center()
self.add_path("metal1",[source_offset, inv_A_offset])
# Route the connection of the source route to the RBL bitline (left)
# Via will go halfway down from the bitcell
bl_offset = self.replica_cell_inst.get_pin(self.bl_list[0]).bc()
# Route down a pitch so we can use M2 routing
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=source_offset)
# BODY ROUTE
# Connect it to the inverter well
nwell_offset = self.rbl_inv_inst.lr()
ur_offset = self.tx_inst.ur()
self.add_rect(layer="nwell",
offset=nwell_offset,
width=ur_offset.x-nwell_offset.x,
height=ur_offset.y-nwell_offset.y)
def route_vdd(self):
""" Route all signals connected to vdd """
self.copy_layout_pin(self.delay_chain_inst,"vdd")
self.copy_layout_pin(self.replica_cell_inst,"vdd")
# Connect the WL and vdd pins directly to the center and right vdd rails
# Connect RBL vdd pins to center and right rails
rbl_vdd_pins = self.replica_column_inst.get_pins("vdd")
for pin in rbl_vdd_pins:
if pin.layer != "metal1":
continue
start = vector(self.center_vdd_pin.cx(),pin.cy())
end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end)
# Add via for the inverter
pin = self.rbl_inv_inst.get_pin("vdd")
start = vector(self.left_vdd_pin.cx(),pin.cy())
end = vector(self.center_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end)
# Add via for the RBC
pin = self.replica_cell_inst.get_pin("vdd")
start = pin.lc()
end = vector(self.right_vdd_pin.cx(),pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end)
# Create the RBL rails too
rbl_pins = self.replica_column_inst.get_pins("vdd")
for pin in rbl_pins:
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_vdd_pin.cx(),pin.cy())
center = vector(self.center_vdd_pin.cx(),pin.cy())
if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
start = left
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left)
else:
start = center
end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy())
self.add_layout_pin_segment_center(text="vdd",
layer="metal1",
start=start,
end=end)
def route_gnd(self):
""" Route all signals connected to gnd """
# Route the gnd lines from left to right
# Add via for the delay chain
left_gnd_start = self.delay_chain_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
left_gnd_end = vector(left_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.left_gnd_pin=self.add_segment_center(layer="metal2",
start=left_gnd_start,
end=left_gnd_end)
# Gnd line to the left of the replica bitline
center_gnd_start = self.replica_cell_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
center_gnd_end = vector(center_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.center_gnd_pin=self.add_segment_center(layer="metal2",
start=center_gnd_start,
end=center_gnd_end)
# Gnd line to the right of the replica bitline
right_gnd_start = self.replica_cell_inst.lr().scale(1,0) + vector(self.m2_pitch,0)
right_gnd_end = vector(right_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
self.right_gnd_pin=self.add_segment_center(layer="metal2",
start=right_gnd_start,
end=right_gnd_end)
# Connect the WL and gnd pins directly to the center and right gnd rails
for row in range(self.bitcell_loads):
wl = self.wl_list[0]+"_{}".format(row)
pin = self.replica_column_inst.get_pin(wl)
if pin.layer != "metal1":
continue
# If above the delay line, route the full width
left = vector(self.left_gnd_pin.cx(),pin.cy())
center = vector(self.center_gnd_pin.cx(),pin.cy())
if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
start = left
else:
start = center
end = vector(self.right_gnd_pin.cx(),pin.cy())
self.add_layout_pin_segment_center(text="gnd",
layer="metal1",
start=start,
end=end)
if start == left:
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=center)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=end)
# rbl_gnd_pins = self.replica_column_inst.get_pins("gnd")
# # Add L shapes to each vertical gnd rail
# for pin in rbl_gnd_pins:
# if pin.layer != "metal1":
# continue
# # If above the delay line, route the full width
# left = vector(self.left_gnd_pin.cx(),pin.cy())
# center = vector(self.center_gnd_pin.cx(),pin.cy())
# if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
# start = left
# else:
# start = center
# end = vector(self.right_gnd_pin.cx(),pin.cy())
# self.add_segment_center(layer="metal1",
# start=start,
# end=end)
# if start == left:
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=left)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=center)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end)
# Connect the gnd pins of the delay chain to the left rails
dc_gnd_pins = self.delay_chain_inst.get_pins("gnd")
for pin in dc_gnd_pins:
if pin.layer != "metal1":
continue
start = vector(self.left_gnd_pin.cx(),pin.cy())
# Note, we don't connect to the center rails because of
# via conflicts with the RBL
#end = vector(self.center_gnd_pin.cx(),pin.cy())
end = pin.rc()
self.add_segment_center(layer="metal1",
start=start,
end=end)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end)
# Add via for the inverter
# pin = self.rbl_inv_inst.get_pin("gnd")
# start = vector(self.left_gnd_pin.cx(),pin.cy())
# end = vector(self.center_gnd_pin.cx(),pin.cy())
# self.add_segment_center(layer="metal1",
# start=start,
# end=end)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=start)
# self.add_via_center(layers=("metal1", "via1", "metal2"),
# offset=end)
# Create RBL rails too
rbl_pins = self.replica_column_inst.get_pins("gnd")
for pin in rbl_pins:
if pin.layer != "metal2":
continue
start = vector(pin.cx(),self.right_gnd_pin.by())
end = vector(pin.cx(),self.right_gnd_pin.uy())
self.add_layout_pin_segment_center(text="gnd",
layer="metal2",
start=start,
end=end)
def add_layout_pins(self):
""" Route the input and output signal """
en_offset = self.delay_chain_inst.get_pin("in").bc()
self.add_layout_pin_segment_center(text="en",
layer="metal2",
start=en_offset,
end=en_offset.scale(1,0))
out_offset = self.rbl_inv_inst.get_pin("Z").center()
self.add_layout_pin_segment_center(text="out",
layer="metal2",
start=out_offset,
end=out_offset.scale(1,0))
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=out_offset)
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.
These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist.
"""
pin = self.rbl_inv_inst.get_pin("A")
self.add_label_pin(text="bl[0]",
layer=pin.layer,
offset=pin.ll(),
height=pin.height(),
width=pin.width())
pin = self.delay_chain_inst.get_pin("out")
self.add_label_pin(text="delayed_en",
layer=pin.layer,
offset=pin.ll(),
height=pin.height(),
width=pin.width())
def get_en_cin(self):
"""Get the enable input relative capacitance"""
#The enable is only connected to the delay, get the cin from that module
en_cin = self.delay_chain.get_cin()
return en_cin
def determine_sen_stage_efforts(self, ext_cout, inp_is_rise=True):
"""Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
stage_effort_list = []
#Stage 1 is the delay chain
stage1_cout = self.get_delayed_en_cin()
stage1 = self.delay_chain.determine_delayed_en_stage_efforts(stage1_cout, inp_is_rise)
stage_effort_list += stage1
#There is a disconnect between the delay chain and inverter. The rise/fall of the input to the inverter
#Will be the negation of the previous stage.
last_stage_is_rise = not stage_effort_list[-1].is_rise
#The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
#model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise)
stage_effort_list.append(stage2)
return stage_effort_list
def get_delayed_en_cin(self):
"""Get the fanout capacitance (relative) of the delayed enable from the delay chain."""
access_tx_cin = self.access_tx.get_cin()
rbc_cin = self.replica_bitcell.get_wl_cin()
return access_tx_cin + rbc_cin

View File

@ -14,12 +14,25 @@ from globals import OPTS
class replica_column(design.design): class replica_column(design.design):
""" """
Generate a replica bitline column for the replica array. Generate a replica bitline column for the replica array.
Rows is the total number of rows i the main array.
Left_rbl and right_rbl are the number of left and right replica bitlines.
Replica bit specifies which replica column this is (to determine where to put the
replica cell.
""" """
def __init__(self, name, rows): def __init__(self, name, rows, left_rbl, right_rbl, replica_bit):
design.design.__init__(self, name) design.design.__init__(self, name)
self.row_size = rows self.rows = rows
self.left_rbl = left_rbl
self.right_rbl = right_rbl
self.replica_bit = replica_bit
# left, right, regular rows plus top/bottom dummy cells
self.total_size = self.left_rbl+rows+self.right_rbl+2
debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.")
debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1,
"Replica bit cannot be in the regular array.")
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -31,26 +44,26 @@ class replica_column(design.design):
self.create_instances() self.create_instances()
def create_layout(self): def create_layout(self):
self.place_instances() self.height = self.total_size*self.cell.height
self.add_layout_pins()
self.height = self.row_size*self.cell.height
self.width = self.cell.width self.width = self.cell.width
self.place_instances()
self.add_layout_pins()
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
column_list = self.cell.list_all_bitline_names()
for cell_column in column_list: for bl_name in self.cell.get_all_bitline_names():
self.add_pin("{0}_{1}".format(cell_column,0)) # In the replica column, these are only outputs!
row_list = self.cell.list_all_wl_names() self.add_pin("{0}_{1}".format(bl_name,0), "OUTPUT")
for row in range(self.row_size):
for cell_row in row_list: for row in range(self.total_size):
self.add_pin("{0}_{1}".format(cell_row,row)) for wl_name in self.cell.get_all_wl_names():
self.add_pin("{0}_{1}".format(wl_name,row), "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.replica_cell = factory.create(module_type="replica_bitcell") self.replica_cell = factory.create(module_type="replica_bitcell")
@ -62,76 +75,77 @@ class replica_column(design.design):
def create_instances(self): def create_instances(self):
self.cell_inst = {} self.cell_inst = {}
for row in range(self.row_size): for row in range(self.total_size):
name="rbc_{0}".format(row) name="rbc_{0}".format(row)
if row>0 and row<self.row_size-2: # Top/bottom cell are always dummy cells.
# Regular array cells are replica cells (>left_rbl and <rows-right_rbl)
# Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell.
if (row>self.left_rbl and row<self.total_size-self.right_rbl-1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
elif row==self.replica_bit:
self.cell_inst[row]=self.add_inst(name=name, self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell) mod=self.replica_cell)
else: else:
self.cell_inst[row]=self.add_inst(name=name, self.cell_inst[row]=self.add_inst(name=name,
mod=self.dummy_cell) mod=self.dummy_cell)
self.connect_inst(self.list_bitcell_pins(0, row)) self.connect_inst(self.get_bitcell_pins(0, row))
def place_instances(self): def place_instances(self):
yoffset = 0 # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom
for row in range(self.row_size): # so that we will start with mirroring rather than not mirroring
rbl_offset = (self.left_rbl+1)%2
for row in range(self.total_size):
name = "bit_r{0}_{1}".format(row,"rbl") name = "bit_r{0}_{1}".format(row,"rbl")
offset = vector(0,self.cell.height*(row+(row+rbl_offset)%2))
# This is opposite of a bitcell array since we will be 1 row off if (row+rbl_offset)%2:
if not row % 2:
tempy = yoffset
dir_key = ""
else:
tempy = yoffset + self.cell.height
dir_key = "MX" dir_key = "MX"
else:
dir_key = "R0"
self.cell_inst[row].place(offset=[0.0, tempy], self.cell_inst[row].place(offset=offset,
mirror=dir_key) mirror=dir_key)
yoffset += self.cell.height
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
row_list = self.cell.list_all_wl_names() for bl_name in self.cell.get_all_bitline_names():
column_list = self.cell.list_all_bitline_names() bl_pin = self.cell_inst[0].get_pin(bl_name)
self.add_layout_pin(text=bl_name,
col = "0"
for cell_column in column_list:
bl_pin = self.cell_inst[0].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
layer="metal2", layer="metal2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=self.height) height=self.height)
for row in range(self.row_size): for row in range(self.total_size):
for cell_row in row_list: for wl_name in self.cell.get_all_wl_names():
wl_pin = self.cell_inst[row].get_pin(cell_row) wl_pin = self.cell_inst[row].get_pin(wl_name)
self.add_layout_pin(text=cell_row+"_{0}".format(row), self.add_layout_pin(text="{0}_{1}".format(wl_name,row),
layer="metal1", layer="metal1",
offset=wl_pin.ll(), offset=wl_pin.ll().scale(0,1),
width=self.width, width=self.width,
height=wl_pin.height()) height=wl_pin.height())
# For every second row and column, add a via for gnd and vdd # For every second row and column, add a via for gnd and vdd
for row in range(self.row_size): for row in range(self.total_size):
inst = self.cell_inst[row] inst = self.cell_inst[row]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name) self.copy_layout_pin(inst, pin_name)
def list_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, """ Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """ indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
pin_names = self.cell.list_all_bitline_names() pin_names = self.cell.get_all_bitline_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col)) bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.list_all_wl_names() pin_names = self.cell.get_all_wl_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row)) bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
@ -139,3 +153,9 @@ class replica_column(design.design):
return bitcell_pins return bitcell_pins
def exclude_all_but_replica(self):
"""Excludes all bits except the replica cell (self.replica_bit)."""
for row, cell in self.cell_inst.items():
if row != self.replica_bit:
self.graph_inst_exclude.add(cell)

View File

@ -55,12 +55,12 @@ class sense_amp_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(0,self.word_size): for i in range(0,self.word_size):
self.add_pin("data_{0}".format(i)) self.add_pin("data_{0}".format(i), "OUTPUT")
self.add_pin("bl_{0}".format(i)) self.add_pin("bl_{0}".format(i), "INPUT")
self.add_pin("br_{0}".format(i)) self.add_pin("br_{0}".format(i), "INPUT")
self.add_pin("en") self.add_pin("en", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.amp = factory.create(module_type="sense_amp") self.amp = factory.create(module_type="sense_amp")

View File

@ -50,13 +50,13 @@ class wordline_driver(design.design):
def add_pins(self): def add_pins(self):
# inputs to wordline_driver. # inputs to wordline_driver.
for i in range(self.rows): for i in range(self.rows):
self.add_pin("in_{0}".format(i)) self.add_pin("in_{0}".format(i), "INPUT")
# Outputs from wordline_driver. # Outputs from wordline_driver.
for i in range(self.rows): for i in range(self.rows):
self.add_pin("wl_{0}".format(i)) self.add_pin("wl_{0}".format(i), "OUTPUT")
self.add_pin("en_bar") self.add_pin("en", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
@ -109,7 +109,7 @@ class wordline_driver(design.design):
# add nand 2 # add nand 2
self.nand_inst.append(self.add_inst(name=name_nand, self.nand_inst.append(self.add_inst(name=name_nand,
mod=self.nand2)) mod=self.nand2))
self.connect_inst(["en_bar", self.connect_inst(["en",
"in_{0}".format(row), "in_{0}".format(row),
"wl_bar_{0}".format(row), "wl_bar_{0}".format(row),
"vdd", "gnd"]) "vdd", "gnd"])
@ -151,7 +151,7 @@ class wordline_driver(design.design):
""" Route all of the signals """ """ Route all of the signals """
# Wordline enable connection # Wordline enable connection
en_pin=self.add_layout_pin(text="en_bar", en_pin=self.add_layout_pin(text="en",
layer="metal2", layer="metal2",
offset=[self.m1_width + 2*self.m1_space,0], offset=[self.m1_width + 2*self.m1_space,0],
width=self.m2_width, width=self.m2_width,
@ -162,7 +162,7 @@ class wordline_driver(design.design):
nand_inst = self.nand_inst[row] nand_inst = self.nand_inst[row]
inv2_inst = self.inv2_inst[row] inv2_inst = self.inv2_inst[row]
# en_bar connection # en connection
a_pin = nand_inst.get_pin("A") a_pin = nand_inst.get_pin("A")
a_pos = a_pin.lc() a_pos = a_pin.lc()
clk_offset = vector(en_pin.bc().x,a_pos.y) clk_offset = vector(en_pin.bc().x,a_pos.y)

View File

@ -59,17 +59,17 @@ class write_driver_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("data_{0}".format(i)) self.add_pin("data_{0}".format(i), "INPUT")
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("bl_{0}".format(i)) self.add_pin("bl_{0}".format(i), "OUTPUT")
self.add_pin("br_{0}".format(i)) self.add_pin("br_{0}".format(i), "OUTPUT")
if self.write_size != None: if self.write_size != None:
for i in range(self.num_wmasks): for i in range(self.num_wmasks):
self.add_pin("en_{}".format(i)) self.add_pin("en_{}".format(i), "INPUT")
else: else:
self.add_pin("en") self.add_pin("en", "INPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.driver = factory.create(module_type="write_driver") self.driver = factory.create(module_type="write_driver")

View File

@ -47,12 +47,12 @@ class options(optparse.Values):
################### ###################
# Optimization options # Optimization options
################### ###################
rbl_delay_percentage = .5 #Approximate percentage of delay compared to bitlines rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines
# Allow manual adjustment of the delay chain over automatic # Allow manual adjustment of the delay chain over automatic
use_tech_delay_chain_size = False use_tech_delay_chain_size = False
delay_chain_stages = 4 delay_chain_stages = 9
delay_chain_fanout_per_stage = 3 delay_chain_fanout_per_stage = 4
@ -84,7 +84,7 @@ class options(optparse.Values):
# This determines whether LVS and DRC is checked for every submodule. # This determines whether LVS and DRC is checked for every submodule.
inline_lvsdrc = False inline_lvsdrc = False
# Remove noncritical memory cells for characterization speed-up # Remove noncritical memory cells for characterization speed-up
trim_netlist = True trim_netlist = False
# Run with extracted parasitics # Run with extracted parasitics
use_pex = False use_pex = False
@ -131,6 +131,7 @@ class options(optparse.Values):
delay_chain = "delay_chain" delay_chain = "delay_chain"
dff_array = "dff_array" dff_array = "dff_array"
dff = "dff" dff = "dff"
dummy_bitcell = "dummy_bitcell"
precharge_array = "precharge_array" precharge_array = "precharge_array"
ptx = "ptx" ptx = "ptx"
replica_bitcell = "replica_bitcell" replica_bitcell = "replica_bitcell"

View File

@ -47,11 +47,11 @@ class pand2(pgate.pgate):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A", "INPUT")
self.add_pin("B") self.add_pin("B", "INPUT")
self.add_pin("Z") self.add_pin("Z", "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_insts(self): def create_insts(self):
self.nand_inst=self.add_inst(name="pand2_nand", self.nand_inst=self.add_inst(name="pand2_nand",

View File

@ -42,10 +42,10 @@ class pbuf(pgate.pgate):
self.add_layout_pins() self.add_layout_pins()
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A", "INPUT")
self.add_pin("Z") self.add_pin("Z", "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def create_modules(self): def create_modules(self):
# Shield the cap, but have at least a stage effort of 4 # Shield the cap, but have at least a stage effort of 4

View File

@ -53,15 +53,15 @@ class pdriver(pgate.pgate):
elif not self.neg_polarity and (self.num_stages%2): elif not self.neg_polarity and (self.num_stages%2):
self.num_stages += 1 self.num_stages += 1
self.size_list = [] self.size_list = []
# compute sizes backwards from the fanout # compute sizes backwards from the fanout
fanout_prev = self.fanout fanout_prev = self.fanout
for x in range(self.num_stages): for x in range(self.num_stages):
fanout_prev = max(round(fanout_prev/self.stage_effort),1) fanout_prev = max(round(fanout_prev/self.stage_effort),1)
self.size_list.append(fanout_prev) self.size_list.append(fanout_prev)
# reverse the sizes to be from input to output # reverse the sizes to be from input to output
self.size_list.reverse() self.size_list.reverse()
def create_netlist(self): def create_netlist(self):
@ -81,10 +81,10 @@ class pdriver(pgate.pgate):
def add_pins(self): def add_pins(self):
self.add_pin("A") self.add_pin("A", "INPUT")
self.add_pin("Z") self.add_pin("Z", "OUTPUT")
self.add_pin("vdd") self.add_pin("vdd", "POWER")
self.add_pin("gnd") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.inv_list = [] self.inv_list = []
@ -178,7 +178,7 @@ class pdriver(pgate.pgate):
return self.inv_list[0].input_load() return self.inv_list[0].input_load()
def analytical_delay(self, corner, slew, load=0.0): def analytical_delay(self, corner, slew, load=0.0):
"""Calculate the analytical delay of INV1 -> ... -> INVn""" """ Calculate the analytical delay of INV1 -> ... -> INVn """
cout_list = [] cout_list = []
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
@ -198,9 +198,12 @@ class pdriver(pgate.pgate):
return delay return delay
def get_sizes(self):
""" Return the relative sizes of the buffers """
return self.size_list
def get_stage_efforts(self, external_cout, inp_is_rise=False): def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A -> Z path""" """ Get the stage efforts of the A -> Z path """
cout_list = [] cout_list = []
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
cout_list.append(inv.get_cin()) cout_list.append(inv.get_cin())
@ -217,5 +220,5 @@ class pdriver(pgate.pgate):
return stage_effort_list return stage_effort_list
def get_cin(self): def get_cin(self):
"""Returns the relative capacitance of the input""" """ Returns the relative capacitance of the input """
return self.inv_list[0].get_cin() return self.inv_list[0].get_cin()

View File

@ -60,7 +60,7 @@ class pinv(pgate.pgate):
def add_pins(self): def add_pins(self):
""" Adds pins for spice netlist """ """ Adds pins for spice netlist """
pin_list = ["A", "Z", "vdd", "gnd"] pin_list = ["A", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'OUTPUT', 'POWER', 'GROUND'] dir_list = ["INPUT", "OUTPUT", "POWER", "GROUND"]
self.add_pin_list(pin_list, dir_list) self.add_pin_list(pin_list, dir_list)
@ -300,4 +300,4 @@ class pinv(pgate.pgate):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -61,7 +61,7 @@ class pnand2(pgate.pgate):
def add_pins(self): def add_pins(self):
""" Adds pins for spice netlist """ """ Adds pins for spice netlist """
pin_list = ["A", "B", "Z", "vdd", "gnd"] pin_list = ["A", "B", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'OUTPUT', 'POWER', 'GROUND'] dir_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
self.add_pin_list(pin_list, dir_list) self.add_pin_list(pin_list, dir_list)
@ -281,4 +281,4 @@ class pnand2(pgate.pgate):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -44,7 +44,7 @@ class pnand3(pgate.pgate):
def add_pins(self): def add_pins(self):
""" Adds pins for spice netlist """ """ Adds pins for spice netlist """
pin_list = ["A", "B", "C", "Z", "vdd", "gnd"] pin_list = ["A", "B", "C", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'INPUT', 'OUTPUT', 'POWER', 'GROUND'] dir_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
self.add_pin_list(pin_list, dir_list) self.add_pin_list(pin_list, dir_list)
def create_netlist(self): def create_netlist(self):
@ -283,4 +283,4 @@ class pnand3(pgate.pgate):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -41,7 +41,7 @@ class pnor2(pgate.pgate):
def add_pins(self): def add_pins(self):
""" Adds pins for spice netlist """ """ Adds pins for spice netlist """
pin_list = ["A", "B", "Z", "vdd", "gnd"] pin_list = ["A", "B", "Z", "vdd", "gnd"]
dir_list = ['INPUT', 'INPUT', 'OUTPUT', 'INOUT', 'INOUT'] dir_list = ["INPUT", "INPUT", "OUTPUT", "INOUT", "INOUT"]
self.add_pin_list(pin_list, dir_list) self.add_pin_list(pin_list, dir_list)
def create_netlist(self): def create_netlist(self):
@ -242,4 +242,4 @@ class pnor2(pgate.pgate):
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -53,7 +53,7 @@ class precharge(design.design):
self.connect_to_bitlines() self.connect_to_bitlines()
def add_pins(self): def add_pins(self):
self.add_pin_list(["bl", "br", "en_bar", "vdd"]) self.add_pin_list(["bl", "br", "en_bar", "vdd"], ["OUTPUT", "OUTPUT", "INPUT", "POWER"])
def add_ptx(self): def add_ptx(self):
""" """

View File

@ -99,13 +99,13 @@ class sram_1bank(sram_base):
# This includes 2 M2 pitches for the row addr clock line. # This includes 2 M2 pitches for the row addr clock line.
control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch, control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - self.bank.m2_gap) self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - 2*self.bank.m2_gap )
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.
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 aove the control logic but below the top of the bitcell array # 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) y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset) 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])
@ -166,16 +166,35 @@ class sram_1bank(sram_base):
# This includes 2 M2 pitches for the row addr clock line # This includes 2 M2 pitches for the row addr clock line
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch, control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ur.y + self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap) self.bank.bank_array_ur.y + self.control_logic_insts[port].height -
(self.control_logic_insts[port].height - self.control_logic_insts[port].mod.control_logic_center.y)
+ 2*self.bank.m2_gap)
#import pdb; pdb.set_trace()
self.control_logic_insts[port].place(control_pos[port], mirror="XY") self.control_logic_insts[port].place(control_pos[port], mirror="XY")
# 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 = 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
# It is above the control logic but below the top of the bitcell array # It is below the control logic but below the bottom of the bitcell array
y_offset = min(self.control_logic_insts[port].by(), self.bank.bank_array_ll.y - self.row_addr_dff_insts[port].height) y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset) row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY") self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
# Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.dff.height)
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
# Add the write mask flops to the left of the din flops.
if self.write_size is not None:
if port in self.write_ports:
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.data_dff_insts[port].height)
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
def add_layout_pins(self): def add_layout_pins(self):
@ -271,7 +290,8 @@ class sram_1bank(sram_base):
def route_control_logic(self): def route_control_logic(self):
""" Route the outputs from the control logic module """ """ Route the control logic pins that are not inputs """
for port in self.all_ports: for port in self.all_ports:
for signal in self.control_logic_outputs[port]: for signal in self.control_logic_outputs[port]:
# The clock gets routed separately and is not a part of the bank # The clock gets routed separately and is not a part of the bank
@ -279,10 +299,14 @@ class sram_1bank(sram_base):
continue continue
src_pin = self.control_logic_insts[port].get_pin(signal) src_pin = self.control_logic_insts[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.connect_vbus_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc()) for port in self.read_ports:
# Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
dest_pin = self.bank_inst.get_pin("rbl_bl{}".format(port))
self.connect_vbus_m2m3(src_pin, dest_pin)
def route_row_addr_dff(self): def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
@ -401,4 +425,4 @@ class sram_1bank(sram_base):
#Sanity check in case it was forgotten #Sanity check in case it was forgotten
if inst_name.find('x') != 0: if inst_name.find('x') != 0:
inst_name = 'x'+inst_name inst_name = 'x'+inst_name
return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col) return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col)

View File

@ -120,7 +120,7 @@ class sram_base(design, verilog, lef):
self.add_lvs_correspondence_points() self.add_lvs_correspondence_points()
self.offset_all_coordinates() #self.offset_all_coordinates()
highest_coord = self.find_highest_coords() highest_coord = self.find_highest_coords()
self.width = highest_coord[0] self.width = highest_coord[0]
@ -197,7 +197,7 @@ class sram_base(design, verilog, lef):
if self.port_id[port] == "r": if self.port_id[port] == "r":
self.control_bus_names[port].extend([sen, pen]) self.control_bus_names[port].extend([sen, pen])
elif self.port_id[port] == "w": elif self.port_id[port] == "w":
self.control_bus_names[port].extend([wen]) self.control_bus_names[port].extend([wen, pen])
else: else:
self.control_bus_names[port].extend([sen, wen, pen]) self.control_bus_names[port].extend([sen, wen, pen])
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2", self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
@ -301,9 +301,6 @@ class sram_base(design, verilog, lef):
self.bank_count = 0 self.bank_count = 0
self.supply_rail_width = self.bank.supply_rail_width
self.supply_rail_pitch = self.bank.supply_rail_pitch
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic. #The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
self.all_mods_except_control_done = True self.all_mods_except_control_done = True
@ -342,6 +339,10 @@ class sram_base(design, verilog, lef):
for port in self.read_ports: for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("DOUT{0}[{1}]".format(port,bit)) temp.append("DOUT{0}[{1}]".format(port,bit))
for port in self.read_ports:
temp.append("rbl_bl{0}".format(port))
for port in self.read_ports:
temp.append("rbl_wl{0}".format(port))
for port in self.write_ports: for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("BANK_DIN{0}[{1}]".format(port,bit)) temp.append("BANK_DIN{0}[{1}]".format(port,bit))
@ -353,7 +354,7 @@ class sram_base(design, verilog, lef):
temp.append("bank_sel{0}[{1}]".format(port,bank_num)) temp.append("bank_sel{0}[{1}]".format(port,bank_num))
for port in self.read_ports: for port in self.read_ports:
temp.append("s_en{0}".format(port)) temp.append("s_en{0}".format(port))
for port in self.read_ports: for port in self.all_ports:
temp.append("p_en_bar{0}".format(port)) temp.append("p_en_bar{0}".format(port))
for port in self.write_ports: for port in self.write_ports:
temp.append("w_en{0}".format(port)) temp.append("w_en{0}".format(port))
@ -501,41 +502,46 @@ class sram_base(design, verilog, lef):
temp.append("web{}".format(port)) temp.append("web{}".format(port))
temp.append("clk{}".format(port)) temp.append("clk{}".format(port))
# for port in self.all_ports: if port in self.read_ports:
# self.add_pin("csb{}".format(port), "INPUT") temp.append("rbl_bl{}".format(port))
# for port in self.readwrite_ports:
# self.add_pin("web{}".format(port), "INPUT") # Ouputs
# for port in self.all_ports: if port in self.read_ports:
# self.add_pin("clk{}".format(port), "INPUT") temp.append("rbl_wl{}".format(port))
# Outputs
if port in self.read_ports: if port in self.read_ports:
temp.append("s_en{}".format(port)) temp.append("s_en{}".format(port))
if port in self.write_ports: if port in self.write_ports:
temp.append("w_en{}".format(port)) temp.append("w_en{}".format(port))
if port in self.read_ports: temp.append("p_en_bar{}".format(port))
temp.append("p_en_bar{}".format(port))
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"]) temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
return insts return insts
def connect_rail_from_left_m2m3(self, src_pin, dest_pin): def connect_vbus_m2m3(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """ """ Helper routine to connect an instance to a vertical bus.
in_pos = src_pin.rc() Routes horizontal then vertical L shape.
Dest pin is assumed to be on M2.
Src pin can be on M1/M2/M3."""
if src_pin.cx()<dest_pin.cx():
in_pos = src_pin.rc()
else:
in_pos = src_pin.lc()
out_pos = dest_pin.center() out_pos = dest_pin.center()
# move horizontal first
self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos]) self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos])
self.add_via_center(layers=("metal2","via2","metal3"), if src_pin.layer=="metal1":
offset=src_pin.rc()) self.add_via_center(layers=("metal1","via1","metal2"),
offset=in_pos)
if src_pin.layer in ["metal1","metal2"]:
def connect_rail_from_left_m2m1(self, src_pin, dest_pin): self.add_via_center(layers=("metal2","via2","metal3"),
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """ offset=in_pos)
in_pos = src_pin.rc()
out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
def sp_write(self, sp_name): def sp_write(self, sp_name):
# Write the entire spice of the object to the file # Write the entire spice of the object to the file

View File

@ -61,7 +61,6 @@ class sram_config:
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
debug.info(1,"Words per row: {}".format(self.words_per_row))
self.recompute_sizes() self.recompute_sizes()
def recompute_sizes(self): def recompute_sizes(self):
@ -71,6 +70,8 @@ class sram_config:
SRAM for testing. SRAM for testing.
""" """
debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row))
# If the banks changed # If the banks changed
self.num_words_per_bank = self.num_words/self.num_banks self.num_words_per_bank = self.num_words/self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank self.num_bits_per_bank = self.word_size*self.num_words_per_bank
@ -78,12 +79,16 @@ class sram_config:
# Fix the number of columns and rows # Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size) self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words_per_bank/self.words_per_row) self.num_rows = int(self.num_words_per_bank/self.words_per_row)
debug.info(1,"Rows: {} Cols: {}".format(self.num_rows,self.num_cols))
# Compute the address and bank sizes # Compute the address and bank sizes
self.row_addr_size = int(log(self.num_rows, 2)) self.row_addr_size = int(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2)) self.col_addr_size = int(log(self.words_per_row, 2))
self.bank_addr_size = self.col_addr_size + self.row_addr_size self.bank_addr_size = self.col_addr_size + self.row_addr_size
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
debug.info(1,"Row addr size: {}".format(self.row_addr_size)
+ " Col addr size: {}".format(self.col_addr_size)
+ " Bank addr size: {}".format(self.bank_addr_size))
def estimate_words_per_row(self,tentative_num_cols, word_size): def estimate_words_per_row(self,tentative_num_cols, word_size):

View File

@ -15,25 +15,31 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class replica_bitline_test(openram_test): class replica_pbitcell_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
import dummy_pbitcell
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
# check replica bitline in single port factory.reset()
stages=4 debug.info(2, "Checking dummy bitcell using pbitcell (small cell)")
fanout=4 tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
rows=13 self.local_check(tx)
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = factory.create(module_type="replica_bitline", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a)
stages=8
rows=100
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = factory.create(module_type="replica_bitline", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
factory.reset()
debug.info(2, "Checking dummy bitcell using pbitcell (large cell)")
tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
self.local_check(tx)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -20,13 +20,17 @@ import debug
class bitcell_1rw_1r_array_test(openram_test): class bitcell_1rw_1r_array_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for cell_1rw_1r") globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="bitcell_array", cols=4, rows=4) a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a) self.local_check(a)

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class replica_bitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
debug.info(2, "Testing 4x4 array for pbitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1])
self.local_check(a)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 4x4 array for pbitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
self.local_check(a)
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(testRunner=debugTestRunner())

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class replica_bitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=2, right_rbl=0, bitcell_ports=[0,1])
self.local_check(a)
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1])
self.local_check(a)
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(testRunner=debugTestRunner())

View File

@ -19,7 +19,7 @@ class replica_bitcell_array_test(openram_test):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for 6t_cell") debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4) a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -1,66 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class replica_bitline_multiport_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
stages=4
fanout=4
rows=13
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows))
a = factory.create(module_type="replica_bitline", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a)
# check replica bitline in pbitcell multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
factory.reset()
debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows))
a = factory.create(module_type="replica_bitline", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a)
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
factory.reset()
debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows))
a = factory.create(module_type="replica_bitline", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
self.local_check(a)
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(testRunner=debugTestRunner())

View File

@ -19,9 +19,17 @@ class replica_column_test(openram_test):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing replica column for 6t_cell") debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4) a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
self.local_check(a) self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
self.local_check(a)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -22,10 +22,17 @@ class control_logic_test(openram_test):
import control_logic import control_logic
import tech import tech
# check control logic for single port debug.info(1, "Testing sample for control_logic_rw")
debug.info(1, "Testing sample for control_logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32) a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for control_logic_r")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32, port_type="r")
self.local_check(a)
debug.info(1, "Testing sample for control_logic_w")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32, port_type="w")
self.local_check(a)
# run the test from the command line # run the test from the command line
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -55,9 +55,9 @@ class port_data_test(openram_test):
self.local_check(a) self.local_check(a)
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 1
c.num_words=16 c.num_words=16
c.words_per_row=1 c.words_per_row=1

View File

@ -20,14 +20,16 @@ class psingle_bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from bank import bank
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell"
# testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent) OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)
@ -35,8 +37,7 @@ class psingle_bank_test(openram_test):
factory.reset() factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "No column mux") debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) a = factory.create(module_type="bank", sram_config=c)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
c.num_words=32 c.num_words=32
@ -44,8 +45,7 @@ class psingle_bank_test(openram_test):
factory.reset() factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) a = factory.create(module_type="bank", sram_config=c)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
c.num_words=64 c.num_words=64
@ -53,8 +53,7 @@ class psingle_bank_test(openram_test):
factory.reset() factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) a = factory.create(module_type="bank", sram_config=c)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
c.word_size=2 c.word_size=2
@ -63,93 +62,9 @@ class psingle_bank_test(openram_test):
factory.reset() factory.reset()
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) a = factory.create(module_type="bank", sram_config=c)
a = bank(c, name=name)
self.local_check(a) self.local_check(a)
# testing bank using pbitcell in various port combinations
# layout for multiple ports does not work yet
"""
OPTS.netlist_only = True
c.num_words=16
c.words_per_row=1
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 0
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 0
OPTS.num_r_ports = c.num_r_ports = 2
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 0
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 0
OPTS.num_r_ports = c.num_r_ports = 0
debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
# testing with various column muxes
OPTS.num_rw_ports = c.num_rw_ports = 2
OPTS.num_w_ports = c.num_w_ports = 2
OPTS.num_r_ports = c.num_r_ports = 2
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux")
name = "bank2_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux")
name = "bank3_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux")
name = "bank4_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
a = bank(c, name=name)
self.local_check(a)
"""
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -19,13 +19,15 @@ class single_bank_1rw_1r_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)

View File

@ -19,13 +19,16 @@ class single_bank_1w_1r_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"
OPTS.num_rw_ports = 1 OPTS.replica_bitcell = "replica_bitcell_1w_1r"
OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 1
from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)

View File

@ -21,9 +21,10 @@ class psram_1bank_2mux_1rw_1w_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0

View File

@ -21,9 +21,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1

View File

@ -23,6 +23,7 @@ class psram_1bank_2mux_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent) # testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1

View File

@ -20,9 +20,10 @@ class psram_1bank_4mux_1rw_1r_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1

View File

@ -23,6 +23,7 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0

View File

@ -21,9 +21,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell="replica_bitcell_1w_1r" OPTS.replica_bitcell="replica_bitcell_1w_1r"
OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1

View File

@ -23,6 +23,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0

View File

@ -23,6 +23,7 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell = "dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0

View File

@ -61,28 +61,27 @@ class timing_sram_test(openram_test):
data.update(port_data[0]) data.update(port_data[0])
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl': [0.2121267], golden_data = {'delay_hl': [0.2181231],
'delay_lh': [0.2121267], 'delay_lh': [0.2181231],
'leakage_power': 0.0023761999999999998, 'leakage_power': 0.0025453999999999997,
'min_period': 0.43, 'min_period': 0.781,
'read0_power': [0.5139368], 'read0_power': [0.34664159999999994],
'read1_power': [0.48940979999999995], 'read1_power': [0.32656349999999995],
'slew_hl': [0.0516745], 'slew_hl': [0.21136519999999998],
'slew_lh': [0.0516745], 'slew_lh': [0.21136519999999998],
'write0_power': [0.46267169999999996], 'write0_power': [0.37980179999999997],
'write1_power': [0.4670826]} 'write1_power': [0.3532026]}
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.288], golden_data = {'delay_hl': [1.4082],
'delay_lh': [1.288], 'delay_lh': [1.4082],
'leakage_power': 0.0273896, 'leakage_power': 0.0267388,
'min_period': 2.578, 'min_period': 4.688,
'read0_power': [16.9996], 'read0_power': [11.5255],
'read1_power': [16.2616], 'read1_power': [10.9406],
'slew_hl': [0.47891700000000004], 'slew_hl': [1.2979],
'slew_lh': [0.47891700000000004], 'slew_lh': [1.2979],
'write0_power': [16.0656], 'write0_power': [12.9458],
'write1_power': [16.2616]} 'write1_power': [11.7444]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results # Check if no too many or too few results

View File

@ -15,8 +15,10 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class model_delay_sram_test(openram_test): @unittest.skip("SKIPPING 21_model_delay_test")
class model_delay_test(openram_test):
""" Compare the accuracy of the analytical model with a spice simulation. """
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False OPTS.analytical_delay = False
@ -61,9 +63,9 @@ class model_delay_sram_test(openram_test):
debug.info(1,"Spice Delays={}".format(spice_delays)) debug.info(1,"Spice Delays={}".format(spice_delays))
debug.info(1,"Model Delays={}".format(model_delays)) debug.info(1,"Model Delays={}".format(model_delays))
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
error_tolerance = .25 error_tolerance = 0.25
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
error_tolerance = .25 error_tolerance = 0.25
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results # Check if no too many or too few results

View File

@ -54,28 +54,27 @@ class timing_sram_test(openram_test):
data.update(port_data[0]) data.update(port_data[0])
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
golden_data = {'delay_hl': [0.2108836], golden_data = {'delay_hl': [0.22609590000000002],
'delay_lh': [0.2108836], 'delay_lh': [0.22609590000000002],
'leakage_power': 0.001564799, 'leakage_power': 0.003317743,
'min_period': 0.508, 'min_period': 0.859,
'read0_power': [0.43916689999999997], 'read0_power': [0.3271056],
'read1_power': [0.4198608], 'read1_power': [0.3064244],
'slew_hl': [0.0455126], 'slew_hl': [0.2153979],
'slew_lh': [0.0455126], 'slew_lh': [0.2153979],
'write0_power': [0.40681890000000004], 'write0_power': [0.3532067],
'write1_power': [0.4198608]} 'write1_power': [0.3381259]}
elif OPTS.tech_name == "scn4m_subm": elif OPTS.tech_name == "scn4m_subm":
golden_data = {'delay_hl': [1.5747600000000002], golden_data = {'delay_hl': [1.709791],
'delay_lh': [1.5747600000000002], 'delay_lh': [1.709791],
'leakage_power': 0.00195795, 'leakage_power': 0.06803324999999999,
'min_period': 3.281, 'min_period': 7.812,
'read0_power': [14.92874], 'read0_power': [7.9499070000000005],
'read1_power': [14.369810000000001], 'read1_power': [7.619662999999999],
'slew_hl': [0.49631959999999997], 'slew_hl': [1.390261],
'slew_lh': [0.49631959999999997], 'slew_lh': [1.390261],
'write0_power': [13.79953], 'write0_power': [8.913003],
'write1_power': [14.369810000000001]} 'write1_power': [8.166687000000001]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail

View File

@ -15,18 +15,20 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
#@unittest.skip("SKIPPING 22_psram_1bank_2mux_1rw_1r_1w_func_test, third port reads are broken?") class psram_1bank_2mux_func_test(openram_test):
class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
@ -35,28 +37,25 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
reload(characterizer) reload(characterizer)
from characterizer import functional, delay from characterizer import functional, delay
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=2,
num_words=64, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
OPTS.num_r_ports, "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_w_ports, OPTS.num_r_ports,
c.word_size, OPTS.num_w_ports,
c.num_words, c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -23,10 +23,13 @@ class psram_1bank_4mux_func_test(openram_test):
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
@ -35,28 +38,25 @@ class psram_1bank_4mux_func_test(openram_test):
reload(characterizer) reload(characterizer)
from characterizer import functional, delay from characterizer import functional, delay
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=2,
num_words=256, num_words=256,
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
OPTS.num_r_ports, "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_w_ports, OPTS.num_r_ports,
c.word_size, OPTS.num_w_ports,
c.num_words, c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -23,10 +23,13 @@ class psram_1bank_8mux_func_test(openram_test):
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
@ -40,23 +43,20 @@ class psram_1bank_8mux_func_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
OPTS.num_r_ports, "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_w_ports, OPTS.num_r_ports,
c.word_size, OPTS.num_w_ports,
c.num_words, c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -23,10 +23,13 @@ class psram_1bank_nomux_func_test(openram_test):
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
@ -35,28 +38,25 @@ class psram_1bank_nomux_func_test(openram_test):
reload(characterizer) reload(characterizer)
from characterizer import functional, delay from characterizer import functional, delay
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=2,
num_words=32, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
OPTS.num_r_ports, "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_w_ports, OPTS.num_r_ports,
c.word_size, OPTS.num_w_ports,
c.num_words, c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

7
compiler/tests/22_psram_wmask_func_test.py Normal file → Executable file
View File

@ -27,6 +27,7 @@ class psram_wmask_func_test(openram_test):
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell = "replica_bitcell_1w_1r" OPTS.replica_bitcell = "replica_bitcell_1w_1r"
OPTS.dummy_bitcell = "dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
@ -52,13 +53,11 @@ class psram_wmask_func_test(openram_test):
c.write_size, c.write_size,
c.num_banks)) c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)
@ -70,4 +69,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner()) unittest.main(testRunner=debugTestRunner())

View File

@ -31,25 +31,22 @@ class sram_1bank_2mux_func_test(openram_test):
from characterizer import functional, delay from characterizer import functional, delay
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=64, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with "
c.num_words, "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner) (fail, error) = f.run()
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run(feasible_period)
self.assertTrue(fail,error) self.assertTrue(fail,error)
globals.end_openram() globals.end_openram()

View File

@ -31,24 +31,21 @@ class sram_1bank_4mux_func_test(openram_test):
from characterizer import functional, delay from characterizer import functional, delay
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=256, num_words=128,
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with "
c.num_words, "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -34,24 +34,21 @@ class sram_1bank_8mux_func_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=256, num_words=128,
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with "
c.num_words, "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -30,22 +30,21 @@ class sram_1bank_nomux_func_test(openram_test):
from characterizer import functional from characterizer import functional
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with "
c.num_words, "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -25,6 +25,7 @@ class psram_1bank_nomux_func_test(openram_test):
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r" OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
@ -40,20 +41,17 @@ class psram_1bank_nomux_func_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram 1rw,1r with "
c.num_words, "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.num_banks)) c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
d = delay(s.s, tempspice, corner)
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail,error) self.assertTrue(fail,error)

View File

@ -36,19 +36,18 @@ class sram_wmask_func_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} bit writes, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with "
c.num_words, "{} bit words, {} words, {} words per row, {} bit writes, {} banks".format(c.word_size,
c.words_per_row, c.num_words,
c.write_size, c.words_per_row,
c.num_banks)) c.write_size,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice) s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner) f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -14,7 +14,8 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
class model_corners_lib_test(openram_test): @unittest.skip("SKIPPING 23_lib_sram_model_corners_test")
class lib_model_corners_lib_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))

View File

@ -14,7 +14,8 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
class lib_test(openram_test): @unittest.skip("SKIPPING 23_lib_sram_model_test")
class lib_sram_model_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))

View File

@ -14,7 +14,8 @@ import globals
from globals import OPTS from globals import OPTS
import debug import debug
class lib_test(openram_test): @unittest.skip("SKIPPING 23_lib_sram_prune_test")
class lib_sram_prune_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
import getpass import getpass
class openram_test(openram_test): class openram_back_end_test(openram_test):
def runTest(self): def runTest(self):
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))

View File

@ -16,7 +16,8 @@ from sram_factory import factory
import debug import debug
import getpass import getpass
class openram_test(openram_test): @unittest.skip("SKIPPING 30_openram_front_end_test")
class openram_front_end_test(openram_test):
def runTest(self): def runTest(self):
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))

View File

@ -16,5 +16,5 @@ temperatures = [25]
inline_lvsdrc = True inline_lvsdrc = True
route_supplies = True route_supplies = True
check_lvsdrc = True check_lvsdrc = True
analytical_delay = False

View File

@ -13,6 +13,6 @@ process_corners = ["TT"]
supply_voltages = [1.0] supply_voltages = [1.0]
temperatures = [25] temperatures = [25]
analytical_delay = False

View File

@ -16,6 +16,7 @@ temperatures = [25]
route_supplies = True route_supplies = True
check_lvsdrc = True check_lvsdrc = True
inline_lvsdrc = True inline_lvsdrc = True
analytical_delay = False
drc_name = "magic" drc_name = "magic"
lvs_name = "netgen" lvs_name = "netgen"

View File

@ -13,6 +13,8 @@ process_corners = ["TT"]
supply_voltages = [5.0] supply_voltages = [5.0]
temperatures = [25] temperatures = [25]
analytical_delay = False
drc_name = "magic" drc_name = "magic"
lvs_name = "netgen" lvs_name = "netgen"
pex_name = "magic" pex_name = "magic"

View File

@ -16,6 +16,7 @@ temperatures = [25]
route_supplies = True route_supplies = True
check_lvsdrc = True check_lvsdrc = True
inline_lvsdrc = True inline_lvsdrc = True
analytical_delay = False
drc_name = "magic" drc_name = "magic"
lvs_name = "netgen" lvs_name = "netgen"

View File

@ -60,6 +60,8 @@ class openram_test(unittest.TestCase):
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) #shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("LVS mismatch: {}".format(a.name)) self.fail("LVS mismatch: {}".format(a.name))
# For debug...
#import pdb; pdb.set_trace()
if OPTS.purge_temp: if OPTS.purge_temp:
self.cleanup() self.cleanup()

View File

@ -345,11 +345,11 @@ spice["msflop_leakage"] = 1 # Leakage power of flop in nW
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
spice["flop_transition_prob"] = .5 # Transition probability of inverter. spice["flop_transition_prob"] = 0.5 # Transition probability of inverter.
spice["inv_transition_prob"] = .5 # Transition probability of inverter. spice["inv_transition_prob"] = 0.5 # Transition probability of inverter.
spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand. spice["nand2_transition_prob"] = 0.1875 # Transition probability of 2-input nand.
spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand. spice["nand3_transition_prob"] = 0.1094 # Transition probability of 3-input nand.
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. spice["nor2_transition_prob"] = 0.1875 # Transition probability of 2-input nor.
#Parameters related to sense amp enable timing and delay chain/RBL sizing #Parameters related to sense amp enable timing and delay chain/RBL sizing
parameter['le_tau'] = 2.25 #In pico-seconds. parameter['le_tau'] = 2.25 #In pico-seconds.
@ -357,10 +357,10 @@ parameter['cap_relative_per_ff'] = 7.5 #Units of Relative Capacitance/ Femt
parameter["dff_clk_cin"] = 30.6 #relative capacitance parameter["dff_clk_cin"] = 30.6 #relative capacitance
parameter["6tcell_wl_cin"] = 3 #relative capacitance parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = 2.4 #Tau delay units parameter["min_inv_para_delay"] = 2.4 #Tau delay units
parameter["sa_en_pmos_size"] = .72 #micro-meters parameter["sa_en_pmos_size"] = 0.72 #micro-meters
parameter["sa_en_nmos_size"] = .27 #micro-meters parameter["sa_en_nmos_size"] = 0.27 #micro-meters
parameter["sa_inv_pmos_size"] = .54 #micro-meters parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
parameter["sa_inv_nmos_size"] = .27 #micro-meters parameter["sa_inv_nmos_size"] = 0.27 #micro-meters
parameter['bitcell_drain_cap'] = 0.1 #In Femto-Farad, approximation of drain capacitance parameter['bitcell_drain_cap'] = 0.1 #In Femto-Farad, approximation of drain capacitance
################################################### ###################################################

Some files were not shown because too many files have changed in this diff Show More