diff --git a/compiler/base/contact.py b/compiler/base/contact.py index de1afec6..be3af1ce 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -1,14 +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. +# 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 hierarchy_design import debug import utils -from tech import drc +from tech import drc,layer from vector import vector @@ -196,5 +196,8 @@ active = factory.create(module_type="contact", layer_stack=("active", "contact", poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"), directions=("V","H")) m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"), directions=("H","V")) m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"), directions=("V","H")) -m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V")) +if "metal4" in layer.keys(): + m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V")) +else: + m3m4 = None diff --git a/compiler/base/delay_data.py b/compiler/base/delay_data.py new file mode 100644 index 00000000..e3d5a8bc --- /dev/null +++ b/compiler/base/delay_data.py @@ -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) + + + + diff --git a/compiler/base/design.py b/compiler/base/design.py index 5a87dd79..da23aa9e 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -1,9 +1,9 @@ # 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. +# 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 hierarchy_design import hierarchy_design import contact @@ -26,13 +26,17 @@ class design(hierarchy_design): self.setup_drc_constants() self.setup_multiport_constants() + from tech import layer self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space) self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space) - self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space) + if "metal4" in layer: + self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space) + else: + self.m3_pitch = self.m2_pitch def setup_drc_constants(self): """ These are some DRC constants used in many places in the compiler.""" - from tech import drc + from tech import drc,layer self.well_width = drc("minwidth_well") self.poly_width = drc("minwidth_poly") self.poly_space = drc("poly_to_poly") @@ -42,8 +46,9 @@ class design(hierarchy_design): self.m2_space = drc("metal2_to_metal2") self.m3_width = drc("minwidth_metal3") self.m3_space = drc("metal3_to_metal3") - self.m4_width = drc("minwidth_metal4") - self.m4_space = drc("metal4_to_metal4") + if "metal4" in layer: + self.m4_width = drc("minwidth_metal4") + self.m4_space = drc("metal4_to_metal4") self.active_width = drc("minwidth_active") self.active_space = drc("active_to_body_active") self.contact_width = drc("minwidth_contact") @@ -93,8 +98,8 @@ class design(hierarchy_design): for port in range(OPTS.num_r_ports): self.read_ports.append(port_number) self.readonly_ports.append(port_number) - port_number += 1 - + port_number += 1 + def analytical_power(self, corner, load): """ Get total power of a module """ total_module_power = self.return_power() diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 144043a2..7063cf81 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This provides a set of useful generic types for the gdsMill interface. @@ -165,7 +165,7 @@ class instance(geometry): debug.info(4, "creating instance: " + self.name) def get_blockages(self, layer, top=False): - """ Retrieve rectangular blockages of all modules in this instance. + """ Retrieve blockages of all modules in this instance. Apply the transform of the instance placement to give absolute blockages.""" angle = math.radians(float(self.rotate)) mirr = 1 @@ -183,21 +183,20 @@ class instance(geometry): elif self.mirror=="XY": mirr = 1 angle += math.radians(180.0) - - if self.mod.is_library_cell: - # For lib cells, block the whole thing except on metal3 - # since they shouldn't use metal3 - if layer==tech.layer["metal1"] or layer==tech.layer["metal2"]: - return [self.transform_coords(self.mod.get_boundary(), self.offset, mirr, angle)] - else: - return [] - else: - blockages = self.mod.get_blockages(layer) - new_blockages = [] + new_blockages = [] + if self.mod.is_library_cell: + # Writes library cell blockages as shapes instead of a large metal blockage + blockages = [] + blockages = self.mod.gds.getBlockages(layer) for b in blockages: new_blockages.append(self.transform_coords(b,self.offset, mirr, angle)) - return new_blockages + else: + blockages = self.mod.get_blockages(layer) + for b in blockages: + new_blockages.append(self.transform_coords(b,self.offset, mirr, angle)) + return new_blockages + def gds_write_file(self, new_layout): """Recursively writes all the sub-modules in this instance""" diff --git a/compiler/base/graph_util.py b/compiler/base/graph_util.py new file mode 100644 index 00000000..5d1ee692 --- /dev/null +++ b/compiler/base/graph_util.py @@ -0,0 +1,130 @@ +import os, copy +from collections import defaultdict + +import gdsMill +import tech +import math +import globals +import debug +from vector import vector +from pin_layout import pin_layout + +class timing_graph(): + """ + Implements a directed graph + Nodes are currently just Strings. + """ + + def __init__(self): + self.graph = defaultdict(set) + self.all_paths = [] + self.edge_mods = {} + + def add_edge(self, src_node, dest_node, edge_mod): + """Adds edge to graph. Nodes added as well if they do not exist. + Module which defines the edge must be provided for timing information.""" + + src_node = src_node.lower() + dest_node = dest_node.lower() + self.graph[src_node].add(dest_node) + self.edge_mods[(src_node, dest_node)] = edge_mod + + def add_node(self, node): + """Add node to graph with no edges""" + + node = node.lower() + if not node in self.graph: + self.graph[node] = set() + + def remove_edges(self, node): + """Helper function to remove edges, useful for removing vdd/gnd""" + + node = node.lower() + self.graph[node] = set() + + def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True): + """Traverse all paths from source to destination""" + + src_node = src_node.lower() + dest_node = dest_node.lower() + + # Remove vdd and gnd by default + # Will require edits if separate supplies are implemented. + if remove_rail_nodes: + # Names are also assumed. + self.remove_edges('vdd') + self.remove_edges('gnd') + + # Mark all the vertices as not visited + visited = set() + + # Create an array to store paths + path = [] + self.all_paths = [] + + # Call the recursive helper function to print all paths + self.get_all_paths_util(src_node, dest_node, visited, path) + debug.info(2, "Paths found={}".format(len(self.all_paths))) + + if reduce_paths: + self.reduce_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): + """Recursive function to find all paths in a Depth First Search manner""" + + # Mark the current node as visited and store in path + visited.add(cur_node) + path.append(cur_node) + + # If current vertex is same as destination, then print + # current path[] + if cur_node == dest_node: + self.all_paths.append(copy.deepcopy(path)) + else: + # If current vertex is not destination + # Recur for all the vertices adjacent to this vertex + for node in self.graph[cur_node]: + if node not in visited: + self.get_all_paths_util(node, dest_node, visited, path) + + # Remove current vertex from path[] and mark it as unvisited + path.pop() + visited.remove(cur_node) + + def get_timing(self, path, corner, slew, load): + """Returns the analytical delays in the input path""" + + if len(path) == 0: + return [] + + delays = [] + cur_slew = slew + for i in range(len(path)-1): + + path_edge_mod = self.edge_mods[(path[i], path[i+1])] + + # On the output of the current stage, get COUT from all other mods connected + cout = 0 + for node in self.graph[path[i+1]]: + output_edge_mod = self.edge_mods[(path[i+1], node)] + cout+=output_edge_mod.get_cin() + # If at the last output, include the final output load + if i == len(path)-2: + cout+=load + + delays.append(path_edge_mod.analytical_delay(corner, slew, cout)) + cur_slew = delays[-1].slew + + return delays + + def __str__(self): + """ override print function output """ + + return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index dfc275ee..055bf412 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -1,9 +1,9 @@ # 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. +# 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 hierarchy_layout import hierarchy_spice @@ -12,6 +12,7 @@ import verify import debug import os from globals import OPTS +import graph_util total_drc_errors = 0 total_lvs_errors = 0 @@ -30,7 +31,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): self.name = name hierarchy_spice.spice.__init__(self, name) hierarchy_layout.layout.__init__(self, name) - + self.init_graph_params() def get_layout_pins(self,inst): """ Return a map of pin locations of the instance offset """ @@ -103,8 +104,123 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): total_lvs_errors += num_errors debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors)) os.remove(tempspice) - os.remove(tempgds) + os.remove(tempgds) + + def init_graph_params(self): + """Initializes parameters relevant to the graph creation""" + #Only initializes a set for checking instances which should not be added + self.graph_inst_exclude = set() + + def build_graph(self, graph, inst_name, port_nets): + """Recursively create graph from instances in module.""" + + #Translate port names to external nets + if len(port_nets) != len(self.pins): + debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1) + port_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + debug.info(3, "Instance name={}".format(inst_name)) + for subinst, conns in zip(self.insts, self.conns): + if subinst in self.graph_inst_exclude: + continue + subinst_name = inst_name+'.X'+subinst.name + subinst_ports = self.translate_nets(conns, port_dict, inst_name) + subinst.mod.build_graph(graph, subinst_name, subinst_ports) + + def build_names(self, name_dict, inst_name, port_nets): + """Collects all the nets and the parent inst of that net.""" + #Translate port names to external nets + if len(port_nets) != len(self.pins): + debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1) + port_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + debug.info(3, "Instance name={}".format(inst_name)) + for subinst, conns in zip(self.insts, self.conns): + subinst_name = inst_name+'.X'+subinst.name + subinst_ports = self.translate_nets(conns, port_dict, inst_name) + for si_port, conn in zip(subinst_ports, conns): + #Only add for first occurrence + if si_port.lower() not in name_dict: + mod_info = {'mod':self, 'int_net':conn} + name_dict[si_port.lower()] = mod_info + subinst.mod.build_names(name_dict, subinst_name, subinst_ports) + def find_aliases(self, inst_name, port_nets, path_nets, alias, alias_mod, exclusion_set=None): + """Given a list of nets, will compare the internal alias of a mod to determine + if the nets have a connection to this mod's net (but not inst). + """ + if exclusion_set == None: + exclusion_set = set() + try: + self.name_dict + except AttributeError: + self.name_dict = {} + self.build_names(self.name_dict, inst_name, port_nets) + aliases = [] + for net in path_nets: + net = net.lower() + int_net = self.name_dict[net]['int_net'] + int_mod = self.name_dict[net]['mod'] + if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set): + aliases.append(net) + return aliases + + def is_net_alias(self, known_net, net_alias, mod, exclusion_set): + """Checks if the alias_net in input mod is the same as the input net for this mod (self).""" + if self in exclusion_set: + return False + #Check ports of this mod + for pin in self.pins: + if self.is_net_alias_name_check(known_net, pin, net_alias, mod): + return True + #Check connections of all other subinsts + mod_set = set() + for subinst, inst_conns in zip(self.insts, self.conns): + for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins): + if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod): + return True + elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set: + if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set): + return True + mod_set.add(subinst.mod) + return False + + def is_net_alias_name_check(self, parent_net, child_net, alias_net, mod): + """Utility function for checking single net alias.""" + return self == mod and \ + child_net.lower() == alias_net.lower() and \ + parent_net.lower() == alias_net.lower() + + def get_mod_net(self, parent_net, child_inst, child_conns): + """Given an instance and net, returns the internal net in the mod + corresponding to input net.""" + for conn, pin in zip(child_conns, child_inst.mod.pins): + if parent_net.lower() == conn.lower(): + return pin + return None + + def translate_nets(self, subinst_ports, port_dict, inst_name): + """Converts connection names to their spice hierarchy equivalent""" + converted_conns = [] + for conn in subinst_ports: + if conn in port_dict: + converted_conns.append(port_dict[conn]) + else: + converted_conns.append("{}.{}".format(inst_name, conn)) + return converted_conns + + def add_graph_edges(self, graph, port_nets): + """For every input, adds an edge to every output. + Only intended to be used for gates and other simple modules.""" + #The final pin names will depend on the spice hierarchy, so + #they are passed as an input. + pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + input_pins = self.get_inputs() + output_pins = self.get_outputs() + inout_pins = self.get_inouts() + for inp in input_pins+inout_pins: + for out in output_pins+inout_pins: + if inp != out: #do not add self loops + graph.add_edge(pin_dict[inp], pin_dict[out], self) + def __str__(self): """ override print function output """ pins = ",".join(self.pins) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e8c1b0b9..26436963 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1,9 +1,9 @@ # 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. +# 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 itertools import geometry @@ -214,18 +214,35 @@ class layout(): return self.pin_map[text] else: return set() - + + def get_pin_names(self): + """ + Return a pin list of all pins + """ + return self.pin_map.keys() + def copy_layout_pin(self, instance, pin_name, new_name=""): """ Create a copied version of the layout pin at the current level. You can optionally rename the pin to a new name. """ pins=instance.get_pins(pin_name) + + debug.check(len(pins)>0,"Could not find pin {}".format(pin_name)) + for pin in pins: if new_name=="": new_name = pin.name self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height()) + def copy_layout_pins(self, instance, prefix=""): + """ + Create a copied version of the layout pin at the current level. + You can optionally rename the pin to a new name. + """ + for pin_name in self.pin_map.keys(): + self.copy_layout_pin(instance, pin_name, prefix+pin_name) + def add_layout_pin_segment_center(self, text, layer, start, end): """ Creates a path like pin with center-line convention @@ -663,81 +680,92 @@ class layout(): self.add_via_center(layers=layer_stack, offset=bus_pos, rotate=90) - + def get_layer_pitch(self, layer): + """ Return the track pitch on a given layer """ + if layer=="metal1": + return (self.m1_pitch,self.m1_pitch-self.m1_space,self.m1_space) + elif layer=="metal2": + return (self.m2_pitch,self.m2_pitch-self.m2_space,self.m2_space) + elif layer=="metal3": + return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space) + elif layer=="metal4": + from tech import layer as tech_layer + if "metal4" in tech_layer: + return (self.m3_pitch,self.m3_pitch-self.m4_space,self.m4_space) + else: + return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space) + else: + debug.error("Cannot find layer pitch.") + def add_horizontal_trunk_route(self, pins, trunk_offset, - layer_stack=("metal1", "via1", "metal2"), - pitch=None): + layer_stack, + pitch): """ Create a trunk route for all pins with the trunk located at the given y offset. """ - if not pitch: - pitch = self.m1_pitch - max_x = max([pin.center().x for pin in pins]) min_x = min([pin.center().x for pin in pins]) - - half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[0])] # if we are less than a pitch, just create a non-preferred layer jog - if max_x-min_x < pitch: + if max_x-min_x <= pitch: + + half_layer_width = 0.5*drc["minwidth_{0}".format(self.vertical_layer)] + # Add the horizontal trunk on the vertical layer! - self.add_path(layer_stack[2],[vector(min_x-half_minwidth,trunk_offset.y), vector(max_x+half_minwidth,trunk_offset.y)]) + self.add_path(self.vertical_layer,[vector(min_x-half_layer_width,trunk_offset.y), vector(max_x+half_layer_width,trunk_offset.y)]) # Route each pin to the trunk for pin in pins: # No bend needed here mid = vector(pin.center().x, trunk_offset.y) - self.add_path(layer_stack[2], [pin.center(), mid]) + self.add_path(self.vertical_layer, [pin.center(), mid]) else: # Add the horizontal trunk - self.add_path(layer_stack[0],[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)]) + self.add_path(self.horizontal_layer,[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)]) trunk_mid = vector(0.5*(max_x+min_x),trunk_offset.y) # Route each pin to the trunk for pin in pins: mid = vector(pin.center().x, trunk_offset.y) - self.add_path(layer_stack[2], [pin.center(), mid]) + self.add_path(self.vertical_layer, [pin.center(), mid]) self.add_via_center(layers=layer_stack, offset=mid) def add_vertical_trunk_route(self, pins, trunk_offset, - layer_stack=("metal1", "via1", "metal2"), - pitch=None): + layer_stack, + pitch): """ Create a trunk route for all pins with the trunk located at the given x offset. """ - if not pitch: - pitch = self.m2_pitch - max_y = max([pin.center().y for pin in pins]) min_y = min([pin.center().y for pin in pins]) - # Add the vertical trunk - half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[2])] - # if we are less than a pitch, just create a non-preferred layer jog - if max_y-min_y < pitch: - # Add the horizontal trunk on the vertical layer! - self.add_path(layer_stack[0],[vector(trunk_offset.x,min_y-half_minwidth), vector(trunk_offset.x,max_y+half_minwidth)]) + if max_y-min_y <= pitch: + + half_layer_width = 0.5*drc["minwidth_{0}".format(self.horizontal_layer)] + + # Add the vertical trunk on the horizontal layer! + self.add_path(self.horizontal_layer,[vector(trunk_offset.x,min_y-half_layer_width), vector(trunk_offset.x,max_y+half_layer_width)]) # Route each pin to the trunk for pin in pins: # No bend needed here mid = vector(trunk_offset.x, pin.center().y) - self.add_path(layer_stack[0], [pin.center(), mid]) + self.add_path(self.horizontal_layer, [pin.center(), mid]) else: # Add the vertical trunk - self.add_path(layer_stack[2],[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)]) + self.add_path(self.vertical_layer,[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)]) trunk_mid = vector(trunk_offset.x,0.5*(max_y+min_y),) # Route each pin to the trunk for pin in pins: mid = vector(trunk_offset.x, pin.center().y) - self.add_path(layer_stack[0], [pin.center(), mid]) + self.add_path(self.horizontal_layer, [pin.center(), mid]) self.add_via_center(layers=layer_stack, offset=mid) @@ -745,7 +773,6 @@ class layout(): def create_channel_route(self, netlist, offset, layer_stack=("metal1", "via1", "metal2"), - pitch=None, vertical=False): """ The net list is a list of the nets. Each net is a list of pins @@ -769,7 +796,7 @@ class layout(): g[other_pin]=conflicts return g - def vcg_nets_overlap(net1, net2, vertical): + def vcg_nets_overlap(net1, net2, vertical, pitch): """ Check all the pin pairs on two nets and return a pin overlap if any pin overlaps @@ -777,12 +804,12 @@ class layout(): for pin1 in net1: for pin2 in net2: - if vcg_pin_overlap(pin1, pin2, vertical): + if vcg_pin_overlap(pin1, pin2, vertical, pitch): return True return False - def vcg_pin_overlap(pin1, pin2, vertical): + def vcg_pin_overlap(pin1, pin2, vertical, pitch): """ Check for vertical or horizontal overlap of the two pins """ # FIXME: If the pins are not in a row, this may break. # However, a top pin shouldn't overlap another top pin, for example, so the @@ -796,10 +823,15 @@ class layout(): overlaps = (not vertical and x_overlap) or (vertical and y_overlap) return overlaps + if self.get_preferred_direction(layer_stack[0])=="V": + self.vertical_layer = layer_stack[0] + self.horizontal_layer = layer_stack[2] + else: + self.vertical_layer = layer_stack[2] + self.horizontal_layer = layer_stack[0] - - if not pitch: - pitch = self.m2_pitch + (self.vertical_pitch,self.vertical_width,self.vertical_space) = self.get_layer_pitch(self.vertical_layer) + (self.horizontal_pitch,self.horizontal_width,self.horizontal_space) = self.get_layer_pitch(self.horizontal_layer) # FIXME: Must extend this to a horizontal conflict graph too if we want to minimize the @@ -829,7 +861,9 @@ class layout(): # Skip yourself if net_name1 == net_name2: continue - if vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical): + if vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.vertical_pitch): + vcg[net_name2].append(net_name1) + elif not vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.horizontal_pitch): vcg[net_name2].append(net_name1) # list of routes to do @@ -857,28 +891,33 @@ class layout(): # Add the trunk routes from the bottom up for horizontal or the left to right for vertical if vertical: - self.add_vertical_trunk_route(pin_list, offset, layer_stack, pitch) - offset += vector(pitch,0) + self.add_vertical_trunk_route(pin_list, offset, layer_stack, self.vertical_pitch) + offset += vector(self.vertical_pitch,0) else: - self.add_horizontal_trunk_route(pin_list, offset, layer_stack, pitch) - offset += vector(0,pitch) + self.add_horizontal_trunk_route(pin_list, offset, layer_stack, self.horizontal_pitch) + offset += vector(0,self.horizontal_pitch) def create_vertical_channel_route(self, netlist, offset, - layer_stack=("metal1", "via1", "metal2"), - pitch=None): + layer_stack=("metal1", "via1", "metal2")): """ Wrapper to create a vertical channel route """ - self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=True) + self.create_channel_route(netlist, offset, layer_stack, vertical=True) def create_horizontal_channel_route(self, netlist, offset, - layer_stack=("metal1", "via1", "metal2"), - pitch=None): + layer_stack=("metal1", "via1", "metal2")): """ Wrapper to create a horizontal channel route """ - self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=False) + self.create_channel_route(netlist, offset, layer_stack, vertical=False) + + def add_boundary(self, offset=vector(0,0)): + """ Add boundary for debugging dimensions """ + self.add_rect(layer="boundary", + offset=offset, + height=self.height, + width=self.width) def add_enclosure(self, insts, layer="nwell"): """ Add a layer that surrounds the given instances. Useful diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index bfa4606c..5166ac6b 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -1,15 +1,19 @@ # 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. +# 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 re import os import math import tech +from delay_data import * +from wire_spice_model import * +from power_data import * +import logical_effort class spice(): """ @@ -24,6 +28,7 @@ class spice(): def __init__(self, name): self.name = name + self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"] # Holds subckts/mods for this module self.mods = [] # Holds the pins for this module @@ -48,34 +53,52 @@ class spice(): def add_comment(self, comment): """ Add a comment to the spice file """ + try: self.commments except: self.comments = [] - else: - self.comments.append(comment) + + self.comments.append(comment) def add_pin(self, name, pin_type="INOUT"): """ Adds a pin to the pins list. Default type is INOUT signal. """ self.pins.append(name) 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 """ # The type list can be a single type for all pins # 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: - self.add_pin(pin,pin_type_list) - elif len(pin_type_list)==len(pin_list): - for (pin,ptype) in zip(pin_list, pin_type_list): + debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type)) + self.add_pin(pin,pin_type) + + 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) else: debug.error("Mismatch in type and pin list lengths.", -1) + def add_pin_types(self, type_list): + """Add pin types for all the cell's pins. + Typically, should only be used for handmade cells.""" + #This only works if self.pins == bitcell.pin_names + if self.pin_names != self.pins: + debug.error("{} spice subcircuit port names do not match pin_names\ + \n SPICE names={}\ + \n Module names={}\ + ".format(self.name, self.pin_names, self.pins),1) + self.pin_type = {pin:type for pin,type in zip(self.pin_names, type_list)} + def get_pin_type(self, name): """ 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): """ Returns the direction of the pin. (Supply/ground are INOUT). """ @@ -103,17 +126,31 @@ class spice(): return output_list + def copy_pins(self, other_module, suffix=""): + """ This will copy all of the pins from the other module and add an optional suffix.""" + for pin in other_module.pins: + self.add_pin(pin+suffix, other_module.get_pin_type(pin)) + + def get_inouts(self): + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" + inout_list = [] + for pin in self.pins: + if self.pin_type[pin]=="INOUT": + inout_list.append(pin) + return inout_list + def add_mod(self, mod): """Adds a subckt/submodule to the subckt hierarchy""" self.mods.append(mod) + def connect_inst(self, args, check=True): """Connects the pins of the last instance added It is preferred to use the function with the check to find if there is a problem. The check option can be set to false where we dynamically generate groups of connections after a group of modules are generated.""" - if (check and (len(self.insts[-1].mod.pins) != len(args))): from pprint import pformat modpins_string=pformat(self.insts[-1].mod.pins) @@ -136,7 +173,13 @@ class spice(): debug.error("-----") debug.error("Connections: \n"+str(conns_string),1) - + def get_conns(self, inst): + """Returns the connections of a given instance.""" + for i in range(len(self.insts)): + if inst is self.insts[i]: + return self.conns[i] + #If not found, returns None + return None def sp_read(self): """Reads the sp file (and parse the pins) from the library @@ -157,6 +200,28 @@ class spice(): else: self.spice = [] + def check_net_in_spice(self, net_name): + """Checks if a net name exists in the current. Intended to be check nets in hand-made cells.""" + #Remove spaces and lower case then add spaces. Nets are separated by spaces. + net_formatted = ' '+net_name.lstrip().rstrip().lower()+' ' + for line in self.spice: + #Lowercase the line and remove any part of the line that is a comment. + line = line.lower().split('*')[0] + + #Skip .subckt or .ENDS lines + if line.find('.') == 0: + continue + if net_formatted in line: + return True + return False + + def do_nets_exist(self, nets): + """For handmade cell, checks sp file contains the storage nodes.""" + nets_match = True + for net in nets: + nets_match = nets_match and self.check_net_in_spice(net) + return nets_match + def contains(self, mod, modlist): for x in modlist: if x.name == mod.name: @@ -184,9 +249,12 @@ class spice(): sp.write("\n.SUBCKT {0} {1}\n".format(self.name, " ".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: sp.write("* {}\n".format(line)) - + # every instance must have a set of connections, even if it is empty. if len(self.insts)!=len(self.conns): debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, @@ -236,14 +304,48 @@ class spice(): def analytical_delay(self, corner, slew, load=0.0): """Inform users undefined delay module while building new modules""" - debug.warning("Design Class {0} delay function needs to be defined" + + # FIXME: Slew is not used in the model right now. Can be added heuristically as linear factor + relative_cap = logical_effort.convert_farad_to_relative_c(load) + stage_effort = self.get_stage_effort(relative_cap) + + # If it fails, then keep running with a valid object. + if stage_effort == None: + return delay_data(0.0, 0.0) + + abs_delay = stage_effort.get_absolute_delay() + corner_delay = self.apply_corners_analytically(abs_delay, corner) + SLEW_APPROXIMATION = 0.1 + corner_slew = SLEW_APPROXIMATION*corner_delay + return delay_data(corner_delay, corner_slew) + + def get_stage_effort(self, corner, slew, load=0.0): + """Inform users undefined delay module while building new modules""" + debug.warning("Design Class {0} logical effort function needs to be defined" .format(self.__class__.__name__)) debug.warning("Class {0} name {1}" .format(self.__class__.__name__, self.name)) - # return 0 to keep code running while building - return delay_data(0.0, 0.0) - + return None + + def get_cin(self): + """Returns input load in Femto-Farads. All values generated using + relative capacitance function then converted based on tech file parameter.""" + + # Override this function within a module if a more accurate input capacitance is needed. + # Input/outputs with differing capacitances is not implemented. + relative_cap = self.input_load() + return logical_effort.convert_relative_c_to_farad(relative_cap) + + def input_load(self): + """Inform users undefined relative capacitance functions used for analytical delays.""" + debug.warning("Design Class {0} input capacitance function needs to be defined" + .format(self.__class__.__name__)) + debug.warning("Class {0} name {1}" + .format(self.__class__.__name__, + self.name)) + return 0 + def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5): """ Calculate the delay of a mosfet by @@ -329,102 +431,3 @@ class spice(): def return_power(self, dynamic=0.0, leakage=0.0): 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 - diff --git a/compiler/base/lef.py b/compiler/base/lef.py index 5932bb67..af539742 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -1,9 +1,9 @@ # 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. +# 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 gdsMill import tech @@ -12,6 +12,7 @@ import math import debug import datetime from collections import defaultdict +import pdb class lef: """ @@ -21,9 +22,11 @@ class lef: """ def __init__(self,layers): # LEF db units per micron - self.lef_units = 1000 + self.lef_units = 2000 # These are the layers of the obstructions self.lef_layers = layers + # Round to ensure float values are divisible by 0.0025 (the manufacturing grid) + self.round_grid = 4; def lef_write(self, lef_name): """Write the entire lef of the object to the file.""" @@ -48,25 +51,14 @@ class lef: self.lef.write("UNITS\n") self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units)) self.lef.write("END UNITS\n") - - self.lef.write("SITE MacroSite\n") - self.indent += " " - self.lef.write("{0}CLASS Core ;\n".format(self.indent)) - self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent, - self.lef_units*self.width, - self.lef_units*self.height)) - self.indent = self.indent[:-3] - self.lef.write("END MacroSite\n") self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name)) self.indent += " " self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent)) self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent, - self.lef_units*self.width, - self.lef_units*self.height)) + round(self.width,self.round_grid), + round(self.height,self.round_grid))) self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent)) - self.lef.write("{0}SITE MacroSite ;\n".format(self.indent)) - def lef_write_footer(self): self.lef.write("{0}END {1}\n".format(self.indent,self.name)) @@ -93,7 +85,7 @@ class lef: pin_list = self.get_pins(name) for pin in pin_list: self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer)) - self.lef_write_rect(pin.rect) + self.lef_write_shape(pin.rect) # End the PORT self.indent = self.indent[:-3] @@ -109,15 +101,29 @@ class lef: for layer in self.lef_layers: self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer)) self.indent += " " + # pdb.set_trace() blockages = self.get_blockages(layer,True) for b in blockages: - self.lef_write_rect(b) + # if len(b) > 2: + # print(b) + self.lef_write_shape(b) self.indent = self.indent[:-3] self.lef.write("{0}END\n".format(self.indent)) - def lef_write_rect(self, rect): - """ Write a LEF rectangle """ - self.lef.write("{0}RECT ".format(self.indent)) - for item in rect: - self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1])) - self.lef.write(" ;\n") + def lef_write_shape(self, rect): + if len(rect) == 2: + """ Write a LEF rectangle """ + self.lef.write("{0}RECT ".format(self.indent)) + for item in rect: + # print(rect) + self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) + self.lef.write(" ;\n") + else: + """ Write a LEF polygon """ + self.lef.write("{0}POLYGON ".format(self.indent)) + for item in rect: + self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) + # for i in range(0,len(rect)): + # self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid))) + self.lef.write(" ;\n") + diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 4c3528fe..2d389119 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import GDS, drc diff --git a/compiler/base/power_data.py b/compiler/base/power_data.py new file mode 100644 index 00000000..77d50d34 --- /dev/null +++ b/compiler/base/power_data.py @@ -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) diff --git a/compiler/base/route.py b/compiler/base/route.py index c0bc1724..c3e446a3 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc import debug diff --git a/compiler/base/utils.py b/compiler/base/utils.py index 6642f095..61e12096 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -1,9 +1,9 @@ # 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. +# 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 os import gdsMill diff --git a/compiler/base/vector.py b/compiler/base/vector.py index a845b47c..8bf09f7d 100644 --- a/compiler/base/vector.py +++ b/compiler/base/vector.py @@ -1,9 +1,9 @@ # 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. +# 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 math diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index 8596e5bc..ff13c4f4 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -21,7 +21,11 @@ class verilog: self.vf.write("// OpenRAM SRAM model\n") self.vf.write("// Words: {0}\n".format(self.num_words)) - self.vf.write("// Word size: {0}\n\n".format(self.word_size)) + self.vf.write("// Word size: {0}\n".format(self.word_size)) + if self.write_size: + self.vf.write("// Write size: {0}\n\n".format(self.write_size)) + else: + self.vf.write("\n") self.vf.write("module {0}(\n".format(self.name)) for port in self.all_ports: @@ -32,16 +36,25 @@ class verilog: elif port in self.write_ports: self.vf.write("// Port {0}: W\n".format(port)) if port in self.readwrite_ports: - self.vf.write(" clk{0},csb{0},web{0},ADDR{0},DIN{0},DOUT{0}".format(port)) + self.vf.write(" clk{0},csb{0},web{0},".format(port)) + if self.write_size: + self.vf.write("wmask{},".format(port)) + self.vf.write("addr{0},din{0},dout{0}".format(port)) elif port in self.write_ports: - self.vf.write(" clk{0},csb{0},ADDR{0},DIN{0}".format(port)) + self.vf.write(" clk{0},csb{0},".format(port)) + if self.write_size: + self.vf.write("wmask{},".format(port)) + self.vf.write("addr{0},din{0}".format(port)) elif port in self.read_ports: - self.vf.write(" clk{0},csb{0},ADDR{0},DOUT{0}".format(port)) + self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port)) # Continue for every port on a new line if port != self.all_ports[-1]: self.vf.write(",\n") self.vf.write("\n );\n\n") - + + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks)) self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size)) self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size)) self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n") @@ -85,11 +98,14 @@ class verilog: self.vf.write(" reg csb{0}_reg;\n".format(port)) if port in self.readwrite_ports: self.vf.write(" reg web{0}_reg;\n".format(port)) - self.vf.write(" reg [ADDR_WIDTH-1:0] ADDR{0}_reg;\n".format(port)) if port in self.write_ports: - self.vf.write(" reg [DATA_WIDTH-1:0] DIN{0}_reg;\n".format(port)) + if self.write_size: + self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port)) + self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port)) + if port in self.write_ports: + self.vf.write(" reg [DATA_WIDTH-1:0] din{0}_reg;\n".format(port)) if port in self.read_ports: - self.vf.write(" reg [DATA_WIDTH-1:0] DOUT{0};\n".format(port)) + self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port)) def add_flops(self, port): """ @@ -102,24 +118,33 @@ class verilog: self.vf.write(" csb{0}_reg = csb{0};\n".format(port)) if port in self.readwrite_ports: self.vf.write(" web{0}_reg = web{0};\n".format(port)) - self.vf.write(" ADDR{0}_reg = ADDR{0};\n".format(port)) if port in self.write_ports: - self.vf.write(" DIN{0}_reg = DIN{0};\n".format(port)) + if self.write_size: + self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port)) + self.vf.write(" addr{0}_reg = addr{0};\n".format(port)) + if port in self.write_ports: + self.vf.write(" din{0}_reg = din{0};\n".format(port)) if port in self.read_ports: - self.vf.write(" DOUT{0} = {1}'bx;\n".format(port,self.word_size)) + self.vf.write(" dout{0} = {1}'bx;\n".format(port,self.word_size)) if port in self.readwrite_ports: self.vf.write(" if ( !csb{0}_reg && web{0}_reg ) \n".format(port)) - self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port)) + self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port)) elif port in self.read_ports: self.vf.write(" if ( !csb{0}_reg ) \n".format(port)) - self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port)) - + self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port)) if port in self.readwrite_ports: self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port)) - self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port)) + if self.write_size: + self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port)) + else: + self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port)) elif port in self.write_ports: self.vf.write(" if ( !csb{0}_reg )\n".format(port)) - self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port)) + if self.write_size: + self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port)) + else: + self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port)) + self.vf.write(" end\n\n") @@ -131,11 +156,13 @@ class verilog: self.vf.write(" input csb{0}; // active low chip select\n".format(port)) if port in self.readwrite_ports: self.vf.write(" input web{0}; // active low write control\n".format(port)) - self.vf.write(" input [ADDR_WIDTH-1:0] ADDR{0};\n".format(port)) + if self.write_size: + self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port)) + self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port)) if port in self.write_ports: - self.vf.write(" input [DATA_WIDTH-1:0] DIN{0};\n".format(port)) + self.vf.write(" input [DATA_WIDTH-1:0] din{0};\n".format(port)) if port in self.read_ports: - self.vf.write(" output [DATA_WIDTH-1:0] DOUT{0};\n".format(port)) + self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port)) def add_write_block(self, port): """ @@ -148,10 +175,25 @@ class verilog: self.vf.write(" always @ (negedge clk{0})\n".format(port)) self.vf.write(" begin : MEM_WRITE{0}\n".format(port)) if port in self.readwrite_ports: - self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port)) + if self.write_size: + self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port)) + else: + self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port)) else: - self.vf.write(" if (!csb{0}_reg)\n".format(port)) - self.vf.write(" mem[ADDR{0}_reg] = DIN{0}_reg;\n".format(port)) + if self.write_size: + self.vf.write(" if (!csb{0}_reg) begin\n".format(port)) + else: + self.vf.write(" if (!csb{0}_reg)\n".format(port)) + + if self.write_size: + for mask in range(0,self.num_wmasks): + lower = mask * self.write_size + upper = lower + self.write_size-1 + self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port,mask)) + self.vf.write(" mem[addr{0}_reg][{1}:{2}] = din{0}_reg[{1}:{2}];\n".format(port,upper,lower)) + self.vf.write(" end\n") + else: + self.vf.write(" mem[addr{0}_reg] = din{0}_reg;\n".format(port)) self.vf.write(" end\n") def add_read_block(self, port): @@ -167,6 +209,6 @@ class verilog: self.vf.write(" if (!csb{0}_reg && web{0}_reg)\n".format(port)) else: self.vf.write(" if (!csb{0}_reg)\n".format(port)) - self.vf.write(" DOUT{0} <= #(DELAY) mem[ADDR{0}_reg];\n".format(port)) + self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port)) self.vf.write(" end\n") diff --git a/compiler/base/wire.py b/compiler/base/wire.py index 2fe36026..bf1daa6a 100644 --- a/compiler/base/wire.py +++ b/compiler/base/wire.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc import debug diff --git a/compiler/base/wire_path.py b/compiler/base/wire_path.py index 71f6af27..ebfb8a0a 100644 --- a/compiler/base/wire_path.py +++ b/compiler/base/wire_path.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc from tech import layer as techlayer diff --git a/compiler/base/wire_spice_model.py b/compiler/base/wire_spice_model.py new file mode 100644 index 00000000..5624b575 --- /dev/null +++ b/compiler/base/wire_spice_model.py @@ -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 diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 7e2bd2c6..cad069a5 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -20,6 +20,8 @@ class bitcell(design.design): """ pin_names = ["bl", "br", "wl", "vdd", "gnd"] + storage_nets = ['Q', 'Qbar'] + type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) @@ -31,42 +33,50 @@ class bitcell(design.design): self.width = bitcell.width self.height = bitcell.height self.pin_map = bitcell.pin_map - - def analytical_delay(self, corner, slew, load=0, swing = 0.5): + self.add_pin_types(self.type_list) + self.nets_match = self.do_nets_exist(self.storage_nets) + + def get_stage_effort(self, load): parasitic_delay = 1 size = 0.5 #This accounts for bitline being drained thought the access TX and internal node 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) - def list_bitcell_pins(self, col, row): - """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ - bitcell_pins = ["bl_{0}".format(col), - "br_{0}".format(col), - "wl_{0}".format(row), - "vdd", - "gnd"] - return bitcell_pins - - def list_all_wl_names(self): + def get_all_wl_names(self): """ Creates a list of all wordline pin names """ row_pins = ["wl"] 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) """ column_pins = ["bl", "br"] return column_pins - def list_all_bl_names(self): + def get_all_bl_names(self): """ Creates a list of all bl pins names """ column_pins = ["bl"] return column_pins - def list_all_br_names(self): + def get_all_br_names(self): """ Creates a list of all br pins names """ column_pins = ["br"] return column_pins + def get_bl_name(self, port=0): + """Get bl name""" + debug.check(port==0,"One port for bitcell only.") + return "bl" + + def get_br_name(self, port=0): + """Get bl name""" + debug.check(port==0,"One port for bitcell only.") + 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): """Bitcell power in nW. Only characterizes leakage.""" from tech import spice @@ -74,10 +84,23 @@ class bitcell(design.design): dynamic = 0 #temporary total_power = self.return_power(dynamic, leakage) return total_power - - def get_wl_cin(self): + + def get_storage_net_names(self): + """Returns names of storage nodes in bitcell in [non-inverting, inverting] format.""" + #Checks that they do exist + if self.nets_match: + return self.storage_nets + else: + debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets)) + return None + + def input_load(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: This applies to bitline capacitances as well. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] return 2*access_tx_cin + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py index 2dd9c9fa..0d536b38 100644 --- a/compiler/bitcells/bitcell_1rw_1r.py +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -20,6 +20,8 @@ class bitcell_1rw_1r(design.design): """ pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"] + type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"] + storage_nets = ['Q', 'Q_bar'] (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"]) @@ -31,15 +33,17 @@ class bitcell_1rw_1r(design.design): self.width = bitcell_1rw_1r.width self.height = bitcell_1rw_1r.height self.pin_map = bitcell_1rw_1r.pin_map - - def analytical_delay(self, corner, slew, load=0, swing = 0.5): + self.add_pin_types(self.type_list) + self.nets_match = self.do_nets_exist(self.storage_nets) + + def get_stage_effort(self, load): parasitic_delay = 1 size = 0.5 #This accounts for bitline being drained thought the access TX and internal node cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. 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) - 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 """ bitcell_pins = ["bl0_{0}".format(col), "br0_{0}".format(col), @@ -51,46 +55,61 @@ class bitcell_1rw_1r(design.design): "gnd"] return bitcell_pins - def list_all_wl_names(self): + def get_all_wl_names(self): """ Creates a list of all wordline pin names """ row_pins = ["wl0", "wl1"] 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) """ column_pins = ["bl0", "br0", "bl1", "br1"] return column_pins - def list_all_bl_names(self): + def get_all_bl_names(self): """ Creates a list of all bl pins names """ column_pins = ["bl0", "bl1"] return column_pins - def list_all_br_names(self): + def get_all_br_names(self): """ Creates a list of all br pins names """ column_pins = ["br0", "br1"] 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 """ column_pins = ["bl0", "bl1"] 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 """ column_pins = ["br0", "br1"] 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 """ column_pins = ["bl0"] 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""" column_pins = ["br0"] return column_pins + def get_bl_name(self, port=0): + """Get bl name by port""" + debug.check(port<2,"Two ports for bitcell_1rw_1r only.") + return "bl{}".format(port) + + def get_br_name(self, port=0): + """Get bl name by port""" + debug.check(port<2,"Two ports for bitcell_1rw_1r only.") + 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): """Bitcell power in nW. Only characterizes leakage.""" from tech import spice @@ -99,10 +118,31 @@ class bitcell_1rw_1r(design.design): total_power = self.return_power(dynamic, leakage) return total_power - def get_wl_cin(self): + def input_load(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. + + # FIXME: This applies to bitline capacitances as well. + # 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 get_storage_net_names(self): + """Returns names of storage nodes in bitcell in [non-inverting, inverting] format.""" + #Checks that they do exist + if self.nets_match: + return self.storage_nets + else: + debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets)) + return None + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges to graph. Multiport bitcell timing graph is too complex + to use the add_graph_edges function.""" + pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + #Edges hardcoded here. Essentially wl->bl/br for both ports. + # Port 0 edges + graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self) + graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self) + # Port 1 edges + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self) diff --git a/compiler/bitcells/bitcell_1w_1r.py b/compiler/bitcells/bitcell_1w_1r.py index 9e920327..7e8c9e75 100644 --- a/compiler/bitcells/bitcell_1w_1r.py +++ b/compiler/bitcells/bitcell_1w_1r.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -20,6 +20,8 @@ class bitcell_1w_1r(design.design): """ pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"] + type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"] + storage_nets = ['Q', 'Q_bar'] (width,height) = utils.get_libcell_size("cell_1w_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1w_1r", GDS["unit"]) @@ -31,15 +33,17 @@ class bitcell_1w_1r(design.design): self.width = bitcell_1w_1r.width self.height = bitcell_1w_1r.height self.pin_map = bitcell_1w_1r.pin_map + self.add_pin_types(self.type_list) + self.nets_match = self.do_nets_exist(self.storage_nets) - def analytical_delay(self, corner, slew, load=0, swing = 0.5): + def get_stage_effort(self, load): parasitic_delay = 1 size = 0.5 #This accounts for bitline being drained thought the access TX and internal node cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. 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) - 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 """ bitcell_pins = ["bl0_{0}".format(col), "br0_{0}".format(col), @@ -51,46 +55,59 @@ class bitcell_1w_1r(design.design): "gnd"] return bitcell_pins - def list_all_wl_names(self): + def get_all_wl_names(self): """ Creates a list of all wordline pin names """ row_pins = ["wl0", "wl1"] 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) """ column_pins = ["bl0", "br0", "bl1", "br1"] return column_pins - def list_all_bl_names(self): + def get_all_bl_names(self): """ Creates a list of all bl pins names """ column_pins = ["bl0", "bl1"] return column_pins - def list_all_br_names(self): + def get_all_br_names(self): """ Creates a list of all br pins names """ column_pins = ["br0", "br1"] 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 """ column_pins = ["bl0", "bl1"] 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 """ column_pins = ["br0", "br1"] 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 """ column_pins = ["bl0"] 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""" column_pins = ["br0"] return column_pins + def get_bl_name(self, port=0): + """Get bl name by port""" + return "bl{}".format(port) + + def get_br_name(self, port=0): + """Get bl name by 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): """Bitcell power in nW. Only characterizes leakage.""" from tech import spice @@ -99,10 +116,29 @@ class bitcell_1w_1r(design.design): total_power = self.return_power(dynamic, leakage) return total_power - def get_wl_cin(self): + def input_load(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. + + # FIXME: This applies to bitline capacitances as well. + # 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 get_storage_net_names(self): + """Returns names of storage nodes in bitcell in [non-inverting, inverting] format.""" + #Checks that they do exist + if self.nets_match: + return self.storage_nets + else: + debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets)) + return None + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges to graph. Multiport bitcell timing graph is too complex + to use the add_graph_edges function.""" + pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + #Edges hardcoded here. Essentially wl->bl/br for both ports. + # Port 0 edges + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self) + # Port 1 is a write port, so its timing is not considered here. diff --git a/compiler/bitcells/dummy_bitcell.py b/compiler/bitcells/dummy_bitcell.py new file mode 100644 index 00000000..db748203 --- /dev/null +++ b/compiler/bitcells/dummy_bitcell.py @@ -0,0 +1,48 @@ +# 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,parameter,drc +import logical_effort + +class dummy_bitcell(design.design): + """ + A single bit cell (6T, 8T, etc.) 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 = ["bl", "br", "wl", "vdd", "gnd"] + (width,height) = utils.get_libcell_size("dummy_cell_6t", GDS["unit"], layer["boundary"]) + pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_6t", GDS["unit"]) + + def __init__(self, name=""): + # Ignore the name argument + design.design.__init__(self, "dummy_cell_6t") + debug.info(2, "Create dummy bitcell") + + self.width = dummy_bitcell.width + self.height = dummy_bitcell.height + self.pin_map = dummy_bitcell.pin_map + + def analytical_power(self, corner, load): + """Bitcell power in nW. Only characterizes leakage.""" + from tech import spice + leakage = spice["bitcell_leakage"] + dynamic = 0 #temporary + total_power = self.return_power(dynamic, leakage) + return total_power + + 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. + access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] + return 2*access_tx_cin diff --git a/compiler/bitcells/dummy_bitcell_1rw_1r.py b/compiler/bitcells/dummy_bitcell_1rw_1r.py new file mode 100644 index 00000000..f8986f2d --- /dev/null +++ b/compiler/bitcells/dummy_bitcell_1rw_1r.py @@ -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 diff --git a/compiler/bitcells/dummy_bitcell_1w_1r.py b/compiler/bitcells/dummy_bitcell_1w_1r.py new file mode 100644 index 00000000..ef451b8c --- /dev/null +++ b/compiler/bitcells/dummy_bitcell_1w_1r.py @@ -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 diff --git a/compiler/bitcells/dummy_pbitcell.py b/compiler/bitcells/dummy_pbitcell.py new file mode 100644 index 00000000..ee15e03c --- /dev/null +++ b/compiler/bitcells/dummy_pbitcell.py @@ -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() diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index e045b763..919a0316 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import design @@ -20,22 +20,32 @@ class pbitcell(design.design): 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_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 self.replica_bitcell = replica_bitcell + self.dummy_bitcell = dummy_bitcell 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, - self.num_w_ports, - self.num_r_ports)) + info_string = "{0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, + self.num_w_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() - # 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.add_boundary() def create_netlist(self): self.add_pins() @@ -79,9 +89,7 @@ class pbitcell(design.design): # in netlist_only mode, calling offset_all_coordinates or translate_all will not be possible # this function is not needed to calculate the dimensions of pbitcell in netlist_only mode though if not OPTS.netlist_only: - self.offset_all_coordinates() - gnd_overlap = vector(0, 0.5*contact.well.width) - self.translate_all(gnd_overlap) + self.translate_all(vector(self.leftmost_xpos, self.botmost_ypos)) def add_pins(self): @@ -98,50 +106,53 @@ class pbitcell(design.design): port = 0 for k in range(self.num_rw_ports): - self.add_pin("bl{}".format(port)) - self.add_pin("br{}".format(port)) + self.add_pin("bl{}".format(port), "OUTPUT") + self.add_pin("br{}".format(port), "OUTPUT") self.rw_bl_names.append("bl{}".format(port)) self.rw_br_names.append("br{}".format(port)) port += 1 for k in range(self.num_w_ports): - self.add_pin("bl{}".format(port)) - self.add_pin("br{}".format(port)) + self.add_pin("bl{}".format(port), "INPUT") + self.add_pin("br{}".format(port), "INPUT") self.w_bl_names.append("bl{}".format(port)) self.w_br_names.append("br{}".format(port)) port += 1 for k in range(self.num_r_ports): - self.add_pin("bl{}".format(port)) - self.add_pin("br{}".format(port)) + self.add_pin("bl{}".format(port), "OUTPUT") + self.add_pin("br{}".format(port), "OUTPUT") self.r_bl_names.append("bl{}".format(port)) self.r_br_names.append("br{}".format(port)) port += 1 port = 0 for k in range(self.num_rw_ports): - self.add_pin("wl{}".format(port)) + self.add_pin("wl{}".format(port), "INPUT") self.rw_wl_names.append("wl{}".format(port)) port += 1 for k in range(self.num_w_ports): - self.add_pin("wl{}".format(port)) + self.add_pin("wl{}".format(port), "INPUT") self.w_wl_names.append("wl{}".format(port)) port += 1 for k in range(self.num_r_ports): - self.add_pin("wl{}".format(port)) + self.add_pin("wl{}".format(port), "INPUT") self.r_wl_names.append("wl{}".format(port)) port += 1 - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") # if this is a replica bitcell, replace the instances of Q_bar with vdd if self.replica_bitcell: self.Q_bar = "vdd" else: self.Q_bar = "Q_bar" - + self.Q = "Q" + self.storage_nets = [self.Q, self.Q_bar] + def add_modules(self): """ Determine size of transistors and add ptx modules """ - # if there are any read/write ports, then the inverter nmos is sized based the number of read/write ports + # if there are any read/write ports, + # then the inverter nmos is sized based the number of read/write ports if(self.num_rw_ports > 0): inverter_nmos_width = self.num_rw_ports*parameter["6T_inv_nmos_size"] inverter_pmos_width = parameter["6T_inv_pmos_size"] @@ -149,7 +160,8 @@ class pbitcell(design.design): write_nmos_width = parameter["6T_access_size"] read_nmos_width = 2*parameter["6T_inv_pmos_size"] - # if there are no read/write ports, then the inverter nmos is statically sized for the dual port case + # if there are no read/write ports, + # then the inverter nmos is statically sized for the dual port case else: inverter_nmos_width = 2*parameter["6T_inv_pmos_size"] inverter_pmos_width = parameter["6T_inv_pmos_size"] @@ -183,14 +195,21 @@ class pbitcell(design.design): def calculate_spacing(self): """ Calculate transistor spacings """ + # calculate metal contact extensions over transistor active - readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height - self.readwrite_nmos.active_height) - write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height - self.write_nmos.active_height) - read_nmos_contact_extension = 0.5*(self.read_nmos.active_contact.height - self.read_nmos.active_height) - max_contact_extension = max(readwrite_nmos_contact_extension, write_nmos_contact_extension, read_nmos_contact_extension) + readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height \ + - self.readwrite_nmos.active_height) + write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height \ + - self.write_nmos.active_height) + read_nmos_contact_extension = 0.5*(self.read_nmos.active_contact.height \ + - self.read_nmos.active_height) + max_contact_extension = max(readwrite_nmos_contact_extension, + write_nmos_contact_extension, + read_nmos_contact_extension) # y-offset for the access transistor's gate contact - self.gate_contact_yoffset = max_contact_extension + self.m2_space + 0.5*max(contact.poly.height, contact.m1m2.height) + self.gate_contact_yoffset = max_contact_extension + self.m2_space \ + + 0.5*max(contact.poly.height, contact.m1m2.height) # y-position of access transistors self.port_ypos = self.m1_space + 0.5*contact.m1m2.height + self.gate_contact_yoffset @@ -199,8 +218,10 @@ class pbitcell(design.design): self.inverter_nmos_ypos = self.port_ypos # spacing between ports (same for read/write and write ports) - self.bitline_offset = -0.5*self.readwrite_nmos.active_width + 0.5*contact.m1m2.height + self.m2_space + self.m2_width - m2_constraint = self.bitline_offset + self.m2_space + 0.5*contact.m1m2.height - 0.5*self.readwrite_nmos.active_width + self.bitline_offset = -0.5*self.readwrite_nmos.active_width + 0.5*contact.m1m2.height \ + + self.m2_space + self.m2_width + m2_constraint = self.bitline_offset + self.m2_space + 0.5*contact.m1m2.height \ + - 0.5*self.readwrite_nmos.active_width self.write_port_spacing = max(self.active_space, self.m1_space, m2_constraint) self.read_port_spacing = self.bitline_offset + self.m2_space @@ -222,11 +243,11 @@ class pbitcell(design.design): + 1.5*contact.poly.width # spacing between wordlines (and gnd) - self.rowline_spacing = self.m1_space + contact.m1m2.width - self.rowline_offset = -0.5*self.m1_width + self.m1_offset = -0.5*self.m1_width # spacing for vdd - implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active + 0.5*(contact.well.width - self.m1_width) + implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active \ + + 0.5*(contact.well.width - self.m1_width) metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space self.vdd_offset = max(implant_constraint, metal1_constraint) + 0.5*self.m1_width @@ -236,8 +257,10 @@ class pbitcell(design.design): def calculate_postions(self): """ Calculate positions that describe the edges and dimensions of the cell """ - self.botmost_ypos = -0.5*self.m1_width - self.total_ports*self.rowline_spacing - self.topmost_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height + self.vdd_offset + self.botmost_ypos = self.m1_offset - self.total_ports*self.m1_pitch + self.topmost_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \ + + self.inverter_gap + self.inverter_pmos.active_height \ + + self.vdd_offset self.leftmost_xpos = -0.5*self.inverter_to_inverter_spacing - self.inverter_nmos.active_width \ - self.num_rw_ports*(self.readwrite_nmos.active_width + self.write_port_spacing) \ @@ -247,9 +270,9 @@ class pbitcell(design.design): self.width = -2*self.leftmost_xpos self.height = self.topmost_ypos - self.botmost_ypos - self.center_ypos = 0.5*(self.topmost_ypos + self.botmost_ypos) - + + def create_storage(self): """ Creates the crossed coupled inverters that act as storage for the bitcell. @@ -258,20 +281,20 @@ class pbitcell(design.design): # create active for nmos self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left", mod=self.inverter_nmos) - self.connect_inst(["Q", self.Q_bar, "gnd", "gnd"]) + self.connect_inst([self.Q, self.Q_bar, "gnd", "gnd"]) self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right", mod=self.inverter_nmos) - self.connect_inst(["gnd", "Q", self.Q_bar, "gnd"]) + self.connect_inst(["gnd", self.Q, self.Q_bar, "gnd"]) # create active for pmos self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left", mod=self.inverter_pmos) - self.connect_inst(["Q", self.Q_bar, "vdd", "vdd"]) + self.connect_inst([self.Q, self.Q_bar, "vdd", "vdd"]) self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right", mod=self.inverter_pmos) - self.connect_inst(["vdd", "Q", self.Q_bar, "vdd"]) + self.connect_inst(["vdd", self.Q, self.Q_bar, "vdd"]) def place_storage(self): """ Places the transistors for the crossed coupled inverters in the bitcell """ @@ -307,13 +330,15 @@ class pbitcell(design.design): width=contact.active.second_layer_width) # add contacts to connect gate poly to drain/source metal1 (to connect Q to Q_bar) - contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x + 0.5*contact.poly.height, self.cross_couple_upper_ypos) + contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x + 0.5*contact.poly.height, + self.cross_couple_upper_ypos) self.add_via_center(layers=("poly", "contact", "metal1"), offset=contact_offset_left, directions=("H","H")) - contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height, self.cross_couple_lower_ypos) + contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height, + self.cross_couple_lower_ypos) self.add_via_center(layers=("poly", "contact", "metal1"), offset=contact_offset_right, directions=("H","H")) @@ -328,21 +353,21 @@ class pbitcell(design.design): def route_rails(self): """ Adds gnd and vdd rails and connects them to the inverters """ # Add rails for vdd and gnd - gnd_ypos = self.rowline_offset - self.total_ports*self.rowline_spacing + gnd_ypos = self.m1_offset - self.total_ports*self.m1_pitch self.gnd_position = vector(0, gnd_ypos) self.add_rect_center(layer="metal1", offset=self.gnd_position, - width=self.width, - height=self.m1_width) + width=self.width) self.add_power_pin("gnd", vector(0,gnd_ypos)) - vdd_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height + self.vdd_offset + vdd_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \ + + self.inverter_gap + self.inverter_pmos.active_height \ + + self.vdd_offset self.vdd_position = vector(0, vdd_ypos) self.add_rect_center(layer="metal1", offset=self.vdd_position, - width=self.width, - height=self.m1_width) + width=self.width) self.add_power_pin("vdd", vector(0,vdd_ypos)) def create_readwrite_ports(self): @@ -360,14 +385,20 @@ class pbitcell(design.design): # iterate over the number of read/write 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 self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), mod=self.readwrite_nmos) - self.connect_inst([self.rw_bl_names[k], self.rw_wl_names[k], "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), 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): """ Places read/write ports in the bit cell """ @@ -393,13 +424,12 @@ class pbitcell(design.design): self.readwrite_nmos_right[k].place(offset=[right_readwrite_transistor_xpos, self.port_ypos]) # add pin for RWWL - rwwl_ypos = self.rowline_offset - k*self.rowline_spacing + rwwl_ypos = self.m1_offset - k*self.m1_pitch self.rwwl_positions[k] = vector(0, rwwl_ypos) self.add_layout_pin_rect_center(text=self.rw_wl_names[k], layer="metal1", offset=self.rwwl_positions[k], - width=self.width, - height=self.m1_width) + width=self.width) # add pins for RWBL and RWBR rwbl_xpos = left_readwrite_transistor_xpos - self.bitline_offset + 0.5*self.m2_width @@ -409,7 +439,8 @@ class pbitcell(design.design): offset=self.rwbl_positions[k], height=self.height) - rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width + self.bitline_offset - 0.5*self.m2_width + rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width \ + + self.bitline_offset - 0.5*self.m2_width self.rwbr_positions[k] = vector(rwbr_xpos, self.center_ypos) self.add_layout_pin_rect_center(text=self.rw_br_names[k], layer="metal2", @@ -434,14 +465,20 @@ class pbitcell(design.design): # iterate over the number of write 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 self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), mod=self.write_nmos) - self.connect_inst([self.w_bl_names[k], self.w_wl_names[k], "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), 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): """ Places write ports in the bit cell """ @@ -468,13 +505,13 @@ class pbitcell(design.design): self.write_nmos_right[k].place(offset=[right_write_transistor_xpos, self.port_ypos]) # add pin for WWL - wwl_ypos = rwwl_ypos = self.rowline_offset - self.num_rw_ports*self.rowline_spacing - k*self.rowline_spacing + wwl_ypos = rwwl_ypos = self.m1_offset - self.num_rw_ports*self.m1_pitch \ + - k*self.m1_pitch self.wwl_positions[k] = vector(0, wwl_ypos) self.add_layout_pin_rect_center(text=self.w_wl_names[k], layer="metal1", offset=self.wwl_positions[k], - width=self.width, - height=self.m1_width) + width=self.width) # add pins for WBL and WBR wbl_xpos = left_write_transistor_xpos - self.bitline_offset + 0.5*self.m2_width @@ -484,7 +521,8 @@ class pbitcell(design.design): offset=self.wbl_positions[k], height=self.height) - wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset - 0.5*self.m2_width + wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset \ + - 0.5*self.m2_width self.wbr_positions[k] = vector(wbr_xpos, self.center_ypos) self.add_layout_pin_rect_center(text=self.w_br_names[k], layer="metal2", @@ -515,6 +553,12 @@ class pbitcell(design.design): # iterate over the number of read 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 self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), mod=self.read_nmos) @@ -522,16 +566,16 @@ class pbitcell(design.design): self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k), mod=self.read_nmos) - self.connect_inst(["gnd", "Q", "RA_to_R_right{}".format(k), "gnd"]) + self.connect_inst(["gnd", self.Q, "RA_to_R_right{}".format(k), "gnd"]) # add read transistors self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), 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), 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): """ Places the read ports in the bit cell """ @@ -565,13 +609,13 @@ class pbitcell(design.design): self.read_nmos_right[k].place(offset=[right_read_transistor_xpos+overlap_offset, self.port_ypos]) # add pin for RWL - rwl_ypos = rwwl_ypos = self.rowline_offset - self.num_rw_ports*self.rowline_spacing - self.num_w_ports*self.rowline_spacing - k*self.rowline_spacing + rwl_ypos = rwwl_ypos = self.m1_offset - self.num_rw_ports*self.m1_pitch \ + - self.num_w_ports*self.m1_pitch - k*self.m1_pitch self.rwl_positions[k] = vector(0, rwl_ypos) self.add_layout_pin_rect_center(text=self.r_wl_names[k], layer="metal1", offset=self.rwl_positions[k], - width=self.width, - height=self.m1_width) + width=self.width) # add pins for RBL and RBR rbl_xpos = left_read_transistor_xpos - self.bitline_offset + 0.5*self.m2_width @@ -581,7 +625,8 @@ class pbitcell(design.design): offset=self.rbl_positions[k], height=self.height) - rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset - 0.5*self.m2_width + rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset \ + - 0.5*self.m2_width self.rbr_positions[k] = vector(rbr_xpos, self.center_ypos) self.add_layout_pin_rect_center(text=self.r_br_names[k], layer="metal2", @@ -668,8 +713,10 @@ class pbitcell(design.design): port_contact_offest = left_port_transistors[k].get_pin("S").center() bl_offset = vector(bl_positions[k].x, port_contact_offest.y) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=port_contact_offest) + # Leave bitline disconnected if a dummy cell + 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) @@ -677,8 +724,10 @@ class pbitcell(design.design): port_contact_offest = right_port_transistors[k].get_pin("D").center() br_offset = vector(br_positions[k].x, port_contact_offest.y) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=port_contact_offest) + # Leave bitline disconnected if a dummy cell + 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) @@ -739,12 +788,14 @@ class pbitcell(design.design): def route_read_access(self): """ Routes read access transistors to the storage component of the bitcell """ # add poly to metal1 contacts for gates of the inverters - left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - self.poly_to_polycontact - 0.5*contact.poly.width, self.cross_couple_upper_ypos) + left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - self.poly_to_polycontact - 0.5*contact.poly.width, + self.cross_couple_upper_ypos) self.add_via_center(layers=("poly", "contact", "metal1"), offset=left_storage_contact, directions=("H","H")) - right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + self.poly_to_polycontact + 0.5*contact.poly.width, self.cross_couple_upper_ypos) + right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + self.poly_to_polycontact + 0.5*contact.poly.width, + self.cross_couple_upper_ypos) self.add_via_center(layers=("poly", "contact", "metal1"), offset=right_storage_contact, directions=("H","H")) @@ -826,7 +877,7 @@ class pbitcell(design.design): implant_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 """ bitcell_pins = [] for port in range(self.total_ports): @@ -838,12 +889,12 @@ class pbitcell(design.design): bitcell_pins.append("gnd") return bitcell_pins - def list_all_wl_names(self): + def get_all_wl_names(self): """ Creates a list of all wordline pin names """ wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_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) """ bitline_pins = [] for port in range(self.total_ports): @@ -851,23 +902,39 @@ class pbitcell(design.design): bitline_pins.append("br{0}".format(port)) return bitline_pins - def list_all_bl_names(self): + def get_all_bl_names(self): """ Creates a list of all bl pins names """ - bl_pins = self.rw_bl_names + self.w_bl_names + self.r_bl_names - return bl_pins + return self.rw_bl_names + self.w_bl_names + self.r_bl_names - def list_all_br_names(self): + def get_all_br_names(self): """ Creates a list of all br pins names """ - br_pins = self.rw_br_names + self.w_br_names + self.r_br_names - return br_pins + return self.rw_br_names + self.w_br_names + self.r_br_names def route_rbc_short(self): """ route the short from Q_bar to gnd necessary for the replica bitcell """ Q_bar_pos = self.inverter_pmos_right.get_pin("S").center() vdd_pos = self.inverter_pmos_right.get_pin("D").center() self.add_path("metal1", [Q_bar_pos, vdd_pos]) + + def get_storage_net_names(self): + """Returns names of storage nodes in bitcell in [non-inverting, inverting] format.""" + return self.storage_nets + + def get_bl_name(self, port=0): + """Get bl name by port""" + return "bl{}".format(port) + + def get_br_name(self, port=0): + """Get bl name by port""" + return "br{}".format(port) - def analytical_delay(self, corner, slew, load=0, swing = 0.5): + 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 get_stage_effort(self, load): parasitic_delay = 1 size = 0.5 #This accounts for bitline being drained thought the access TX and internal node cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. @@ -887,9 +954,27 @@ class pbitcell(design.design): total_power = self.return_power(dynamic, leakage) return total_power - def get_wl_cin(self): + def input_load(self): """Return the relative capacitance of the access transistor gates""" - #pbitcell uses the different sizing for the port access tx's. Not accounted for in this model. + + # FIXME: This applies to bitline capacitances as well. + # pbitcell uses the different sizing for the port access tx's. Not accounted for in this model. access_tx_cin = self.readwrite_nmos.get_cin() return 2*access_tx_cin + def build_graph(self, graph, inst_name, port_nets): + """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)} + # 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) + r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names) + + for pin_zip in [rw_pin_names, r_pin_names]: + for wl,bl,br in pin_zip: + graph.add_edge(pin_dict[wl],pin_dict[bl], self) + graph.add_edge(pin_dict[wl],pin_dict[br], self) + diff --git a/compiler/bitcells/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py index 0a0e4fbf..2f804bf0 100644 --- a/compiler/bitcells/replica_bitcell.py +++ b/compiler/bitcells/replica_bitcell.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -18,6 +18,7 @@ class replica_bitcell(design.design): the technology library. """ pin_names = ["bl", "br", "wl", "vdd", "gnd"] + type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"]) @@ -29,10 +30,30 @@ class replica_bitcell(design.design): self.width = replica_bitcell.width self.height = replica_bitcell.height self.pin_map = replica_bitcell.pin_map - - def get_wl_cin(self): + self.add_pin_types(self.type_list) + + def get_stage_effort(self, load): + parasitic_delay = 1 + size = 0.5 #This accounts for bitline being drained thought the access TX and internal node + cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. + 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) + + def input_load(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: This applies to bitline capacitances as well. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin + return 2*access_tx_cin + + def analytical_power(self, corner, load): + """Bitcell power in nW. Only characterizes leakage.""" + from tech import spice + leakage = spice["bitcell_leakage"] + dynamic = 0 #temporary + total_power = self.return_power(dynamic, leakage) + return total_power + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/bitcells/replica_bitcell_1rw_1r.py b/compiler/bitcells/replica_bitcell_1rw_1r.py index 2ada1381..0f56319e 100644 --- a/compiler/bitcells/replica_bitcell_1rw_1r.py +++ b/compiler/bitcells/replica_bitcell_1rw_1r.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -18,6 +18,7 @@ class replica_bitcell_1rw_1r(design.design): 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("replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"]) @@ -29,11 +30,31 @@ class replica_bitcell_1rw_1r(design.design): self.width = replica_bitcell_1rw_1r.width self.height = replica_bitcell_1rw_1r.height self.pin_map = replica_bitcell_1rw_1r.pin_map + self.add_pin_types(self.type_list) - def get_wl_cin(self): + def get_stage_effort(self, load): + parasitic_delay = 1 + size = 0.5 #This accounts for bitline being drained thought the access TX and internal node + cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. + 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) + + def input_load(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. + + # FIXME: This applies to bitline capacitances as well. + # 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): + """Adds edges to graph. Multiport bitcell timing graph is too complex + to use the add_graph_edges function.""" + pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} + #Edges hardcoded here. Essentially wl->bl/br for both ports. + # Port 0 edges + graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self) + graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self) + # Port 1 edges + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self) \ No newline at end of file diff --git a/compiler/bitcells/replica_bitcell_1w_1r.py b/compiler/bitcells/replica_bitcell_1w_1r.py index c079399a..b903e0ad 100644 --- a/compiler/bitcells/replica_bitcell_1w_1r.py +++ b/compiler/bitcells/replica_bitcell_1w_1r.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -18,6 +18,7 @@ class replica_bitcell_1w_1r(design.design): 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("replica_cell_1w_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1w_1r", GDS["unit"]) @@ -29,11 +30,30 @@ class replica_bitcell_1w_1r(design.design): self.width = replica_bitcell_1w_1r.width self.height = replica_bitcell_1w_1r.height self.pin_map = replica_bitcell_1w_1r.pin_map + self.add_pin_types(self.type_list) - def get_wl_cin(self): + def get_stage_effort(self, load): + parasitic_delay = 1 + size = 0.5 #This accounts for bitline being drained thought the access TX and internal node + cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. + 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) + + def input_load(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. + + # FIXME: This applies to bitline capacitances as well. + # 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): + """Adds edges to graph. Multiport bitcell timing graph is too complex + 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)} + #Edges hardcoded here. Essentially wl->bl/br for the read port. + # Port 1 edges + graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self) + graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self) + # Port 0 is a write port, so its timing is not considered here. \ No newline at end of file diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py index 30898d82..4fcfb4c5 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/bitcells/replica_pbitcell.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -84,8 +84,4 @@ class replica_pbitcell(design.design): 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() + \ No newline at end of file diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 4c3cd910..93dd5bcb 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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 os import debug @@ -13,9 +13,7 @@ from .lib import * from .delay import * from .setup_hold import * from .functional import * -from .worst_case import * from .simulation import * -from .bitline_delay import * from .measurements import * from .model_check import * diff --git a/compiler/characterizer/bit_polarity.py b/compiler/characterizer/bit_polarity.py new file mode 100644 index 00000000..c14c167e --- /dev/null +++ b/compiler/characterizer/bit_polarity.py @@ -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 + diff --git a/compiler/characterizer/bitline_delay.py b/compiler/characterizer/bitline_delay.py deleted file mode 100644 index 90197619..00000000 --- a/compiler/characterizer/bitline_delay.py +++ /dev/null @@ -1,248 +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 bitline_delay(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) - self.period = tech.spice["feasible_period"] - self.is_bitline_measure = True - - def create_signal_names(self): - delay.create_signal_names(self) - self.bl_signal_names = ["Xsram.Xbank0.bl", "Xsram.Xbank0.br"] - self.sen_name = "Xsram.s_en" - - def create_measurement_names(self): - """Create measurement names. The names themselves currently define the type of measurement""" - #Altering the names will crash the characterizer. TODO: object orientated approach to the measurements. - self.bl_volt_meas_names = ["volt_bl", "volt_br"] - self.bl_delay_meas_names = ["delay_bl", "delay_br"] #only used in SPICE simulation - self.bl_delay_result_name = "delay_bl_vth" #Used in the return value - - def set_probe(self,probe_address, probe_data): - """ Probe address and data can be set separately to utilize other - functions in this characterizer besides analyze.""" - delay.set_probe(self,probe_address, probe_data) - self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data) - - def write_delay_measures(self): - """ - Write the measure statements to quantify the bitline voltage at sense amp enable 50%. - """ - self.sf.write("\n* Measure statements for delay and power\n") - - # Output some comments to aid where cycles start and - for comment in self.cycle_comments: - self.sf.write("* {}\n".format(comment)) - - for read_port in self.targ_read_ports: - self.write_bitline_voltage_measures(read_port) - self.write_bitline_delay_measures(read_port) - - def write_bitline_voltage_measures(self, port): - """ - Add measurments to capture the bitline voltages at 50% Sense amp enable - """ - debug.info(2, "Measuring bitline column={}, port={}".format(self.bitline_column,port)) - if len(self.all_ports) == 1: #special naming case for single port sram bitlines - bitline_port = "" - else: - bitline_port = str(port) - - sen_port_name = "{}{}".format(self.sen_name,port) - for (measure_name, bl_signal_name) in zip(self.bl_volt_meas_names, self.bl_signal_names): - bl_port_name = "{}{}_{}".format(bl_signal_name, bitline_port, self.bitline_column) - measure_port_name = "{}{}".format(measure_name,port) - self.stim.gen_meas_find_voltage(measure_port_name, sen_port_name, bl_port_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]]) - - def write_bitline_delay_measures(self, port): - """ - Write the measure statements to quantify the delay and power results for a read port. - """ - # add measure statements for delays/slews - for (measure_name, bl_signal_name) in zip(self.bl_delay_meas_names, self.bl_signal_names): - meas_values = self.get_delay_meas_values(measure_name, bl_signal_name, port) - self.stim.gen_meas_delay(*meas_values) - - def get_delay_meas_values(self, delay_name, bitline_name, port): - """Get the values needed to generate a Spice measurement statement based on the name of the measurement.""" - if len(self.all_ports) == 1: #special naming case for single port sram bitlines - bitline_port = "" - else: - bitline_port = str(port) - - meas_name="{0}{1}".format(delay_name, port) - targ_name = "{0}{1}_{2}".format(bitline_name,bitline_port,self.bitline_column) - half_vdd = 0.5 * self.vdd_voltage - trig_val = half_vdd - targ_val = self.vdd_voltage-tech.spice["v_threshold_typical"] - trig_name = "clk{0}".format(port) - trig_dir="FALL" - targ_dir="FALL" - #Half period added to delay measurement to negative clock edge - trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2 - return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td) - - def gen_test_cycles_one_port(self, read_port, write_port): - """Sets a list of key time-points [ns] of the waveform (each rising edge) - of the cycles to do a timing evaluation of a single port """ - - # Create the inverse address for a scratch address - inverse_address = self.calculate_inverse_address() - - # For now, ignore data patterns and write ones or zeros - data_ones = "1"*self.word_size - data_zeros = "0"*self.word_size - - if self.t_current == 0: - self.add_noop_all_ports("Idle cycle (no positive clock edge)", - inverse_address, data_zeros) - - self.add_write("W data 1 address {}".format(inverse_address), - inverse_address,data_ones,write_port) - - self.add_write("W data 0 address {} to write value".format(self.probe_address), - self.probe_address,data_zeros,write_port) - self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1 - - # This also ensures we will have a H->L transition on the next read - self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address), - inverse_address,data_zeros,read_port) - self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1 - - self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address), - self.probe_address,data_zeros,read_port) - self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1 - - def get_data_bit_column_number(self, probe_address, probe_data): - """Calculates bitline column number of data bit under test using bit position and mux size""" - if self.sram.col_addr_size>0: - col_address = int(probe_address[0:self.sram.col_addr_size],2) - else: - col_address = 0 - bl_column = int(self.sram.words_per_row*probe_data + col_address) - return bl_column - - def run_delay_simulation(self): - """ - This tries to simulate a period and checks if the result works. If - so, it returns True and the delays, slews, and powers. It - works on the trimmed netlist by default, so powers do not - include leakage of all cells. - """ - #Sanity Check - debug.check(self.period > 0, "Target simulation period non-positive") - - result = [{} for i in self.all_ports] - # Checking from not data_value to data_value - self.write_delay_stimulus() - - self.stim.run_sim() #running sim prodoces spice output file. - - for port in self.targ_read_ports: - #Parse and check the voltage measurements - bl_volt_meas_dict = {} - for mname in self.bl_volt_meas_names: - mname_port = "{}{}".format(mname,port) - volt_meas_val = parse_spice_list("timing", mname_port) - if type(volt_meas_val)!=float: - debug.error("Failed to Parse Bitline Voltage:\n\t\t{0}={1}".format(mname,volt_meas_val),1) - bl_volt_meas_dict[mname] = volt_meas_val - result[port].update(bl_volt_meas_dict) - - #Parse and check the delay measurements. Intended that one measurement will fail, save the delay that did not fail. - bl_delay_meas_dict = {} - values_added = 0 #For error checking - for mname in self.bl_delay_meas_names: #Parse - mname_port = "{}{}".format(mname,port) - delay_meas_val = parse_spice_list("timing", mname_port) - if type(delay_meas_val)==float: #Only add if value is float, do not error. - bl_delay_meas_dict[self.bl_delay_result_name] = delay_meas_val * 1e9 #convert to ns - values_added+=1 - debug.check(values_added>0, "Bitline delay measurements failed in SPICE simulation.") - debug.check(values_added<2, "Both bitlines experienced a Vth drop, check simulation results.") - result[port].update(bl_delay_meas_dict) - - # The delay is from the negative edge for our SRAM - return (True,result) - - def check_bitline_all_results(self, results): - """Checks the bitline values measured for each tested port""" - for port in self.targ_read_ports: - self.check_bitline_port_results(results[port]) - - def check_bitline_port_results(self, port_results): - """Performs three different checks for the bitline values: functionality, bitline swing from vdd, and differential bit swing""" - bl_volt, br_volt = port_results["volt_bl"], port_results["volt_br"] - self.check_functionality(bl_volt,br_volt) - self.check_swing_from_vdd(bl_volt,br_volt) - self.check_differential_swing(bl_volt,br_volt) - - def check_functionality(self, bl_volt, br_volt): - """Checks whether the read failed or not. Measured values are hardcoded with the intention of reading a 0.""" - if bl_volt > br_volt: - debug.error("Read failure. Value 1 was read instead of 0.",1) - - def check_swing_from_vdd(self, bl_volt, br_volt): - """Checks difference on discharging bitline from VDD to see if it is within margin of the RBL height parameter.""" - if bl_volt < br_volt: - discharge_volt = bl_volt - else: - discharge_volt = br_volt - desired_bl_volt = tech.parameter["rbl_height_percentage"]*self.vdd_voltage - debug.info(1, "Active bitline={:.3f}v, Desired bitline={:.3f}v".format(discharge_volt,desired_bl_volt)) - vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now. - if abs(discharge_volt - desired_bl_volt) > vdd_error_margin*self.vdd_voltage: - debug.warning("Bitline voltage is not within {}% Vdd margin. Delay chain/RBL could need resizing.".format(vdd_error_margin*100)) - - def check_differential_swing(self, bl_volt, br_volt): - """This check looks at the difference between the bitline voltages. This needs to be large enough to prevent - sensing errors.""" - bitline_swing = abs(bl_volt-br_volt) - debug.info(1,"Bitline swing={:.3f}v".format(bitline_swing)) - vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now. - if bitline_swing < vdd_error_margin*self.vdd_voltage: - debug.warning("Bitline swing less than {}% Vdd margin. Sensing errors more likely to occur.".format(vdd_error_margin)) - - def analyze(self, probe_address, probe_data, slews, loads): - """Measures the bitline swing of the differential bitlines (bl/br) at 50% s_en """ - self.set_probe(probe_address, probe_data) - self.load=max(loads) - self.slew=max(slews) - - read_port = self.read_ports[0] #only test the first read port - bitline_swings = {} - self.targ_read_ports = [read_port] - self.targ_write_ports = [self.write_ports[0]] - debug.info(1,"Bitline swing test: corner {}".format(self.corner)) - (success, results)=self.run_delay_simulation() - debug.check(success, "Bitline Failed: period {}".format(self.period)) - debug.info(1,"Bitline values (voltages/delays):\n\t {}".format(results[read_port])) - self.check_bitline_all_results(results) - - return results - - - diff --git a/compiler/characterizer/charutils.py b/compiler/characterizer/charutils.py index 7081ff85..fa49b1ed 100644 --- a/compiler/characterizer/charutils.py +++ b/compiler/characterizer/charutils.py @@ -1,15 +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. +# 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 re import debug from globals import OPTS - + def relative_compare(value1,value2,error_tolerance=0.001): """ This is used to compare relative values for convergence. """ return (abs(value1 - value2) / abs(max(value1,value2)) <= error_tolerance) @@ -32,7 +32,6 @@ def parse_spice_list(filename, key): f.close() # val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents) val = re.search(r"{0}\s*=\s*(-?\d+.?\d*[e]?[-+]?[0-9]*\S*)\s+.*".format(key), contents) - if val != None: debug.info(4, "Key = " + key + " Val = " + val.group(1)) return convert_to_float(val.group(1)) @@ -93,4 +92,4 @@ def check_dict_values_is_float(dict): for key, value in dict.items(): if type(value)!=float: return False - return True \ No newline at end of file + return True diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 05c8862f..7a905b11 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -1,25 +1,30 @@ # 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. +# 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 sys,re,shutil,copy import debug import tech import math from .stimuli import * from .trim_spice import * from .charutils import * +from .sram_op import * +from .bit_polarity import * import utils from globals import OPTS from .simulation import simulation from .measurements import * import logical_effort +import graph_util +from sram_factory import factory class delay(simulation): - """Functions to measure the delay and power of an SRAM at a given address and + """ + Functions to measure the delay and power of an SRAM at a given address and data bit. In general, this will perform the following actions: @@ -38,113 +43,323 @@ class delay(simulation): def __init__(self, sram, spfile, corner): simulation.__init__(self, sram, spfile, corner) - # These are the member variables for a simulation self.targ_read_ports = [] self.targ_write_ports = [] self.period = 0 + if self.write_size: + self.num_wmasks = int(self.word_size / self.write_size) + else: + self.num_wmasks = 0 self.set_load_slew(0,0) self.set_corner(corner) + self.create_signal_names() + self.add_graph_exclusions() def create_measurement_names(self): - """Create measurement names. The names themselves currently define the type of measurement""" - #Altering the names will crash the characterizer. TODO: object orientated approach to the measurements. + """ Create measurement names. The names themselves currently define the type of measurement """ + self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"] self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"] - #self.voltage_when_names = ["volt_bl", "volt_br"] - #self.bitline_delay_names = ["delay_bl", "delay_br"] + # self.voltage_when_names = ["volt_bl", "volt_br"] + # self.bitline_delay_names = ["delay_bl", "delay_br"] def create_measurement_objects(self): - """Create the measurements used for read and write ports""" - self.create_read_port_measurement_objects() - self.create_write_port_measurement_objects() - + """ Create the measurements used for read and write ports """ + + self.read_meas_lists = self.create_read_port_measurement_objects() + self.write_meas_lists = self.create_write_port_measurement_objects() + self.check_meas_names(self.read_meas_lists+self.write_meas_lists) + + def check_meas_names(self, measures_lists): + """ + Given measurements (in 2d list), checks that their names are unique. + Spice sim will fail otherwise. + """ + name_set = set() + for meas_list in measures_lists: + for meas in meas_list: + name = meas.name.lower() + debug.check(name not in name_set,("SPICE measurements must have unique names. " + "Duplicate name={}").format(name)) + name_set.add(name) + def create_read_port_measurement_objects(self): """Create the measurements used for read ports: delays, slews, powers""" - - self.read_meas_objs = [] - trig_delay_name = "clk{0}" - targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit - self.read_meas_objs.append(delay_measure("delay_lh", trig_delay_name, targ_name, "RISE", "RISE", measure_scale=1e9)) - self.read_meas_objs[-1].meta_str = "read1" #Used to index time delay values when measurements written to spice file. - self.read_meas_objs.append(delay_measure("delay_hl", trig_delay_name, targ_name, "FALL", "FALL", measure_scale=1e9)) - self.read_meas_objs[-1].meta_str = "read0" - - self.read_meas_objs.append(slew_measure("slew_lh", targ_name, "RISE", measure_scale=1e9)) - self.read_meas_objs[-1].meta_str = "read1" - self.read_meas_objs.append(slew_measure("slew_hl", targ_name, "FALL", measure_scale=1e9)) - self.read_meas_objs[-1].meta_str = "read0" - - self.read_meas_objs.append(power_measure("read1_power", "RISE", measure_scale=1e3)) - self.read_meas_objs[-1].meta_str = "read1" - self.read_meas_objs.append(power_measure("read0_power", "FALL", measure_scale=1e3)) - self.read_meas_objs[-1].meta_str = "read0" - - #This will later add a half-period to the spice time delay. Only for reading 0. - for obj in self.read_meas_objs: - if obj.meta_str is "read0": - obj.meta_add_delay = True - trig_name = "Xsram.s_en{}" #Sense amp enable - if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name - port_format = "" - else: - port_format = "{}" + self.read_lib_meas = [] + self.clk_frmt = "clk{0}" # Unformatted clock name + targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit + self.delay_meas = [] + self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9)) + self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file. + self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9)) + self.delay_meas[-1].meta_str = sram_op.READ_ZERO + self.read_lib_meas+=self.delay_meas - bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column) - br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column) - # self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[0], trig_name, bl_name, "RISE", .5)) - # self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[1], trig_name, br_name, "RISE", .5)) + self.slew_meas = [] + self.slew_meas.append(slew_measure("slew_lh", targ_name, "RISE", measure_scale=1e9)) + self.slew_meas[-1].meta_str = sram_op.READ_ONE + self.slew_meas.append(slew_measure("slew_hl", targ_name, "FALL", measure_scale=1e9)) + self.slew_meas[-1].meta_str = sram_op.READ_ZERO + self.read_lib_meas+=self.slew_meas - #These are read values but need to be separated for unique error checking. - self.create_bitline_delay_measurement_objects() + self.read_lib_meas.append(power_measure("read1_power", "RISE", measure_scale=1e3)) + self.read_lib_meas[-1].meta_str = sram_op.READ_ONE + self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3)) + self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO + + # This will later add a half-period to the spice time delay. Only for reading 0. + for obj in self.read_lib_meas: + if obj.meta_str is sram_op.READ_ZERO: + obj.meta_add_delay = True + + read_measures = [] + read_measures.append(self.read_lib_meas) + # Other measurements associated with the read port not included in the liberty file + read_measures.append(self.create_bitline_measurement_objects()) + read_measures.append(self.create_debug_measurement_objects()) + read_measures.append(self.create_read_bit_measures()) + + return read_measures - def create_bitline_delay_measurement_objects(self): - """Create the measurements used for bitline delay values. Due to unique error checking, these are separated from other measurements. - These measurements are only associated with read values + def create_bitline_measurement_objects(self): + """ + Create the measurements used for bitline delay values. Due to + unique error checking, these are separated from other measurements. + These measurements are only associated with read values. """ - self.bitline_delay_objs = [] - trig_name = "clk{0}" - if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name - port_format = "" - else: - port_format = "{}" - bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column) - br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column) - targ_val = (self.vdd_voltage - tech.spice["v_threshold_typical"])/self.vdd_voltage #Calculate as a percentage of vdd - targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit - # self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[0], trig_name, bl_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9)) - # self.bitline_delay_objs[-1].meta_str = "read0" - # self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[1], trig_name, br_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9)) - # self.bitline_delay_objs[-1].meta_str = "read1" - #Enforces the time delay on the bitline measurements for read0 or read1 - for obj in self.bitline_delay_objs: - obj.meta_add_delay = True + self.bitline_volt_meas = [] + + self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO", + self.bl_name)) + self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO + self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO", + self.br_name)) + self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO + + self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE", + self.bl_name)) + self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE + self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE", + self.br_name)) + self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE + return self.bitline_volt_meas def create_write_port_measurement_objects(self): """Create the measurements used for read ports: delays, slews, powers""" - self.write_meas_objs = [] + + self.write_lib_meas = [] - self.write_meas_objs.append(power_measure("write1_power", "RISE", measure_scale=1e3)) - self.write_meas_objs[-1].meta_str = "write1" - self.write_meas_objs.append(power_measure("write0_power", "FALL", measure_scale=1e3)) - self.write_meas_objs[-1].meta_str = "write0" + self.write_lib_meas.append(power_measure("write1_power", "RISE", measure_scale=1e3)) + self.write_lib_meas[-1].meta_str = sram_op.WRITE_ONE + self.write_lib_meas.append(power_measure("write0_power", "FALL", measure_scale=1e3)) + self.write_lib_meas[-1].meta_str = sram_op.WRITE_ZERO + + write_measures = [] + write_measures.append(self.write_lib_meas) + write_measures.append(self.create_write_bit_measures()) + return write_measures + + def create_debug_measurement_objects(self): + """Create debug measurement to help identify failures.""" + + self.dout_volt_meas = [] + for meas in self.delay_meas: + # Output voltage measures + self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name), + meas.targ_name_no_port)) + self.dout_volt_meas[-1].meta_str = meas.meta_str + + self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9) + self.sen_meas.meta_str = sram_op.READ_ZERO + self.sen_meas.meta_add_delay = True + + return self.dout_volt_meas+[self.sen_meas] - def create_signal_names(self): - self.addr_name = "A" - self.din_name = "DIN" - self.dout_name = "DOUT" + def create_read_bit_measures(self): + """ Adds bit measurements for read0 and read1 cycles """ - #This is TODO once multiport control has been finalized. - #self.control_name = "CSB" + self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} + meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE) + for cycle in meas_cycles: + meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) + single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) + for polarity,meas in single_bit_meas.items(): + meas.meta_str = cycle + self.bit_meas[polarity].append(meas) + # Dictionary values are lists, reduce to a single list of measurements + return [meas for meas_list in self.bit_meas.values() for meas in meas_list] + + def create_write_bit_measures(self): + """ Adds bit measurements for write0 and write1 cycles """ + self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} + meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE) + for cycle in meas_cycles: + meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) + single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) + for polarity,meas in single_bit_meas.items(): + meas.meta_str = cycle + self.bit_meas[polarity].append(meas) + # Dictionary values are lists, reduce to a single list of measurements + return [meas for meas_list in self.bit_meas.values() for meas in meas_list] + + def get_bit_measures(self, meas_tag, probe_address, probe_data): + """ + Creates measurements for the q/qbar of input bit position. + meas_tag is a unique identifier for the measurement. + """ + + bit_col = self.get_data_bit_column_number(probe_address, probe_data) + bit_row = self.get_address_row_number(probe_address) + (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col) + 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]) + + # Bit measures, measurements times to be defined later. The measurement names must be unique + # but they is enforced externally + q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False) + qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name, has_port=False) + + return {bit_polarity.NONINVERTING:q_meas, bit_polarity.INVERTING:qbar_meas} + def set_load_slew(self,load,slew): """ Set the load and slew """ + self.load = load self.slew = slew + 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() + + def create_graph(self): + """Creates timing graph to generate the timing paths for the SRAM output.""" + + self.sram.bank.bitcell_array.bitcell_array.init_graph_params() # Removes previous bit exclusions + self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column) + + # 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) + + def set_internal_spice_names(self): + """Sets important names for characterization such as Sense amp enable and internal bit nets.""" + + port = self.read_ports[0] + self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + + 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)) + + 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 + + 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_primary_cell_mod(self, cell_mods): + """ + Distinguish bitcell array mod from replica bitline array. + Assume there are no replica bitcells in the primary array. + """ + if len(cell_mods) == 1: + return cell_mods[0] + rbc_mods = factory.get_mods(OPTS.replica_bitcell) + non_rbc_mods = [] + for bitcell in cell_mods: + has_cell = False + for replica_cell in rbc_mods: + has_cell = has_cell or replica_cell.contains(bitcell, replica_cell.mods) + if not has_cell: + non_rbc_mods.append(bitcell) + if len(non_rbc_mods) != 1: + debug.error('Multiple bitcell mods found. Cannot distinguish for characterization',1) + return non_rbc_mods[0] + + def are_mod_pins_equal(self, mods): + """Determines if there are pins differences in the input mods""" + + if len(mods) == 0: + return True + pins = mods[0].pins + for mod in mods[1:]: + if pins != mod.pins: + return False + return True + + 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 + def check_arguments(self): """Checks if arguments given for write_stimulus() meets requirements""" + try: int(self.probe_address, 2) except ValueError: @@ -156,7 +371,7 @@ class delay(simulation): if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0: debug.error("Given probe_data is not an integer to specify a data bit",1) - #Adding port options here which the characterizer cannot handle. Some may be added later like ROM + # Adding port options here which the characterizer cannot handle. Some may be added later like ROM if len(self.read_ports) == 0: debug.error("Characterizer does not currently support SRAMs without read ports.",1) if len(self.write_ports) == 0: @@ -171,12 +386,8 @@ class delay(simulation): # instantiate the sram self.sf.write("\n* Instantiation of the SRAM\n") - self.stim.inst_sram(sram=self.sram, - port_signal_names=(self.addr_name,self.din_name,self.dout_name), - port_info=(len(self.all_ports),self.write_ports,self.read_ports), - abits=self.addr_size, - dbits=self.word_size, - sram_name=self.name) + self.stim.inst_model(pins=self.pins, + model_name=self.sram.name) self.sf.write("\n* SRAM output loads\n") for port in self.read_ports: for i in range(self.word_size): @@ -184,10 +395,12 @@ class delay(simulation): def write_delay_stimulus(self): - """ Creates a stimulus file for simulations to probe a bitcell at a given clock period. + """ + Creates a stimulus file for simulations to probe a bitcell at a given clock period. Address and bit were previously set with set_probe(). Input slew (in ns) and output capacitive load (in fF) are required for charaterization. """ + self.check_arguments() # obtains list of time-points for each rising clk edge @@ -282,30 +495,47 @@ class delay(simulation): self.sf.close() - def get_read_measure_variants(self, port, measure_obj): - """Checks the measurement object and calls respective function for related measurement inputs.""" + def get_measure_variants(self, port, measure_obj, measure_type=None): + """ + Checks the measurement object and calls respective function for + related measurement inputs. + """ + meas_type = type(measure_obj) if meas_type is delay_measure or meas_type is slew_measure: - return self.get_delay_measure_variants(port, measure_obj) + variant_tuple = self.get_delay_measure_variants(port, measure_obj) elif meas_type is power_measure: - return self.get_power_measure_variants(port, measure_obj, "read") + variant_tuple = self.get_power_measure_variants(port, measure_obj, measure_type) elif meas_type is voltage_when_measure: - return self.get_volt_when_measure_variants(port, measure_obj) + variant_tuple = self.get_volt_when_measure_variants(port, measure_obj) + elif meas_type is voltage_at_measure: + variant_tuple = self.get_volt_at_measure_variants(port, measure_obj) else: debug.error("Input function not defined for measurement type={}".format(meas_type)) - + # Removes port input from any object which does not use it. This shorthand only works if + # the measurement has port as the last input. Could be implemented by measurement type or + # remove entirely from measurement classes. + if not measure_obj.has_port: + variant_tuple = variant_tuple[:-1] + return variant_tuple + def get_delay_measure_variants(self, port, delay_obj): - """Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)""" - #Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port - #vdd is arguably constant as that is true for a single lib file. - if delay_obj.meta_str == "read0": - #Falling delay are measured starting from neg. clk edge. Delay adjusted to that. + """ + Get the measurement values that can either vary from simulation to + simulation (vdd, address) or port to port (time delays) + """ + + # Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port + # vdd is arguably constant as that is true for a single lib file. + if delay_obj.meta_str == sram_op.READ_ZERO: + # Falling delay are measured starting from neg. clk edge. Delay adjusted to that. meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]] - elif delay_obj.meta_str == "read1": + elif delay_obj.meta_str == sram_op.READ_ONE: meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]] else: debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1) + # These measurements have there time further delayed to the neg. edge of the clock. if delay_obj.meta_add_delay: meas_cycle_delay += self.period/2 @@ -313,16 +543,33 @@ class delay(simulation): def get_power_measure_variants(self, port, power_obj, operation): """Get the measurement values that can either vary port to port (time delays)""" - #Return value is intended to match the power measure format: t_initial, t_final, port + + # Return value is intended to match the power measure format: t_initial, t_final, port t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]] t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1] return (t_initial, t_final, port) - def get_volt_when_measure_variants(self, port, power_obj): - """Get the measurement values that can either vary port to port (time delays)""" - #Only checking 0 value reads for now. - t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]] + def get_volt_at_measure_variants(self, port, volt_meas): + """ + Get the measurement values that can either vary port to port (time delays) + """ + + meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]] + + # Measurement occurs slightly into the next period so we know that the value + # "stuck" after the end of the period -> current period start + 1.25*period + at_time = meas_cycle+1.25*self.period + + return (at_time, port) + + def get_volt_when_measure_variants(self, port, volt_meas): + """ + Get the measurement values that can either vary port to port (time delays) + """ + + # Only checking 0 value reads for now. + t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]] return (t_trig, self.vdd_voltage, port) @@ -330,43 +577,45 @@ class delay(simulation): """ Write the measure statements to quantify the delay and power results for a read port. """ + # add measure statements for delays/slews - for measure in self.read_meas_objs+self.bitline_delay_objs: - measure_variant_inp_tuple = self.get_read_measure_variants(port, measure) - measure.write_measure(self.stim, measure_variant_inp_tuple) + for meas_list in self.read_meas_lists: + for measure in meas_list: + measure_variant_inp_tuple = self.get_measure_variants(port, measure, "read") + measure.write_measure(self.stim, measure_variant_inp_tuple) - def get_write_measure_variants(self, port, measure_obj): - """Checks the measurement object and calls respective function for related measurement inputs.""" - meas_type = type(measure_obj) - if meas_type is power_measure: - return self.get_power_measure_variants(port, measure_obj, "write") - else: - debug.error("Input function not defined for measurement type={}".format(meas_type)) def write_delay_measures_write_port(self, port): """ Write the measure statements to quantify the power results for a write port. """ + # add measure statements for power - for measure in self.write_meas_objs: - measure_variant_inp_tuple = self.get_write_measure_variants(port, measure) - measure.write_measure(self.stim, measure_variant_inp_tuple) + for meas_list in self.write_meas_lists: + for measure in meas_list: + measure_variant_inp_tuple = self.get_measure_variants(port, measure, "write") + measure.write_measure(self.stim, measure_variant_inp_tuple) def write_delay_measures(self): """ Write the measure statements to quantify the delay and power results for all targeted ports. """ + self.sf.write("\n* Measure statements for delay and power\n") # Output some comments to aid where cycles start and # what is happening for comment in self.cycle_comments: self.sf.write("* {}\n".format(comment)) - + + self.sf.write("\n") for read_port in self.targ_read_ports: - self.write_delay_measures_read_port(read_port) + self.sf.write("* Read ports {}\n".format(read_port)) + self.write_delay_measures_read_port(read_port) + for write_port in self.targ_write_ports: - self.write_delay_measures_write_port(write_port) + self.sf.write("* Write ports {}\n".format(write_port)) + self.write_delay_measures_write_port(write_port) def write_power_measures(self): @@ -400,35 +649,36 @@ class delay(simulation): if (time_out <= 0): debug.error("Timed out, could not find a feasible period.",2) - #Clear any write target ports and set read port - self.targ_write_ports = [] + # Clear any write target ports and set read port + self.targ_write_ports = [port] self.targ_read_ports = [port] - success = False debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port)) self.period = feasible_period (success, results)=self.run_delay_simulation() - #Clear these target ports after simulation + + # Clear these target ports after simulation + self.targ_write_ports = [] self.targ_read_ports = [] if not success: feasible_period = 2 * feasible_period continue - #Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews + # Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname] feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname] delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays) slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews) debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period, - delay_str, - slew_str, - port)) + delay_str, + slew_str, + port)) if success: debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period)) self.period = feasible_period - #Only return results related to input port. + # Only return results related to input port. return results[port] def find_feasible_period(self): @@ -438,19 +688,19 @@ class delay(simulation): """ feasible_delays = [{} for i in self.all_ports] - #Get initial feasible delays from first port + # Get initial feasible delays from first port feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0]) previous_period = self.period - #Loops through all the ports checks if the feasible period works. Everything restarts it if does not. - #Write ports do not produce delays which is why they are not included here. + # Loops through all the ports checks if the feasible period works. Everything restarts it if does not. + # Write ports do not produce delays which is why they are not included here. i = 1 while i < len(self.read_ports): port = self.read_ports[i] - #Only extract port values from the specified port, not the entire results. + # Only extract port values from the specified port, not the entire results. feasible_delays[port].update(self.find_feasible_period_one_port(port)) - #Function sets the period. Restart the entire process if period changes to collect accurate delays + # Function sets the period. Restart the entire process if period changes to collect accurate delays if self.period > previous_period: i = 0 else: @@ -466,71 +716,174 @@ class delay(simulation): works on the trimmed netlist by default, so powers do not include leakage of all cells. """ - #Sanity Check + debug.check(self.period > 0, "Target simulation period non-positive") - result = [{} for i in self.all_ports] - # Checking from not data_value to data_value self.write_delay_stimulus() self.stim.run_sim() + + return self.check_measurements() + + def check_measurements(self): + """ Check the write and read measurements """ - #Loop through all targeted ports and collect delays and powers. - #Too much duplicate code here. Try reducing - for port in self.targ_read_ports: - debug.info(2, "Check delay values for port {}".format(port)) - read_port_dict = {} - #Get measurements from output file - for measure in self.read_meas_objs: - read_port_dict[measure.name] = measure.retrieve_measure(port=port) - - #Check timing for read ports. Power is only checked if it was read correctly - if not self.check_valid_delays(read_port_dict): - return (False,{}) - if not check_dict_values_is_float(read_port_dict): - debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) #Printing the entire dict looks bad. - - result[port].update(read_port_dict) - - bitline_delay_dict = self.evaluate_bitline_delay(port) - result[port].update(bitline_delay_dict) - + # Loop through all targeted ports and collect delays and powers. + result = [{} for i in self.all_ports] + + + # First, check that the memory has the right values at the right times + if not self.check_bit_measures(): + return(False,{}) + for port in self.targ_write_ports: + debug.info(2, "Checking write values for port {}".format(port)) write_port_dict = {} - for measure in self.write_meas_objs: + for measure in self.write_lib_meas: write_port_dict[measure.name] = measure.retrieve_measure(port=port) if not check_dict_values_is_float(write_port_dict): - debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) #Printing the entire dict looks bad. + debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) result[port].update(write_port_dict) - # The delay is from the negative edge for our SRAM + + for port in self.targ_read_ports: + debug.info(2, "Checking read delay values for port {}".format(port)) + # Check sen timing, then bitlines, then general measurements. + if not self.check_sen_measure(port): + return (False,{}) + + if not self.check_read_debug_measures(port): + return (False,{}) + + # Check timing for read ports. Power is only checked if it was read correctly + read_port_dict = {} + for measure in self.read_lib_meas: + read_port_dict[measure.name] = measure.retrieve_measure(port=port) + + if not self.check_valid_delays(read_port_dict): + return (False,{}) + + if not check_dict_values_is_float(read_port_dict): + debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) + + result[port].update(read_port_dict) + return (True,result) - def evaluate_bitline_delay(self, port): - """Parse and check the bitline delay. One of the measurements is expected to fail which warrants its own function.""" - bl_delay_meas_dict = {} - values_added = 0 #For error checking - for measure in self.bitline_delay_objs: - bl_delay_val = measure.retrieve_measure(port=port) - if type(bl_delay_val) != float or 0 > bl_delay_val or bl_delay_val > self.period/2: #Only add if value is valid, do not error. - debug.error("Bitline delay measurement failed: half-period={}, {}={}".format(self.period/2, measure.name, bl_delay_val),1) - bl_delay_meas_dict[measure.name] = bl_delay_val - return bl_delay_meas_dict + def check_sen_measure(self, port): + """Checks that the sen occurred within a half-period""" + + sen_val = self.sen_meas.retrieve_measure(port=port) + debug.info(2,"s_en delay={}ns".format(sen_val)) + if self.sen_meas.meta_add_delay: + max_delay = self.period/2 + else: + max_delay = self.period + return not (type(sen_val) != float or sen_val > max_delay) + + + def check_read_debug_measures(self, port): + """Debug measures that indicate special conditions.""" + + # Currently, only check if the opposite than intended value was read during + # the read cycles i.e. neither of these measurements should pass. + # FIXME: these checks need to be re-done to be more robust against possible errors + bl_vals = {} + br_vals = {} + for meas in self.bitline_volt_meas: + val = meas.retrieve_measure(port=port) + if self.bl_name == meas.targ_name_no_port: + bl_vals[meas.meta_str] = val + elif self.br_name == meas.targ_name_no_port: + br_vals[meas.meta_str] = val + + debug.info(2,"{}={}".format(meas.name,val)) + + dout_success = True + bl_success = False + for meas in self.dout_volt_meas: + val = meas.retrieve_measure(port=port) + debug.info(2,"{}={}".format(meas.name, val)) + debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name,val)) + + if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1: + dout_success = False + debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val)) + bl_success = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE]) + elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9: + dout_success = False + debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val)) + bl_success = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE]) + + # If the bitlines have a correct value while the output does not then that is a + # sen error. FIXME: there are other checks that can be done to solidfy this conclusion. + if not dout_success and bl_success: + debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1) + + return dout_success + + + def check_bit_measures(self): + """ + Checks the measurements which represent the internal storage voltages + at the end of the read cycle. + """ + success = False + for polarity, meas_list in self.bit_meas.items(): + for meas in meas_list: + val = meas.retrieve_measure() + debug.info(2,"{}={}".format(meas.name, val)) + if type(val) != float: + continue + meas_cycle = meas.meta_str + # Loose error conditions. Assume it's not metastable but account for noise during reads. + if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\ + (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING): + success = val < self.vdd_voltage/2 + elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\ + (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING): + success = val > self.vdd_voltage/2 + elif (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.INVERTING) or\ + (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.NONINVERTING): + success = val > self.vdd_voltage/2 + elif (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.INVERTING) or\ + (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.NONINVERTING): + success = val < self.vdd_voltage/2 + if not success: + debug.info(1,("Wrong value detected on probe bit during read/write cycle. " + "Check writes and control logic for bugs.\n measure={}, op={}, " + "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val)) + + return success + + def check_bitline_meas(self, v_discharged_bl, v_charged_bl): + """ + Checks the value of the discharging bitline. Confirms s_en timing errors. + Returns true if the bitlines are at there expected value. + """ + # The inputs looks at discharge/charged bitline rather than left or right (bl/br) + # Performs two checks, discharging bitline is at least 10% away from vdd and there is a + # 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error. + min_dicharge = v_discharged_bl < self.vdd_voltage*0.9 + min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage*0.1 + + debug.info(1,"min_dicharge={}, min_diff={}".format(min_dicharge,min_diff)) + return (min_dicharge and min_diff) def run_power_simulation(self): """ This simulates a disabled SRAM to get the leakage power when it is off. - """ + debug.info(1, "Performing leakage power simulations.") self.write_power_stimulus(trim=False) self.stim.run_sim() leakage_power=parse_spice_list("timing", "leakage_power") debug.check(leakage_power!="Failed","Could not measure leakage power.") debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power*1e3)) - #debug - #sys.exit(1) + # debug + # sys.exit(1) self.write_power_stimulus(trim=True) self.stim.run_sim() @@ -539,12 +892,13 @@ class delay(simulation): debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power*1e3)) # For debug, you sometimes want to inspect each simulation. - #key=raw_input("press return to continue") + # key=raw_input("press return to continue") return (leakage_power*1e3, trim_leakage_power*1e3) def check_valid_delays(self, result_dict): """ Check if the measurements are defined and if they are valid. """ - #Hard coded names currently + + # Hard coded names currently delay_hl = result_dict["delay_hl"] delay_lh = result_dict["delay_lh"] slew_hl = result_dict["slew_hl"] @@ -562,8 +916,9 @@ class delay(simulation): delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh) slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh) - half_period = self.period/2 #high-to-low delays start at neg. clk edge, so they need to be less than half_period - if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period: + half_period = self.period/2 # high-to-low delays start at neg. clk edge, so they need to be less than half_period + if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ + or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0: debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, delays_str, slews_str)) @@ -584,15 +939,15 @@ class delay(simulation): lb_period = 0.0 target_period = 0.5 * (ub_period + lb_period) - #Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position. - #For testing purposes, only checks read ports. + # Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position. + # For testing purposes, only checks read ports. for port in self.read_ports: target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period) - #The min period of one port becomes the new lower bound. Reset the upper_bound. + # The min period of one port becomes the new lower bound. Reset the upper_bound. lb_period = target_period ub_period = feasible_period - #Clear the target ports before leaving + # Clear the target ports before leaving self.targ_read_ports = [] self.targ_write_ports = [] return target_period @@ -603,13 +958,14 @@ class delay(simulation): long period. For the current logic to characterize multiport, bounds are required as an input. """ - #previous_period = ub_period = self.period - #ub_period = self.period - #lb_period = 0.0 - #target_period = 0.5 * (ub_period + lb_period) + # previous_period = ub_period = self.period + # ub_period = self.period + # lb_period = 0.0 + # target_period = 0.5 * (ub_period + lb_period) # Binary search algorithm to find the min period (max frequency) of input port time_out = 25 + self.targ_write_ports = [port] self.targ_read_ports = [port] while True: time_out -= 1 @@ -618,9 +974,9 @@ class delay(simulation): self.period = target_period debug.info(1, "MinPeriod Search Port {3}: {0}ns (ub: {1} lb: {2})".format(target_period, - ub_period, - lb_period, - port)) + ub_period, + lb_period, + port)) if self.try_period(feasible_delays): ub_period = target_period @@ -631,9 +987,9 @@ class delay(simulation): # ub_period is always feasible. return ub_period - #Update target + # Update target target_period = 0.5 * (ub_period + lb_period) - #key=input("press return to continue") + # key=input("press return to continue") def try_period(self, feasible_delays): @@ -641,18 +997,20 @@ class delay(simulation): This tries to simulate a period and checks if the result works. If it does and the delay is within 5% still, it returns True. """ + # Run Delay simulation but Power results not used. (success, results) = self.run_delay_simulation() if not success: return False - #Check the values of target readwrite and read ports. Write ports do not produce delays in this current version - for port in self.targ_read_ports: - for dname in self.delay_meas_names: #check that the delays and slews do not degrade with tested period. + # Check the values of target readwrite and read ports. Write ports do not produce delays in this current version + for port in self.targ_read_ports: + # check that the delays and slews do not degrade with tested period. + for dname in self.delay_meas_names: - #FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there - #is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist. - #Delays/slews based on the period will cause the min_period search to come to the wrong period. + # FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there + # is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist. + # Delays/slews based on the period will cause the min_period search to come to the wrong period. if self.sram.col_addr_size>0 and "slew" in dname: continue @@ -660,9 +1018,8 @@ class delay(simulation): debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname])) return False - #key=raw_input("press return to continue") + # key=raw_input("press return to continue") - #Dynamic way to build string. A bit messy though. delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names) debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period, delay_str, @@ -670,8 +1027,11 @@ class delay(simulation): return True def set_probe(self,probe_address, probe_data): - """ Probe address and data can be set separately to utilize other - functions in this characterizer besides analyze.""" + """ + Probe address and data can be set separately to utilize other + functions in this characterizer besides analyze. + """ + self.probe_address = probe_address self.probe_data = probe_data self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data) @@ -680,6 +1040,7 @@ class delay(simulation): def get_data_bit_column_number(self, probe_address, probe_data): """Calculates bitline column number of data bit under test using bit position and mux size""" + if self.sram.col_addr_size>0: col_address = int(probe_address[0:self.sram.col_addr_size],2) else: @@ -689,6 +1050,7 @@ class delay(simulation): def get_address_row_number(self, probe_address): """Calculates wordline row number of data bit under test using address and column mux size""" + return int(probe_address[self.sram.col_addr_size:],2) def prepare_netlist(self): @@ -712,31 +1074,26 @@ class delay(simulation): # Make a copy in temp for debugging shutil.copy(self.sp_file, self.sim_sp_file) - - - def analyze(self,probe_address, probe_data, slews, loads): - """ - Main function to characterize an SRAM for a table. Computes both delay and power characterization. - """ - #Dict to hold all characterization values - char_sram_data = {} + def analysis_init(self, probe_address, probe_data): + """Sets values which are dependent on the data address/bit being tested.""" self.set_probe(probe_address, probe_data) - self.create_signal_names() + self.create_graph() + self.set_internal_spice_names() self.create_measurement_names() self.create_measurement_objects() + def analyze(self, probe_address, probe_data, slews, loads): + """ + Main function to characterize an SRAM for a table. Computes both delay and power characterization. + """ + + # Dict to hold all characterization values + char_sram_data = {} + self.analysis_init(probe_address, probe_data) + self.load=max(loads) self.slew=max(slews) - # This is for debugging a full simulation - # debug.info(0,"Debug simulation running...") - # target_period=50.0 - # feasible_delay_lh=0.059083183 - # feasible_delay_hl=0.17953789 - # load=1.6728 - # slew=0.04 - # self.try_period(target_period, feasible_delay_lh, feasible_delay_hl) - # sys.exit(1) # 1) Find a feasible period and it's corresponding delays using the trimmed array. feasible_delays = self.find_feasible_period() @@ -756,22 +1113,24 @@ class delay(simulation): self.period = min_period char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset) - #FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate. + # FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate. self.alter_lh_char_data(char_port_data) return (char_sram_data, char_port_data) def alter_lh_char_data(self, char_port_data): """Copies high-to-low data to low-to-high data to make them consistent on the same clock edge.""" - #This is basically a hack solution which should be removed/fixed later. + + # This is basically a hack solution which should be removed/fixed later. for port in self.all_ports: char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl'] char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl'] def simulate_loads_and_slews(self, slews, loads, leakage_offset): """Simulate all specified output loads and input slews pairs of all ports""" + measure_data = self.get_empty_measure_data_dict() - #Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. + # Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. self.targ_read_ports = self.read_ports self.targ_write_ports = self.write_ports for slew in slews: @@ -781,7 +1140,7 @@ class delay(simulation): (success, delay_results) = self.run_delay_simulation() debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load)) - #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). + # The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). for port in self.all_ports: for mname,value in delay_results[port].items(): if "power" in mname: @@ -793,11 +1152,12 @@ class delay(simulation): def calculate_inverse_address(self): """Determine dummy test address based on probe address and column mux size.""" - #The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines - #This is only an issue when there is a column mux and the address maps to different bitlines. - column_addr = self.probe_address[:self.sram.col_addr_size] #do not invert this part + + # The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines + # This is only an issue when there is a column mux and the address maps to different bitlines. + column_addr = self.probe_address[:self.sram.col_addr_size] # do not invert this part inverse_address = "" - for c in self.probe_address[self.sram.col_addr_size:]: #invert everything else + for c in self.probe_address[self.sram.col_addr_size:]: # invert everything else if c=="0": inverse_address += "1" elif c=="1": @@ -816,48 +1176,51 @@ class delay(simulation): # For now, ignore data patterns and write ones or zeros data_ones = "1"*self.word_size data_zeros = "0"*self.word_size + wmask_ones = "1"*self.num_wmasks + wmask_zeroes = "0"*self.num_wmasks if self.t_current == 0: self.add_noop_all_ports("Idle cycle (no positive clock edge)", - inverse_address, data_zeros) + inverse_address, data_zeros,wmask_zeroes) self.add_write("W data 1 address {}".format(inverse_address), - inverse_address,data_ones,write_port) + inverse_address,data_ones,wmask_ones,write_port) self.add_write("W data 0 address {} to write value".format(self.probe_address), - self.probe_address,data_zeros,write_port) - self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1 + self.probe_address,data_zeros,wmask_ones,write_port) + self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1 # This also ensures we will have a H->L transition on the next read - self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address), - inverse_address,data_zeros,read_port) + self.add_read("R data 1 address {} to set dout caps".format(inverse_address), + inverse_address,data_zeros,wmask_ones,read_port) self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address), - self.probe_address,data_zeros,read_port) - self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1 + self.probe_address,data_zeros,wmask_ones,read_port) + self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1 self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)", - inverse_address,data_zeros) + inverse_address,data_zeros,wmask_zeroes) self.add_write("W data 1 address {} to write value".format(self.probe_address), - self.probe_address,data_ones,write_port) - self.measure_cycles[write_port]["write1"] = len(self.cycle_times)-1 + self.probe_address,data_ones,wmask_ones,write_port) + self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1 - self.add_write("W data 0 address {} to clear DIN caps".format(inverse_address), - inverse_address,data_zeros,write_port) + self.add_write("W data 0 address {} to clear din caps".format(inverse_address), + inverse_address,data_zeros,wmask_ones,write_port) # This also ensures we will have a L->H transition on the next read - self.add_read("R data 0 address {} to clear DOUT caps".format(inverse_address), - inverse_address,data_zeros,read_port) + self.add_read("R data 0 address {} to clear dout caps".format(inverse_address), + inverse_address,data_zeros,wmask_ones,read_port) self.add_read("R data 1 address {} to check W1 worked".format(self.probe_address), - self.probe_address,data_zeros,read_port) - self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1 + self.probe_address,data_zeros,wmask_ones,read_port) + self.measure_cycles[read_port][sram_op.READ_ONE] = len(self.cycle_times)-1 self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))", - self.probe_address,data_zeros) + self.probe_address,data_zeros,wmask_zeroes) def get_available_port(self,get_read_port): + """Returns the first accessible read or write port. """ if get_read_port and len(self.read_ports) > 0: return self.read_ports[0] @@ -870,29 +1233,32 @@ class delay(simulation): self.measure_cycles = [{} for port in self.all_ports] def create_test_cycles(self): - """Returns a list of key time-points [ns] of the waveform (each rising edge) + """ + Returns a list of key time-points [ns] of the waveform (each rising edge) of the cycles to do a timing evaluation. The last time is the end of the simulation - and does not need a rising edge.""" - #Using this requires setting at least one port to target for simulation. + and does not need a rising edge. + """ + + # Using this requires setting at least one port to target for simulation. if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: debug.error("No port selected for characterization.",1) self.set_stimulus_variables() - #Get any available read/write port in case only a single write or read ports is being characterized. + # Get any available read/write port in case only a single write or read ports is being characterized. cur_read_port = self.get_available_port(get_read_port=True) cur_write_port = self.get_available_port(get_read_port=False) debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") - #Create test cycles for specified target ports. + # Create test cycles for specified target ports. write_pos = 0 read_pos = 0 while True: - #Exit when all ports have been characterized + # Exit when all ports have been characterized if write_pos >= len(self.targ_write_ports) and read_pos >= len(self.targ_read_ports): break - #Select new write and/or read ports for the next cycle. Use previous port if none remaining. + # Select new write and/or read ports for the next cycle. Use previous port if none remaining. if write_pos < len(self.targ_write_ports): cur_write_port = self.targ_write_ports[write_pos] write_pos+=1 @@ -900,48 +1266,81 @@ class delay(simulation): cur_read_port = self.targ_read_ports[read_pos] read_pos+=1 - #Add test cycle of read/write port pair. One port could have been used already, but the other has not. + # Add test cycle of read/write port pair. One port could have been used already, but the other has not. self.gen_test_cycles_one_port(cur_read_port, cur_write_port) + def sum_delays(self, delays): + """Adds the delays (delay_data objects) so the correct slew is maintained""" + + delay = delays[0] + for i in range(1, len(delays)): + delay+=delays[i] + return delay + def analytical_delay(self, slews, loads): - """ Return the analytical model results for the SRAM. + """ + Return the analytical model results for the SRAM. """ if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0: debug.warning("Analytical characterization results are not supported for multiport.") - self.create_signal_names() + + # Probe set to 0th bit, does not matter for analytical delay. + self.set_probe('0', 0) + self.create_graph() + self.set_internal_spice_names() self.create_measurement_names() - power = self.analytical_power(slews, loads) + + port = self.read_ports[0] + self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + + # Select the path with the bitline (bl) + bl_name,br_name = self.get_bl_name(self.graph.all_paths, port) + bl_path = [path for path in self.graph.all_paths if bl_name in path][0] + + # Set delay/power for slews and loads port_data = self.get_empty_measure_data_dict() - relative_loads = [logical_effort.convert_farad_to_relative_c(c_farad) for c_farad in loads] + power = self.analytical_power(slews, loads) + debug.info(1,'Slew, Load, Delay(ns), Slew(ns)') + max_delay = 0.0 for slew in slews: - for load in relative_loads: - self.set_load_slew(load,slew) - bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load) + for load in loads: + # Calculate delay based on slew and load + path_delays = self.graph.get_timing(bl_path, self.corner, slew, load) + + total_delay = self.sum_delays(path_delays) + max_delay = max(max_delay, total_delay.delay) + debug.info(1,'{}, {}, {}, {}'.format(slew,load,total_delay.delay/1e3, total_delay.slew/1e3)) + + # Delay is only calculated on a single port and replicated for now. for port in self.all_ports: for mname in self.delay_meas_names+self.power_meas_names: if "power" in mname: port_data[port][mname].append(power.dynamic) - elif "delay" in mname: - port_data[port][mname].append(bank_delay[port].delay/1e3) - elif "slew" in mname: - port_data[port][mname].append(bank_delay[port].slew/1e3) + elif "delay" in mname and port in self.read_ports: + port_data[port][mname].append(total_delay.delay/1e3) + elif "slew" in mname and port in self.read_ports: + port_data[port][mname].append(total_delay.slew/1e3) else: debug.error("Measurement name not recognized: {}".format(mname),1) + + # Estimate the period as double the delay with margin period_margin = 0.1 - risefall_delay = bank_delay[self.read_ports[0]].delay/1e3 - sram_data = { "min_period":risefall_delay*2*period_margin, + sram_data = { "min_period":(max_delay/1e3)*2*period_margin, "leakage_power": power.leakage} + debug.info(2,"SRAM Data:\n{}".format(sram_data)) debug.info(2,"Port Data:\n{}".format(port_data)) - return (sram_data,port_data) - + return (sram_data,port_data) + def analytical_power(self, slews, loads): """Get the dynamic and leakage power from the SRAM""" - #slews unused, only last load is used + + # slews unused, only last load is used load = loads[-1] power = self.sram.analytical_power(self.corner, load) - #convert from nW to mW + # convert from nW to mW power.dynamic /= 1e6 power.leakage /= 1e6 debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic)) @@ -950,6 +1349,7 @@ class delay(simulation): def gen_data(self): """ Generates the PWL data inputs for a simulation timing test. """ + for write_port in self.write_ports: for i in range(self.word_size): sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i) @@ -960,6 +1360,7 @@ class delay(simulation): Generates the address inputs for a simulation timing test. This alternates between all 1's and all 0's for the address. """ + for port in self.all_ports: for i in range(self.addr_size): sig_name = "{0}{1}_{2}".format(self.addr_name,port,i) @@ -967,6 +1368,7 @@ class delay(simulation): def gen_control(self): """ Generates the control signals """ + for port in self.all_ports: self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05) if port in self.readwrite_ports: @@ -975,7 +1377,8 @@ class delay(simulation): def get_empty_measure_data_dict(self): """Make a dict of lists for each type of delay and power measurement to append results to""" + measure_names = self.delay_meas_names + self.power_meas_names - #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. + # Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports] return measure_data diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index c12b6669..39dd33a2 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -1,11 +1,12 @@ # 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. +# 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 collections from design import design import debug import math @@ -15,9 +16,10 @@ from .stimuli import * from .charutils import * import utils from globals import OPTS - from .simulation import simulation from .delay import delay +import graph_util +from sram_factory import factory class functional(simulation): """ @@ -32,19 +34,38 @@ class functional(simulation): if OPTS.is_unit_test: random.seed(12345) + if self.write_size: + self.num_wmasks = int(self.word_size / self.write_size) + else: + self.num_wmasks = 0 + self.set_corner(corner) self.set_spice_constants() - #self.set_feasible_period(sram, spfile, corner) self.set_stimulus_variables() - self.create_signal_names() + # For the debug signal names + self.create_signal_names() + self.add_graph_exclusions() + self.create_graph() + self.set_internal_spice_names() + self.initialize_wmask() + # Number of checks can be changed - self.num_cycles = 2 - self.stored_words = {} + self.num_cycles = 15 + # This is to have ordered keys for random selection + self.stored_words = collections.OrderedDict() self.write_check = [] self.read_check = [] - + + + def initialize_wmask(self): + self.wmask = "" + if self.write_size: + # initialize all wmask bits to 1 + for bit in range(self.num_wmasks): + self.wmask += "1" + def run(self, feasible_period=None): if feasible_period: #period defaults to tech.py feasible period otherwise. self.period = feasible_period @@ -55,7 +76,7 @@ class functional(simulation): self.write_functional_stimulus() self.stim.run_sim() - # read DOUT values from SPICE simulation. If the values do not fall within the noise margins, return the error. + # read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error. (success, error) = self.read_stim_results() if not success: return (0, error) @@ -64,37 +85,42 @@ class functional(simulation): return self.check_stim_results() def write_random_memory_sequence(self): - rw_ops = ["noop", "write", "read"] - w_ops = ["noop", "write"] + if self.write_size: + rw_ops = ["noop", "write", "partial_write", "read"] + w_ops = ["noop", "write", "partial_write"] + else: + rw_ops = ["noop", "write", "read"] + w_ops = ["noop", "write"] r_ops = ["noop", "read"] rw_read_din_data = "0"*self.word_size check = 0 - + # First cycle idle - comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current) - self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size) + comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current) + self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks) # Write at least once addr = self.gen_addr() word = self.gen_data() - comment = self.gen_cycle_comment("write", word, addr, 0, self.t_current) - self.add_write(comment, addr, word, 0) + comment = self.gen_cycle_comment("write", word, addr, self.wmask, 0, self.t_current) + self.add_write(comment, addr, word, self.wmask, 0) self.stored_words[addr] = word - + # Read at least once. For multiport, it is important that one read cycle uses all RW and R port to read from the same address simultaniously. # This will test the viablilty of the transistor sizing in the bitcell. for port in self.all_ports: if port in self.write_ports: - self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port) + self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) else: - comment = self.gen_cycle_comment("read", word, addr, port, self.t_current) - self.add_read_one_port(comment, addr, rw_read_din_data, port) + comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current) + self.add_read_one_port(comment, addr, rw_read_din_data, "0"*self.num_wmasks, port) self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check]) check += 1 self.cycle_times.append(self.t_current) self.t_current += self.period # Perform a random sequence of writes and reads on random ports, using random addresses and random words + # and random write masks (if applicable) for i in range(self.num_cycles): w_addrs = [] for port in self.all_ports: @@ -108,26 +134,48 @@ class functional(simulation): if op == "noop": addr = "0"*self.addr_size word = "0"*self.word_size - self.add_noop_one_port(addr, word, port) + wmask = "0" * self.num_wmasks + self.add_noop_one_port(addr, word, wmask, port) elif op == "write": addr = self.gen_addr() word = self.gen_data() # two ports cannot write to the same address if addr in w_addrs: - self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port) + self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) else: - comment = self.gen_cycle_comment("write", word, addr, port, self.t_current) - self.add_write_one_port(comment, addr, word, port) + comment = self.gen_cycle_comment("write", word, addr, self.wmask, port, self.t_current) + self.add_write_one_port(comment, addr, word, self.wmask, port) self.stored_words[addr] = word w_addrs.append(addr) + elif op == "partial_write": + # write only to a word that's been written to + (addr,old_word) = self.get_data() + word = self.gen_data() + wmask = self.gen_wmask() + new_word = word + for bit in range(len(wmask)): + # When the write mask's bits are 0, the old data values should appear in the new word + # as to not overwrite the old values + if wmask[bit] == "0": + lower = bit * self.write_size + upper = lower + self.write_size - 1 + new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:] + # two ports cannot write to the same address + if addr in w_addrs: + self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) + else: + comment = self.gen_cycle_comment("partial_write", word, addr, wmask, port, self.t_current) + self.add_write_one_port(comment, addr, word, wmask, port) + self.stored_words[addr] = new_word + w_addrs.append(addr) else: (addr,word) = random.choice(list(self.stored_words.items())) # cannot read from an address that is currently being written to if addr in w_addrs: - self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port) + self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port) else: - comment = self.gen_cycle_comment("read", word, addr, port, self.t_current) - self.add_read_one_port(comment, addr, rw_read_din_data, port) + comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current) + self.add_read_one_port(comment, addr, rw_read_din_data, "0"*self.num_wmasks, port) self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check]) check += 1 @@ -135,11 +183,11 @@ class functional(simulation): self.t_current += self.period # Last cycle idle needed to correctly measure the value on the second to last clock edge - comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current) - self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size) + comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current) + self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks) def read_stim_results(self): - # Extrat DOUT values from spice timing.lis + # Extrat dout values from spice timing.lis for (word, dout_port, eo_period, check) in self.write_check: sp_read_value = "" for bit in range(self.word_size): @@ -170,23 +218,47 @@ class functional(simulation): self.read_check[i][2]) return(0, error) return(1, "SUCCESS") - + + def gen_wmask(self): + wmask = "" + # generate a random wmask + for bit in range(self.num_wmasks): + rand = random.randint(0, 1) + wmask += str(rand) + # prevent the wmask from having all bits on or off (this is not a partial write) + all_zeroes = True + all_ones = True + for bit in range(self.num_wmasks): + if wmask[bit]=="0": + all_ones = False + elif wmask[bit]=="1": + all_zeroes = False + if all_zeroes: + index = random.randint(0, self.num_wmasks - 1) + wmask = wmask[:index] + "1" + wmask[index + 1:] + elif all_ones: + index = random.randint(0, self.num_wmasks - 1) + wmask = wmask[:index] + "0" + wmask[index + 1:] + # wmask must be reversed since a python list goes right to left and sram bits go left to right. + return wmask[::-1] + + def gen_data(self): """ Generates a random word to write. """ - rand = random.randint(0,(2**self.word_size)-1) - data_bits = self.convert_to_bin(rand,False) + random_value = random.randint(0,(2**self.word_size)-1) + data_bits = self.convert_to_bin(random_value,False) return data_bits - + def gen_addr(self): """ Generates a random address value to write to. """ - rand = random.randint(0,(2**self.addr_size)-1) - addr_bits = self.convert_to_bin(rand,True) - return addr_bits + random_value = random.randint(0,(2**self.addr_size)-1) + addr_bits = self.convert_to_bin(random_value,True) + return addr_bits def get_data(self): """ Gets an available address and corresponding word. """ - # Currently unused but may need later depending on how the functional test develops - addr = random.choice(self.stored_words.keys()) + # Used for write masks since they should be writing to previously written addresses + addr = random.choice(list(self.stored_words.keys())) word = self.stored_words[addr] return (addr,word) @@ -196,17 +268,13 @@ class functional(simulation): if(is_addr): expected_value = self.addr_size else: + expected_value = self.word_size for i in range (expected_value - len(new_value)): new_value = "0" + new_value #print("Binary Conversion: {} to {}".format(value, new_value)) - return new_value - - def create_signal_names(self): - self.addr_name = "A" - self.din_name = "DIN" - self.dout_name = "DOUT" + return new_value def write_functional_stimulus(self): """ Writes SPICE stimulus. """ @@ -216,9 +284,7 @@ class functional(simulation): self.stim = stimuli(self.sf,self.corner) #Write include statements - self.sram_sp_file = "{}sram.sp".format(OPTS.openram_temp) - shutil.copy(self.sp_file, self.sram_sp_file) - self.stim.write_include(self.sram_sp_file) + self.stim.write_include(self.sp_file) #Write Vdd/Gnd statements self.sf.write("\n* Global Power Supplies\n") @@ -226,12 +292,8 @@ class functional(simulation): #Instantiate the SRAM self.sf.write("\n* Instantiation of the SRAM\n") - self.stim.inst_sram(sram=self.sram, - port_signal_names=(self.addr_name,self.din_name,self.dout_name), - port_info=(len(self.all_ports), self.write_ports, self.read_ports), - abits=self.addr_size, - dbits=self.word_size, - sram_name=self.name) + self.stim.inst_model(pins=self.pins, + model_name=self.sram.name) # Add load capacitance to each of the read ports self.sf.write("\n* SRAM output loads\n") @@ -239,9 +301,17 @@ class functional(simulation): for bit in range(self.word_size): 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)) + + # 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 - 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: self.sf.write("*{}\n".format(comment)) @@ -266,6 +336,17 @@ class functional(simulation): for port in self.readwrite_ports: self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05) + # Generate wmask bits + for port in self.write_ports: + if self.write_size: + self.sf.write("\n* Generation of wmask signals\n") + for bit in range(self.num_wmasks): + sig_name = "WMASK{0}_{1} ".format(port, bit) + # self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period, + # self.slew, 0.05) + self.stim.gen_pwl(sig_name, self.cycle_times, self.wmask_values[port][bit], self.period, + self.slew, 0.05) + # Generate CLK signals for port in self.all_ports: self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port), @@ -276,7 +357,7 @@ class functional(simulation): t_rise=self.slew, t_fall=self.slew) - # Generate DOUT value measurements + # Generate dout value measurements self.sf.write("\n * Generation of dout measurements\n") for (word, dout_port, eo_period, check) in self.write_check: t_intital = eo_period - 0.01*self.period @@ -290,4 +371,117 @@ class functional(simulation): self.stim.write_control(self.cycle_times[-1] + self.period) 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 + diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 4f709999..b8a72f77 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -1,9 +1,9 @@ # 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. +# 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 os,sys,re import debug @@ -148,9 +148,9 @@ class lib: self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height)) #Build string of all control signals. - control_str = 'CSb0' #assume at least 1 port + control_str = 'csb0' #assume at least 1 port for i in range(1, self.total_port_num): - control_str += ' & CSb{0}'.format(i) + control_str += ' & csb{0}'.format(i) # Leakage is included in dynamic when macro is enabled self.lib.write(" leakage_power () {\n") @@ -161,13 +161,17 @@ class lib: def write_units(self): - """ Adds default units for time, voltage, current,...""" - + """ Adds default units for time, voltage, current,... + Valid values are 1mV, 10mV, 100mV, and 1V. + For time: Valid values are 1ps, 10ps, 100ps, and 1ns. + For power: Valid values are 1mW, 100uW (for 100mW), 10uW (for 10mW), + 1uW (for 1mW), 100nW, 10nW, 1nW, 100pW, 10pW, and 1pW. + """ self.lib.write(" time_unit : \"1ns\" ;\n") - self.lib.write(" voltage_unit : \"1v\" ;\n") + self.lib.write(" voltage_unit : \"1V\" ;\n") self.lib.write(" current_unit : \"1mA\" ;\n") self.lib.write(" resistance_unit : \"1kohm\" ;\n") - self.lib.write(" capacitive_load_unit(1 ,fF) ;\n") + self.lib.write(" capacitive_load_unit(1, pF) ;\n") self.lib.write(" leakage_power_unit : \"1mW\" ;\n") self.lib.write(" pulling_resistance_unit :\"1kohm\" ;\n") self.lib.write(" operating_conditions(OC){\n") @@ -239,7 +243,9 @@ class lib: self.lib.write(" variable_1 : input_net_transition;\n") self.lib.write(" variable_2 : total_output_net_capacitance;\n") self.write_index(1,self.slews) - self.write_index(2,self.loads) + # Dividing by 1000 to all cap values since output of .sp is in fF, + # and it needs to be in pF for Innovus. + self.write_index(2,self.loads/1000) self.lib.write(" }\n\n") CONS = ["CONSTRAINT_TABLE"] @@ -272,10 +278,10 @@ class lib: # self.lib.write(" }\n\n") def write_bus(self): - """ Adds format of DATA and ADDR bus.""" + """ Adds format of data and addr bus.""" self.lib.write("\n\n") - self.lib.write(" type (DATA){\n") + self.lib.write(" type (data){\n") self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") self.lib.write(" bit_width : {0};\n".format(self.sram.word_size)) @@ -283,7 +289,7 @@ class lib: self.lib.write(" bit_to : {0};\n".format(self.sram.word_size - 1)) self.lib.write(" }\n\n") - self.lib.write(" type (ADDR){\n") + self.lib.write(" type (addr){\n") self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") self.lib.write(" bit_width : {0};\n".format(self.sram.addr_size)) @@ -323,18 +329,18 @@ class lib: def write_data_bus_output(self, read_port): """ Adds data bus timing results.""" - self.lib.write(" bus(DOUT{0}){{\n".format(read_port)) - self.lib.write(" bus_type : DATA; \n") + self.lib.write(" bus(dout{0}){{\n".format(read_port)) + self.lib.write(" bus_type : data; \n") self.lib.write(" direction : output; \n") # This is conservative, but limit to range that we characterized. - self.lib.write(" max_capacitance : {0}; \n".format(max(self.loads))) - self.lib.write(" min_capacitance : {0}; \n".format(min(self.loads))) + self.lib.write(" max_capacitance : {0}; \n".format(max(self.loads)/1000)) + self.lib.write(" min_capacitance : {0}; \n".format(min(self.loads)/1000)) self.lib.write(" memory_read(){ \n") - self.lib.write(" address : ADDR{0}; \n".format(read_port)) + self.lib.write(" address : addr{0}; \n".format(read_port)) self.lib.write(" }\n") - self.lib.write(" pin(DOUT{0}[{1}:0]){{\n".format(read_port,self.sram.word_size-1)) + self.lib.write(" pin(dout{0}[{1}:0]){{\n".format(read_port,self.sram.word_size-1)) self.lib.write(" timing(){ \n") self.lib.write(" timing_sense : non_unate; \n") self.lib.write(" related_pin : \"clk{0}\"; \n".format(read_port)) @@ -356,18 +362,18 @@ class lib: self.lib.write(" }\n\n") # bus def write_data_bus_input(self, write_port): - """ Adds DIN data bus timing results.""" + """ Adds din data bus timing results.""" - self.lib.write(" bus(DIN{0}){{\n".format(write_port)) - self.lib.write(" bus_type : DATA; \n") + self.lib.write(" bus(din{0}){{\n".format(write_port)) + self.lib.write(" bus_type : data; \n") self.lib.write(" direction : input; \n") # This is conservative, but limit to range that we characterized. - self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000)) self.lib.write(" memory_write(){ \n") - self.lib.write(" address : ADDR{0}; \n".format(write_port)) + self.lib.write(" address : addr{0}; \n".format(write_port)) self.lib.write(" clocked_on : clk{0}; \n".format(write_port)) self.lib.write(" }\n") - self.lib.write(" pin(DIN{0}[{1}:0]){{\n".format(write_port,self.sram.word_size-1)) + self.lib.write(" pin(din{0}[{1}:0]){{\n".format(write_port,self.sram.word_size-1)) self.write_FF_setuphold(write_port) self.lib.write(" }\n") # pin self.lib.write(" }\n") #bus @@ -382,12 +388,12 @@ class lib: def write_addr_bus(self, port): """ Adds addr bus timing results.""" - self.lib.write(" bus(ADDR{0}){{\n".format(port)) - self.lib.write(" bus_type : ADDR; \n") + self.lib.write(" bus(addr{0}){{\n".format(port)) + self.lib.write(" bus_type : addr; \n") self.lib.write(" direction : input; \n") - self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000)) self.lib.write(" max_transition : {0};\n".format(self.slews[-1])) - self.lib.write(" pin(ADDR{0}[{1}:0])".format(port,self.sram.addr_size-1)) + self.lib.write(" pin(addr{0}[{1}:0])".format(port,self.sram.addr_size-1)) self.lib.write("{\n") self.write_FF_setuphold(port) @@ -398,15 +404,15 @@ class lib: def write_control_pins(self, port): """ Adds control pins timing results.""" #The control pins are still to be determined. This is a placeholder for what could be. - ctrl_pin_names = ["CSb{0}".format(port)] + ctrl_pin_names = ["csb{0}".format(port)] if port in self.readwrite_ports: - ctrl_pin_names.append("WEb{0}".format(port)) + ctrl_pin_names.append("web{0}".format(port)) for i in ctrl_pin_names: self.lib.write(" pin({0})".format(i)) self.lib.write("{\n") self.lib.write(" direction : input; \n") - self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000)) self.write_FF_setuphold(port) self.lib.write(" }\n\n") @@ -417,7 +423,7 @@ class lib: self.lib.write(" clock : true;\n") self.lib.write(" direction : input; \n") # FIXME: This depends on the clock buffer size in the control logic - self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000)) self.add_clk_control_power(port) @@ -452,10 +458,10 @@ class lib: if port in self.write_ports: if port in self.read_ports: - web_name = " & !WEb{0}".format(port) + web_name = " & !web{0}".format(port) avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!CSb{0} & clk{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!csb{0} & clk{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0)) self.lib.write(" }\n") @@ -466,10 +472,10 @@ class lib: if port in self.read_ports: if port in self.write_ports: - web_name = " & WEb{0}".format(port) + web_name = " & web{0}".format(port) avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!CSb{0} & !clk{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!csb{0} & !clk{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0)) self.lib.write(" }\n") @@ -480,7 +486,7 @@ class lib: # Have 0 internal power when disabled, this will be represented as leakage power. self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"CSb{0}\"; \n".format(port)) + self.lib.write(" when : \"csb{0}\"; \n".format(port)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"0\");\n") self.lib.write(" }\n") @@ -571,10 +577,10 @@ class lib: datasheet.write(str(self.sram.width * self.sram.height)+',') # write timing information for all ports for port in self.all_ports: - #DIN timings + #din timings if port in self.write_ports: datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format( - "DIN{1}[{0}:0]".format(self.sram.word_size - 1, port), + "din{1}[{0}:0]".format(self.sram.word_size - 1, port), min(list(map(round_time,self.times["setup_times_LH"]))), max(list(map(round_time,self.times["setup_times_LH"]))), @@ -590,10 +596,10 @@ class lib: )) for port in self.all_ports: - #DOUT timing + #dout timing if port in self.read_ports: datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format( - "DOUT{1}[{0}:0]".format(self.sram.word_size - 1, port), + "dout{1}[{0}:0]".format(self.sram.word_size - 1, port), min(list(map(round_time,self.char_port_results[port]["delay_lh"]))), max(list(map(round_time,self.char_port_results[port]["delay_lh"]))), @@ -610,9 +616,9 @@ class lib: )) for port in self.all_ports: - #CSb timings + #csb timings datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format( - "CSb{0}".format(port), + "csb{0}".format(port), min(list(map(round_time,self.times["setup_times_LH"]))), max(list(map(round_time,self.times["setup_times_LH"]))), @@ -628,9 +634,9 @@ class lib: )) for port in self.all_ports: - #ADDR timings + #addr timings datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format( - "ADDR{1}[{0}:0]".format(self.sram.addr_size - 1, port), + "addr{1}[{0}:0]".format(self.sram.addr_size - 1, port), min(list(map(round_time,self.times["setup_times_LH"]))), max(list(map(round_time,self.times["setup_times_LH"]))), @@ -649,9 +655,9 @@ class lib: for port in self.all_ports: if port in self.readwrite_ports: - #WEb timings + #web timings datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format( - "WEb{0}".format(port), + "web{0}".format(port), min(list(map(round_time,self.times["setup_times_LH"]))), max(list(map(round_time,self.times["setup_times_LH"]))), @@ -673,8 +679,8 @@ class lib: # write dynamic power usage if port in self.read_ports: - web_name = " & !WEb{0}".format(port) - name = "!CSb{0} & clk{0}{1}".format(port, web_name) + web_name = " & !web{0}".format(port) + name = "!csb{0} & clk{0}{1}".format(port, web_name) read_write = 'Read' datasheet.write("{0},{1},{2},{3},".format( @@ -686,8 +692,8 @@ class lib: )) if port in self.write_ports: - web_name = " & WEb{0}".format(port) - name = "!CSb{0} & !clk{0}{1}".format(port, web_name) + web_name = " & web{0}".format(port) + name = "!csb{0} & !clk{0}{1}".format(port, web_name) read_write = 'Write' datasheet.write("{0},{1},{2},{3},".format( @@ -699,9 +705,9 @@ class lib: )) # write leakage power - control_str = 'CSb0' + control_str = 'csb0' for i in range(1, self.total_port_num): - control_str += ' & CSb{0}'.format(i) + control_str += ' & csb{0}'.format(i) datasheet.write("{0},{1},{2},".format('leak', control_str, self.char_sram_results["leakage_power"])) diff --git a/compiler/characterizer/logical_effort.py b/compiler/characterizer/logical_effort.py index 13005695..42ac8861 100644 --- a/compiler/characterizer/logical_effort.py +++ b/compiler/characterizer/logical_effort.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, parameter, spice @@ -23,23 +23,23 @@ class logical_effort(): self.cin = cin self.cout = cout self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin - self.eletrical_effort = self.cout/self.cin + self.electrical_effort = self.cout/self.cin self.parasitic_scale = parasitic self.is_rise = out_is_rise def __str__(self): return "Name={}, g={}, h={}, p={}*pinv, rise_delay={}".format(self.name, self.logical_effort, - self.eletrical_effort, + self.electrical_effort, self.parasitic_scale, self.is_rise ) def get_stage_effort(self): - return self.logical_effort*self.eletrical_effort + return self.logical_effort*self.electrical_effort def get_parasitic_delay(self): - return logical_effort.pinv * self.parasitic_scale + return logical_effort.pinv*self.parasitic_scale def get_stage_delay(self): return self.get_stage_effort()+self.get_parasitic_delay() @@ -78,4 +78,7 @@ def calculate_relative_rise_fall_delays(stage_effort_list): def convert_farad_to_relative_c(c_farad): """Converts capacitance in Femto-Farads to relative capacitance.""" return c_farad*parameter['cap_relative_per_ff'] - \ No newline at end of file + +def convert_relative_c_to_farad(c_relative): + """Converts capacitance in logical effort relative units to Femto-Farads.""" + return c_relative/parameter['cap_relative_per_ff'] \ No newline at end of file diff --git a/compiler/characterizer/measurements.py b/compiler/characterizer/measurements.py index 01c6fa51..54f9973f 100644 --- a/compiler/characterizer/measurements.py +++ b/compiler/characterizer/measurements.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, parameter, spice @@ -13,10 +13,11 @@ from .charutils import * class spice_measurement(ABC): """Base class for spice stimulus measurements.""" - def __init__(self, measure_name, measure_scale=None): + def __init__(self, measure_name, measure_scale=None, has_port=True): #Names must be unique for correct spice simulation, but not enforced here. self.name = measure_name self.measure_scale = measure_scale + self.has_port = has_port #Needed for error checking #Some meta values used externally. variables are added here for consistency accross the objects self.meta_str = None self.meta_add_delay = False @@ -35,18 +36,29 @@ class spice_measurement(ABC): measure_vals = self.get_measure_values(*input_tuple) measure_func(stim_obj, *measure_vals) - def retrieve_measure(self, port=""): - value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port)) + def retrieve_measure(self, port=None): + self.port_error_check(port) + if port != None: + value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port)) + else: + value = parse_spice_list("timing", "{0}".format(self.name.lower())) if type(value)!=float or self.measure_scale == None: return value else: return value*self.measure_scale - + + def port_error_check(self, port): + if self.has_port and port == None: + debug.error("Cannot retrieve measurement, port input was expected.",1) + elif not self.has_port and port != None: + debug.error("Unexpected port input received during measure retrieval.",1) + class delay_measure(spice_measurement): """Generates a spice measurement for the delay of 50%-to-50% points of two signals.""" - def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd=0.5, targ_vdd=0.5, measure_scale=None): - spice_measurement.__init__(self, measure_name, measure_scale) + def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str,\ + trig_vdd=0.5, targ_vdd=0.5, measure_scale=None, has_port=True): + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) def get_measure_function(self): @@ -56,10 +68,8 @@ class delay_measure(spice_measurement): """Set the constants for this measurement: signal names, directions, and trigger scales""" self.trig_dir_str = trig_dir_str self.targ_dir_str = targ_dir_str - self.trig_val_of_vdd = trig_vdd self.targ_val_of_vdd = targ_vdd - self.trig_name_no_port = trig_name self.targ_name_no_port = targ_name @@ -67,9 +77,10 @@ class delay_measure(spice_measurement): def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" + self.port_error_check(port) trig_val = self.trig_val_of_vdd * vdd_voltage targ_val = self.targ_val_of_vdd * vdd_voltage - + if port != None: #For dictionary indexing reasons, the name is formatted differently than the signals meas_name = "{}{}".format(self.name, port) @@ -79,13 +90,12 @@ class delay_measure(spice_measurement): meas_name = self.name trig_name = self.trig_name_no_port targ_name = self.targ_name_no_port - return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td) class slew_measure(delay_measure): - def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None): - spice_measurement.__init__(self, measure_name, measure_scale) + def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None, has_port=True): + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(signal_name, slew_dir_str) def set_meas_constants(self, signal_name, slew_dir_str): @@ -101,7 +111,6 @@ class slew_measure(delay_measure): self.targ_val_of_vdd = 0.1 else: debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1) - self.trig_name_no_port = signal_name self.targ_name_no_port = signal_name @@ -110,8 +119,8 @@ class slew_measure(delay_measure): class power_measure(spice_measurement): """Generates a spice measurement for the average power between two time points.""" - def __init__(self, measure_name, power_type="", measure_scale=None): - spice_measurement.__init__(self, measure_name, measure_scale) + def __init__(self, measure_name, power_type="", measure_scale=None, has_port=True): + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(power_type) def get_measure_function(self): @@ -124,6 +133,7 @@ class power_measure(spice_measurement): def get_measure_values(self, t_initial, t_final, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" + self.port_error_check(port) if port != None: meas_name = "{}{}".format(self.name, port) else: @@ -133,8 +143,8 @@ class power_measure(spice_measurement): class voltage_when_measure(spice_measurement): """Generates a spice measurement to measure the voltage of a signal based on the voltage of another.""" - def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None): - spice_measurement.__init__(self, measure_name, measure_scale) + def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None, has_port=True): + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) def get_measure_function(self): @@ -144,13 +154,12 @@ class voltage_when_measure(spice_measurement): """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" self.trig_dir_str = trig_dir_str self.trig_val_of_vdd = trig_vdd - self.trig_name_no_port = trig_name self.targ_name_no_port = targ_name def get_measure_values(self, trig_td, vdd_voltage, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" - + self.port_error_check(port) if port != None: #For dictionary indexing reasons, the name is formatted differently than the signals meas_name = "{}{}".format(self.name, port) @@ -160,7 +169,33 @@ class voltage_when_measure(spice_measurement): meas_name = self.name trig_name = self.trig_name_no_port targ_name = self.targ_name_no_port - - trig_voltage = self.trig_val_of_vdd*vdd_voltage - - return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td) \ No newline at end of file + trig_voltage = self.trig_val_of_vdd*vdd_voltage + return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td) + +class voltage_at_measure(spice_measurement): + """Generates a spice measurement to measure the voltage at a specific time. + The time is considered variant with different periods.""" + + def __init__(self, measure_name, targ_name, measure_scale=None, has_port=True): + spice_measurement.__init__(self, measure_name, measure_scale, has_port) + self.set_meas_constants(targ_name) + + def get_measure_function(self): + return stimuli.gen_meas_find_voltage_at_time + + def set_meas_constants(self, targ_name): + """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" + self.targ_name_no_port = targ_name + + def get_measure_values(self, time_at, port=None): + """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" + self.port_error_check(port) + if port != None: + #For dictionary indexing reasons, the name is formatted differently than the signals + meas_name = "{}{}".format(self.name, port) + targ_name = self.targ_name_no_port.format(port) + else: + meas_name = self.name + targ_name = self.targ_name_no_port + return (meas_name,targ_name,time_at) + \ No newline at end of file diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index c7834602..b35c3c47 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -38,7 +38,7 @@ class model_check(delay): self.bl_meas_name, self.bl_slew_name = "bl_measures", "bl_slews" self.power_name = "total_power" - def create_measurement_names(self): + def create_measurement_names(self, port): """Create measurement names. The names themselves currently define the type of measurement""" #Create delay measurement names wl_en_driver_delay_names = ["delay_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] @@ -49,7 +49,10 @@ class model_check(delay): else: dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] self.wl_delay_meas_names = wl_en_driver_delay_names+["delay_wl_en", "delay_wl_bar"]+wl_driver_delay_names+["delay_wl"] - self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names + if port not in self.sram.readonly_ports: + self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names + else: + self.rbl_delay_meas_names = ["delay_gated_clk_nand"]+dc_delay_names self.sae_delay_meas_names = ["delay_pre_sen"]+sen_driver_delay_names+["delay_sen"] # if self.custom_delaychain: @@ -65,45 +68,54 @@ class model_check(delay): else: dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] self.wl_slew_meas_names = ["slew_wl_gated_clk_bar"]+wl_en_driver_slew_names+["slew_wl_en", "slew_wl_bar"]+wl_driver_slew_names+["slew_wl"] - self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names + if port not in self.sram.readonly_ports: + self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names + else: + self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar"]+dc_slew_names self.sae_slew_meas_names = ["slew_replica_bl0", "slew_pre_sen"]+sen_driver_slew_names+["slew_sen"] self.bitline_meas_names = ["delay_wl_to_bl", "delay_bl_to_dout"] self.power_meas_names = ['read0_power'] - def create_signal_names(self): + def create_signal_names(self, port): """Creates list of the signal names used in the spice file along the wl and sen paths. Names are re-harded coded here; i.e. the names are hardcoded in most of OpenRAM and are replicated here. """ delay.create_signal_names(self) #Signal names are all hardcoded, need to update to make it work for probe address and different configurations. - wl_en_driver_signals = ["Xsram.Xcontrol0.Xbuf_wl_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] - wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver0.Xwl_driver_inv{}.Zb{}_int".format(self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())] - sen_driver_signals = ["Xsram.Xcontrol0.Xbuf_s_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_sen_driver_stages())] + wl_en_driver_signals = ["Xsram.Xcontrol{}.Xbuf_wl_en.Zb{}_int".format('{}', stage) for stage in range(1,self.get_num_wl_en_driver_stages())] + wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver{}.Xwl_driver_inv{}.Zb{}_int".format('{}', self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())] + sen_driver_signals = ["Xsram.Xcontrol{}.Xbuf_s_en.Zb{}_int".format('{}',stage) for stage in range(1,self.get_num_sen_driver_stages())] if self.custom_delaychain: delay_chain_signal_names = [] else: - delay_chain_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.Xdelay_chain.dout_{}".format(stage) for stage in range(1,self.get_num_delay_stages())] - - self.wl_signal_names = ["Xsram.Xcontrol0.gated_clk_bar"]+\ + delay_chain_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.Xdelay_chain.dout_{}".format('{}', stage) for stage in range(1,self.get_num_delay_stages())] + if len(self.sram.all_ports) > 1: + port_format = '{}' + else: + port_format = '' + self.wl_signal_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')]+\ wl_en_driver_signals+\ - ["Xsram.wl_en0", "Xsram.Xbank0.Xwordline_driver0.wl_bar_{}".format(self.wordline_row)]+\ + ["Xsram.wl_en{}".format('{}'), "Xsram.Xbank0.Xwordline_driver{}.wl_bar_{}".format('{}',self.wordline_row)]+\ wl_driver_signals+\ - ["Xsram.Xbank0.wl_{}".format(self.wordline_row)] - pre_delay_chain_names = ["Xsram.Xcontrol0.gated_clk_bar", "Xsram.Xcontrol0.Xand2_rbl_in.zb_int", "Xsram.Xcontrol0.rbl_in"] + ["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row)] + pre_delay_chain_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')] + if port not in self.sram.readonly_ports: + pre_delay_chain_names+= ["Xsram.Xcontrol{}.Xand2_rbl_in.zb_int".format('{}'), "Xsram.Xcontrol{}.rbl_in".format('{}')] + self.rbl_en_signal_names = pre_delay_chain_names+\ delay_chain_signal_names+\ - ["Xsram.Xcontrol0.Xreplica_bitline.delayed_en"] + ["Xsram.Xcontrol{}.Xreplica_bitline.delayed_en".format('{}')] - self.sae_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.bl0_0", "Xsram.Xcontrol0.pre_s_en"]+\ + self.sae_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.bl0_0".format('{}'), "Xsram.Xcontrol{}.pre_s_en".format('{}')]+\ sen_driver_signals+\ - ["Xsram.s_en0"] + ["Xsram.s_en{}".format('{}')] dout_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit - self.bl_signal_names = ["Xsram.Xbank0.wl_{}".format(self.wordline_row),\ - "Xsram.Xbank0.bl_{}".format(self.bitline_column),\ + self.bl_signal_names = ["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row),\ + "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column),\ dout_name] def create_measurement_objects(self): @@ -369,17 +381,18 @@ class model_check(delay): errors = self.calculate_error_l2_norm(scaled_meas, scaled_model) debug.info(1, "Errors:\n{}\n".format(errors)) - def analyze(self, probe_address, probe_data, slews, loads): + def analyze(self, probe_address, probe_data, slews, loads, port): """Measures entire delay path along the wordline and sense amp enable and compare it to the model delays.""" self.load=max(loads) self.slew=max(slews) self.set_probe(probe_address, probe_data) - self.create_signal_names() - self.create_measurement_names() + self.create_signal_names(port) + self.create_measurement_names(port) self.create_measurement_objects() data_dict = {} read_port = self.read_ports[0] #only test the first read port + read_port = port self.targ_read_ports = [read_port] self.targ_write_ports = [self.write_ports[0]] debug.info(1,"Model test: corner {}".format(self.corner)) diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index c85a5ad0..4e661a9e 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -1,9 +1,9 @@ # 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. +# 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 import tech diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index e6204490..a44ba154 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -1,9 +1,9 @@ # 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. +# 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 from design import design @@ -24,15 +24,18 @@ class simulation(): self.name = self.sram.name self.word_size = self.sram.word_size self.addr_size = self.sram.addr_size - self.num_cols = self.sram.num_cols - self.num_rows = self.sram.num_rows - self.num_banks = self.sram.num_banks + self.write_size = self.sram.write_size self.sp_file = spfile self.all_ports = self.sram.all_ports self.readwrite_ports = self.sram.readwrite_ports self.read_ports = self.sram.read_ports self.write_ports = self.sram.write_ports + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + else: + self.num_wmasks = 0 + def set_corner(self,corner): """ Set the corner values """ @@ -49,6 +52,19 @@ class simulation(): self.v_low = tech.spice["v_threshold_typical"] self.gnd_voltage = 0 + def create_signal_names(self): + self.addr_name = "a" + self.din_name = "din" + self.dout_name = "dout" + self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name), + port_info=(len(self.all_ports),self.write_ports,self.read_ports), + abits=self.addr_size, + dbits=self.word_size) + debug.check(len(self.sram.pins) == len(self.pins), "Number of pins generated for characterization \ + do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,self.pins)) + #This is TODO once multiport control has been finalized. + #self.control_name = "CSB" + def set_stimulus_variables(self): # Clock signals self.cycle_times = [] @@ -61,6 +77,7 @@ class simulation(): # Three dimensional list to handle each addr and data bits for wach port over the number of checks self.addr_values = [[[] for bit in range(self.addr_size)] for port in self.all_ports] self.data_values = [[[] for bit in range(self.word_size)] for port in self.write_ports] + self.wmask_values = [[[] for bit in range(self.num_wmasks)] for port in self.write_ports] # For generating comments in SPICE stimulus self.cycle_comments = [] @@ -112,8 +129,22 @@ class simulation(): else: debug.error("Non-binary address string",1) bit -= 1 + + def add_wmask(self, wmask, port): + """ Add the array of address values """ + debug.check(len(wmask) == self.num_wmasks, "Invalid wmask size.") + + bit = self.num_wmasks - 1 + for c in wmask: + if c == "0": + self.wmask_values[port][bit].append(0) + elif c == "1": + self.wmask_values[port][bit].append(1) + else: + debug.error("Non-binary wmask string", 1) + bit -= 1 - def add_write(self, comment, address, data, port): + def add_write(self, comment, address, data, wmask, port): """ Add the control values for a write cycle. """ debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports)) debug.info(2, comment) @@ -126,15 +157,16 @@ class simulation(): self.add_control_one_port(port, "write") self.add_data(data,port) self.add_address(address,port) + self.add_wmask(wmask,port) #This value is hard coded here. Possibly change to member variable or set in add_noop_one_port noop_data = "0"*self.word_size #Add noops to all other ports. for unselected_port in self.all_ports: if unselected_port != port: - self.add_noop_one_port(address, noop_data, unselected_port) + self.add_noop_one_port(address, noop_data, wmask, unselected_port) - def add_read(self, comment, address, din_data, port): + def add_read(self, comment, address, din_data, wmask, port): """ Add the control values for a read cycle. """ debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports)) debug.info(2, comment) @@ -148,6 +180,7 @@ class simulation(): #If the port is also a readwrite then add data. if port in self.write_ports: self.add_data(din_data,port) + self.add_wmask(wmask,port) self.add_address(address, port) #This value is hard coded here. Possibly change to member variable or set in add_noop_one_port @@ -155,9 +188,9 @@ class simulation(): #Add noops to all other ports. for unselected_port in self.all_ports: if unselected_port != port: - self.add_noop_one_port(address, noop_data, unselected_port) + self.add_noop_one_port(address, noop_data, wmask, unselected_port) - def add_noop_all_ports(self, comment, address, data): + def add_noop_all_ports(self, comment, address, data, wmask): """ Add the control values for a noop to all ports. """ debug.info(2, comment) self.fn_cycle_comments.append(comment) @@ -167,19 +200,20 @@ class simulation(): self.t_current += self.period for port in self.all_ports: - self.add_noop_one_port(address, data, port) - - def add_write_one_port(self, comment, address, data, port): + self.add_noop_one_port(address, data, wmask, port) + + def add_write_one_port(self, comment, address, data, wmask, port): """ Add the control values for a write cycle. Does not increment the period. """ debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports)) debug.info(2, comment) self.fn_cycle_comments.append(comment) - + self.add_control_one_port(port, "write") self.add_data(data,port) self.add_address(address,port) + self.add_wmask(wmask,port) - def add_read_one_port(self, comment, address, din_data, port): + def add_read_one_port(self, comment, address, din_data, wmask, port): """ Add the control values for a read cycle. Does not increment the period. """ debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports)) debug.info(2, comment) @@ -189,13 +223,15 @@ class simulation(): #If the port is also a readwrite then add data. if port in self.write_ports: self.add_data(din_data,port) + self.add_wmask(wmask,port) self.add_address(address, port) - def add_noop_one_port(self, address, data, port): + def add_noop_one_port(self, address, data, wmask, port): """ Add the control values for a noop to a single port. Does not increment the period. """ self.add_control_one_port(port, "noop") if port in self.write_ports: self.add_data(data,port) + self.add_wmask(wmask,port) self.add_address(address, port) def append_cycle_comment(self, port, comment): @@ -209,24 +245,74 @@ class simulation(): time_spacing, comment)) - def gen_cycle_comment(self, op, word, addr, port, t_current): + def gen_cycle_comment(self, op, word, addr, wmask, port, t_current): if op == "noop": comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period), t_current, t_current+self.period) elif op == "write": comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, - addr, - port, - int(t_current/self.period), - t_current, - t_current+self.period) + addr, + port, + int(t_current/self.period), + t_current, + t_current+self.period) + 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, + addr, + wmask, + port, + int(t_current / self.period), + t_current, + t_current + self.period) else: comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, - addr, - port, - int(t_current/self.period), - t_current, - t_current+self.period) + addr, + port, + int(t_current/self.period), + t_current, + t_current+self.period) + + return comment + def gen_pin_names(self, port_signal_names, port_info, abits, dbits): + """Creates the pins names of the SRAM based on the no. of ports.""" + #This may seem redundant as the pin names are already defined in the sram. However, it is difficult + #to extract the functionality from the names, so they are recreated. As the order is static, changing + #the order of the pin names will cause issues here. + pin_names = [] + (addr_name, din_name, dout_name) = port_signal_names + (total_ports, write_index, read_index) = port_info + + for write_input in write_index: + for i in range(dbits): + pin_names.append("{0}{1}_{2}".format(din_name,write_input, i)) + + for port in range(total_ports): + for i in range(abits): + pin_names.append("{0}{1}_{2}".format(addr_name,port,i)) + + #Control signals not finalized. + for port in range(total_ports): + pin_names.append("CSB{0}".format(port)) + for port in range(total_ports): + if (port in read_index) and (port in write_index): + pin_names.append("WEB{0}".format(port)) + + for port in range(total_ports): + pin_names.append("{0}{1}".format(tech.spice["clk"], port)) + + if self.write_size: + for port in write_index: + for bit in range(self.num_wmasks): + pin_names.append("WMASK{0}_{1}".format(port,bit)) + + for read_output in read_index: + for i in range(dbits): + pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i)) + + pin_names.append("{0}".format(tech.spice["vdd_name"])) + pin_names.append("{0}".format(tech.spice["gnd_name"])) + return pin_names + diff --git a/compiler/characterizer/sram_op.py b/compiler/characterizer/sram_op.py new file mode 100644 index 00000000..58999ca0 --- /dev/null +++ b/compiler/characterizer/sram_op.py @@ -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 diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index ddd1df7e..31ee24d1 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This file generates simple spice cards for simulation. There are @@ -36,51 +36,15 @@ class stimuli(): (self.process, self.voltage, self.temperature) = corner self.device_models = tech.spice["fet_models"][self.process] - def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name): + self.sram_name = "Xsram" + + def inst_sram(self, pins, inst_name): """ Function to instatiate an SRAM subckt. """ - pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits) - #Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM - debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names)) - - self.sf.write("Xsram ") - for pin in pin_names: + + self.sf.write("{} ".format(self.sram_name)) + for pin in self.sram_pins: self.sf.write("{0} ".format(pin)) - self.sf.write("{0}\n".format(sram_name)) - - def gen_pin_names(self, port_signal_names, port_info, abits, dbits): - """Creates the pins names of the SRAM based on the no. of ports.""" - #This may seem redundant as the pin names are already defined in the sram. However, it is difficult to extract the - #functionality from the names, so they are recreated. As the order is static, changing the order of the pin names - #will cause issues here. - pin_names = [] - (addr_name, din_name, dout_name) = port_signal_names - (total_ports, write_index, read_index) = port_info - - for write_input in write_index: - for i in range(dbits): - pin_names.append("{0}{1}_{2}".format(din_name,write_input, i)) - - for port in range(total_ports): - for i in range(abits): - pin_names.append("{0}{1}_{2}".format(addr_name,port,i)) - - #Control signals not finalized. - for port in range(total_ports): - pin_names.append("CSB{0}".format(port)) - for port in range(total_ports): - if (port in read_index) and (port in write_index): - pin_names.append("WEB{0}".format(port)) - - for port in range(total_ports): - pin_names.append("{0}{1}".format(tech.spice["clk"], port)) - - for read_output in read_index: - for i in range(dbits): - pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i)) - - pin_names.append("{0}".format(self.vdd_name)) - pin_names.append("{0}".format(self.gnd_name)) - return pin_names + self.sf.write("{0}\n".format(inst_name)) def inst_model(self, pins, model_name): """ Function to instantiate a generic model with a set of pins """ @@ -233,6 +197,13 @@ class stimuli(): trig_dir, trig_td)) + def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at): + """ Creates the .meas statement for voltage at time""" + measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n" + self.sf.write(measure_string.format(meas_name, + targ_name, + time_at)) + def gen_meas_power(self, meas_name, t_initial, t_final): """ Creates the .meas statement for the measurement of avg power """ # power mea cmd is different in different spice: diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index b8878db3..ffc45a9c 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -1,9 +1,9 @@ # 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. +# 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 from math import log diff --git a/compiler/characterizer/worst_case.py b/compiler/characterizer/worst_case.py deleted file mode 100644 index 612d6f9f..00000000 --- a/compiler/characterizer/worst_case.py +++ /dev/null @@ -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))] - - diff --git a/compiler/datasheet/add_db.py b/compiler/datasheet/add_db.py index a5984969..9514cf1b 100644 --- a/compiler/datasheet/add_db.py +++ b/compiler/datasheet/add_db.py @@ -1,9 +1,9 @@ # 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. +# 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 pathlib import Path import glob diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index 0874cd01..35091d36 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -1,9 +1,9 @@ # 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. +# 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 table_gen import * import os diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index c7eecd8d..02ecc5d4 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 """ @@ -161,7 +161,7 @@ def parse_characterizer_csv(f, pages): # check current .lib file produces the slowest timing results while(True): col_start = col - if(row[col].startswith('DIN')): + if(row[col].startswith('din')): start = col for item in sheet.timing_table.rows: if item[0].startswith(row[col]): @@ -200,7 +200,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('DOUT')): + elif(row[col].startswith('dout')): start = col for item in sheet.timing_table.rows: if item[0].startswith(row[col]): @@ -239,7 +239,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('CSb')): + elif(row[col].startswith('csb')): start = col for item in sheet.timing_table.rows: if item[0].startswith(row[col]): @@ -278,7 +278,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('WEb')): + elif(row[col].startswith('web')): start = col for item in sheet.timing_table.rows: if item[0].startswith(row[col]): @@ -317,7 +317,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('ADDR')): + elif(row[col].startswith('addr')): start = col for item in sheet.timing_table.rows: if item[0].startswith(row[col]): @@ -441,7 +441,7 @@ def parse_characterizer_csv(f, pages): # parse initial timing information while(True): col_start = col - if(row[col].startswith('DIN')): + if(row[col].startswith('din')): start = col new_sheet.timing_table.add_row( @@ -465,7 +465,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('DOUT')): + elif(row[col].startswith('dout')): start = col new_sheet.timing_table.add_row( @@ -489,7 +489,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('CSb')): + elif(row[col].startswith('csb')): start = col new_sheet.timing_table.add_row( @@ -513,7 +513,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('WEb')): + elif(row[col].startswith('web')): start = col new_sheet.timing_table.add_row( @@ -537,7 +537,7 @@ def parse_characterizer_csv(f, pages): col += 1 - elif(row[col].startswith('ADDR')): + elif(row[col].startswith('addr')): start = col new_sheet.timing_table.add_row( diff --git a/compiler/datasheet/table_gen.py b/compiler/datasheet/table_gen.py index 01479d7f..85a6cfba 100644 --- a/compiler/datasheet/table_gen.py +++ b/compiler/datasheet/table_gen.py @@ -1,9 +1,9 @@ # 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. +# 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 table_gen: """small library of functions to generate the html tables""" diff --git a/compiler/debug.py b/compiler/debug.py index 4fa8b487..02a28c22 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -1,9 +1,9 @@ # 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. +# 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 os import inspect @@ -85,7 +85,7 @@ def log(str): # use a static list of strings to store messages until the global paths are set up log.setup_output = [] -log.create_file = 1 +log.create_file = True def info(lev, str): diff --git a/compiler/drc/design_rules.py b/compiler/drc/design_rules.py index 09729144..1017aca6 100644 --- a/compiler/drc/design_rules.py +++ b/compiler/drc/design_rules.py @@ -1,9 +1,9 @@ # 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. +# 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 from drc_value import * @@ -42,6 +42,7 @@ class design_rules(): return rule else: debug.error("Must call complex DRC rule {} with arguments.".format(b),-1) + diff --git a/compiler/drc/drc_lut.py b/compiler/drc/drc_lut.py index 0a214231..0ad0fde4 100644 --- a/compiler/drc/drc_lut.py +++ b/compiler/drc/drc_lut.py @@ -1,9 +1,9 @@ # 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. +# 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 diff --git a/compiler/drc/drc_value.py b/compiler/drc/drc_value.py index 4c85657f..1649e203 100644 --- a/compiler/drc/drc_value.py +++ b/compiler/drc/drc_value.py @@ -1,9 +1,9 @@ # 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. +# 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 drc_value(): diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 03873ed4..f4248ebd 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -2,6 +2,7 @@ from .gdsPrimitives import * from datetime import * #from mpmath import matrix #from numpy import matrix +from vector import vector import numpy as np #import gdsPrimitives import debug @@ -725,12 +726,26 @@ class VlsiLayout: self.pins[label_text] = [] self.pins[label_text].append(pin_shapes) - + + def getBlockages(self,layer): + """ + Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and + user units. + """ + blockages = [] + + shapes = self.getAllShapes(layer) + for boundary in shapes: + vectors = [] + for i in range(0,len(boundary),2): + vectors.append(vector(boundary[i],boundary[i+1])) + blockages.append(vectors) + return blockages def getAllShapes(self,layer): """ - Return all gshapes on a given layer in [llx, lly, urx, ury] format and - user units. + Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles + and [coordinate 1, coordinate 2,...] format and user units for polygons. """ boundaries = set() for TreeUnit in self.xyTree: @@ -740,42 +755,67 @@ class VlsiLayout: # Convert to user units user_boundaries = [] for boundary in boundaries: - user_boundaries.append([boundary[0]*self.units[0],boundary[1]*self.units[0], - boundary[2]*self.units[0],boundary[3]*self.units[0]]) - + boundaries_list = [] + for i in range(0,len(boundary)): + boundaries_list.append(boundary[i]*self.units[0]) + user_boundaries.append(boundaries_list) return user_boundaries def getShapesInStructure(self,layer,structure): """ Go through all the shapes in a structure and return the list of shapes in - the form [llx, lly, urx, ury] + the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons. """ - (structureName,structureOrigin,structureuVector,structurevVector)=structure #print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose()) boundaries = [] for boundary in self.structures[str(structureName)].boundaries: - # FIXME: Right now, this only supports rectangular shapes! - # We should trigger an error but some FreePDK45 library cells contain paths. - # These get saved fine, but we cannot parse them as blockages... - #debug.check(len(boundary.coordinates)==5,"Non-rectangular shapes are not supported.") - if len(boundary.coordinates)!=5: - continue if layer==boundary.drawingLayer: - left_bottom=boundary.coordinates[0] - right_top=boundary.coordinates[2] - # Rectangle is [leftx, bottomy, rightx, topy]. - boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] - # perform the rotation - boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) - # add the offset and make it a tuple - boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), - boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()) - boundaries.append(boundaryRect) - + if len(boundary.coordinates)!=5: + # if shape is a polygon (used in DFF) + boundaryPolygon = [] + # Polygon is a list of coordinates going ccw + for coord in range(0,len(boundary.coordinates)): + boundaryPolygon.append(boundary.coordinates[coord][0]) + boundaryPolygon.append(boundary.coordinates[coord][1]) + # perform the rotation + boundaryPolygon=self.transformPolygon(boundaryPolygon,structureuVector,structurevVector) + # add the offset + polygon = [] + for i in range(0,len(boundaryPolygon),2): + polygon.append(boundaryPolygon[i]+structureOrigin[0].item()) + polygon.append(boundaryPolygon[i+1]+structureOrigin[1].item()) + # make it a tuple + polygon = tuple(polygon) + boundaries.append(polygon) + else: + # else shape is a rectangle + left_bottom=boundary.coordinates[0] + right_top=boundary.coordinates[2] + # Rectangle is [leftx, bottomy, rightx, topy]. + boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]] + # perform the rotation + boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector) + # add the offset and make it a tuple + boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(), + boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()) + boundaries.append(boundaryRect) return boundaries - + + + def transformPolygon(self,originalPolygon,uVector,vVector): + """ + Transforms the coordinates of a polygon in space. + """ + polygon = [] + newPolygon = [] + for i in range(0,len(originalPolygon),2): + polygon.append(self.transformCoordinate([originalPolygon[i],originalPolygon[i+1]],uVector,vVector)) + newPolygon.append(polygon[int(i/2)][0]) + newPolygon.append(polygon[int(i/2)][1]) + return newPolygon + def transformRectangle(self,originalRectangle,uVector,vVector): """ Transforms the four coordinates of a rectangle in space @@ -799,7 +839,7 @@ class VlsiLayout: """ Rotate a coordinate in space. """ - # MRG: 9/3/18 Incorrect matrixi multiplication! + # MRG: 9/3/18 Incorrect matrix multiplication! # This is fixed to be: # |u[0] v[0]| |x| |x'| # |u[1] v[1]|x|y|=|y'| diff --git a/compiler/gen_stimulus.py b/compiler/gen_stimulus.py index 3b24cff7..6a6be1d1 100755 --- a/compiler/gen_stimulus.py +++ b/compiler/gen_stimulus.py @@ -1,10 +1,10 @@ #!/usr/bin/env python # 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. +# 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. # """ This script will generate a stimulus file for a given period, load, and slew input diff --git a/compiler/globals.py b/compiler/globals.py index 2fe0ec1b..4fed4cd9 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This is called globals.py, but it actually parses all the arguments and performs @@ -19,9 +19,10 @@ import re import copy import importlib -USAGE = "Usage: openram.py [options] \nUse -h for help.\n" +VERSION = "1.1.0" +NAME = "OpenRAM v{}".format(VERSION) +USAGE = "openram.py [options] \nUse -h for help.\n" -# Anonymous object that will be the options OPTS = options.options() CHECKPOINT_OPTS=None @@ -57,9 +58,9 @@ def parse_args(): } parser = optparse.OptionParser(option_list=option_list, - description="Compile and/or characterize an SRAM.", + description=NAME, usage=USAGE, - version="OpenRAM") + version=VERSION) (options, args) = parser.parse_args(values=OPTS) # If we don't specify a tech, assume scmos. @@ -79,8 +80,7 @@ def print_banner(): return debug.print_raw("|==============================================================================|") - name = "OpenRAM Compiler" - debug.print_raw("|=========" + name.center(60) + "=========|") + debug.print_raw("|=========" + NAME.center(60) + "=========|") debug.print_raw("|=========" + " ".center(60) + "=========|") debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") @@ -169,11 +169,12 @@ def setup_bitcell(): # If we have non-1rw ports, # and the user didn't over-ride the bitcell manually, # 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): OPTS.bitcell = "bitcell" OPTS.replica_bitcell = "replica_bitcell" + OPTS.dummy_bitcell = "dummy_bitcell" else: ports = "" if OPTS.num_rw_ports>0: @@ -185,21 +186,26 @@ def setup_bitcell(): OPTS.bitcell = "bitcell_"+ports OPTS.replica_bitcell = "replica_bitcell_"+ports - - # See if a custom bitcell exists - from importlib import find_loader - try: - __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.") + OPTS.dummy_bitcell = "dummy_bitcell_"+ports + else: + OPTS.replica_bitcell = "replica_" + OPTS.bitcell + OPTS.replica_bitcell = "dummy_" + OPTS.bitcell + # 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)) @@ -464,6 +470,20 @@ def report_status(): debug.error("{0} is not an integer in config file.".format(OPTS.word_size)) if type(OPTS.num_words)!=int: debug.error("{0} is not an integer in config file.".format(OPTS.sram_size)) + if type(OPTS.write_size) is not int and OPTS.write_size is not None: + debug.error("{0} is not an integer in config file.".format(OPTS.write_size)) + + # If a write mask is specified by the user, the mask write size should be the same as + # the word size so that an entire word is written at once. + if OPTS.write_size is not None: + if (OPTS.word_size % OPTS.write_size != 0): + debug.error("Write size needs to be an integer multiple of word size.") + # If write size is more than half of the word size, then it doesn't need a write mask. It would be writing + # the whole word. + if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2): + debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size)) + + if not OPTS.tech_name: debug.error("Tech name must be specified in config file.") @@ -477,9 +497,12 @@ def report_status(): debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, OPTS.num_words, OPTS.num_banks)) + if (OPTS.write_size != OPTS.word_size): + debug.print_raw("Write size: {}".format(OPTS.write_size)) debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, OPTS.num_r_ports, OPTS.num_w_ports)) + if OPTS.netlist_only: debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).") diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a854c40b..c0c9d1a0 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, parameter @@ -28,13 +28,19 @@ class bank(design.design): def __init__(self, sram_config, name=""): + self.sram_config = sram_config sram_config.set_local_config(self) + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + else: + self.num_wmasks = 0 if name == "": name = "bank_{0}_{1}".format(self.word_size, self.num_words) design.design.__init__(self, name) 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, # so this prefix will be added to all of the input signals to create # the internal gated signals. @@ -47,12 +53,13 @@ class bank(design.design): if not OPTS.netlist_only: debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.") self.create_layout() + self.add_boundary() def create_netlist(self): self.compute_sizes() - self.add_pins() self.add_modules() + self.add_pins() # Must create the replica bitcell array first self.create_instances() @@ -74,10 +81,12 @@ class bank(design.design): """ Adding pins for Bank module""" for port in self.read_ports: 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.all_ports: + self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT") for port in self.write_ports: 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 bit in range(self.addr_size): self.add_pin("addr{0}_{1}".format(port,bit),"INPUT") @@ -89,10 +98,12 @@ class bank(design.design): self.add_pin("bank_sel{}".format(port),"INPUT") for port in self.read_ports: 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") for port in self.write_ports: self.add_pin("w_en{0}".format(port), "INPUT") + for bit in range(self.num_wmasks): + self.add_pin("bank_wmask{0}_{1}".format(port,bit),"INPUT") for port in self.all_ports: self.add_pin("wl_en{0}".format(port), "INPUT") self.add_pin("vdd","POWER") @@ -105,52 +116,45 @@ class bank(design.design): for port in self.all_ports: self.route_bitlines(port) - self.route_wordline_driver(port) - self.route_row_decoder(port) + self.route_rbl(port) + self.route_port_address(port) self.route_column_address_lines(port) self.route_control_lines(port) if self.num_banks > 1: - self.route_bank_select(port) + self.route_bank_select(port) self.route_supplies() + def route_rbl(self,port): + """ Route the rbl_bl and rbl_wl """ + + 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): """ Route the bitlines depending on the port type rw, w, or r. """ + + if port in self.write_ports: + self.route_port_data_in(port) + if port in self.read_ports: + self.route_port_data_out(port) + self.route_port_data_to_bitcell_array(port) - if port in self.readwrite_ports: - # write_driver -> sense_amp -> (column_mux) -> precharge -> bitcell_array - self.route_write_driver_in(port) - self.route_sense_amp_out(port) - self.route_write_driver_to_sense_amp(port) - self.route_sense_amp_to_column_mux_or_precharge_array(port) - self.route_column_mux_to_precharge_array(port) - self.route_precharge_to_bitcell_array(port) - elif port in self.read_ports: - # sense_amp -> (column_mux) -> precharge -> bitcell_array - self.route_sense_amp_out(port) - self.route_sense_amp_to_column_mux_or_precharge_array(port) - self.route_column_mux_to_precharge_array(port) - self.route_precharge_to_bitcell_array(port) - else: - # write_driver -> (column_mux) -> bitcell_array - self.route_write_driver_in(port) - self.route_write_driver_to_column_mux_or_bitcell_array(port) - self.route_column_mux_to_bitcell_array(port) def create_instances(self): """ Create the instances of the netlist. """ self.create_bitcell_array() - - self.create_precharge_array() - self.create_column_mux_array() - self.create_sense_amp_array() - self.create_write_driver_array() - - self.create_row_decoder() - self.create_wordline_driver() + self.create_port_data() + self.create_port_address() self.create_column_decoder() - self.create_bank_select() def compute_instance_offsets(self): @@ -158,39 +162,26 @@ class bank(design.design): Compute the empty instance offsets for port0 and port1 (if needed) """ - # These are created even if the port type (e.g. read only) - # doesn't need the instance (e.g. write driver). - - # Create the bottom-up and left to right order of components in each port - # which deepends on the port type rw, w, r - self.vertical_port_order = [] - self.vertical_port_offsets = [] - for port in self.all_ports: - self.vertical_port_order.append([]) - self.vertical_port_offsets.append([None]*4) - - # For later placement, these are fixed in the order: write driver, - # sense amp, clumn mux, precharge, even if the item is not used - # in a given port (it will be None then) - self.vertical_port_order[port].append(self.write_driver_array_inst[port]) - self.vertical_port_order[port].append(self.sense_amp_array_inst[port]) - self.vertical_port_order[port].append(self.column_mux_array_inst[port]) - self.vertical_port_order[port].append(self.precharge_array_inst[port]) - - # For the odd ones they will go on top, so reverse in place - if port%2: - self.vertical_port_order[port]=self.vertical_port_order[port][::-1] - - self.write_driver_offsets = [None]*len(self.all_ports) - self.sense_amp_offsets = [None]*len(self.all_ports) - self.column_mux_offsets = [None]*len(self.all_ports) - self.precharge_offsets = [None]*len(self.all_ports) - - self.wordline_driver_offsets = [None]*len(self.all_ports) - self.row_decoder_offsets = [None]*len(self.all_ports) + self.port_data_offsets = [None]*len(self.all_ports) + self.port_address_offsets = [None]*len(self.all_ports) self.column_decoder_offsets = [None]*len(self.all_ports) self.bank_select_offsets = [None]*len(self.all_ports) + + + # The center point for these cells are the upper-right corner of + # the bitcell array. + # The port address decoder/driver logic is placed on the right and mirrored on Y-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_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() if len(self.all_ports)==2: @@ -199,7 +190,7 @@ class bank(design.design): 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 @@ -210,110 +201,71 @@ class bank(design.design): # LOWER RIGHT QUADRANT # Below the bitcell array - y_height = 0 - for p in self.vertical_port_order[port]: - if p==None: - continue - y_height += p.height + self.m2_gap - - y_offset = -y_height - for i,p in enumerate(self.vertical_port_order[port]): - if p==None: - continue - self.vertical_port_offsets[port][i]=vector(0,y_offset) - y_offset += (p.height + self.m2_gap) - - self.write_driver_offsets[port] = self.vertical_port_offsets[port][0] - self.sense_amp_offsets[port] = self.vertical_port_offsets[port][1] - self.column_mux_offsets[port] = self.vertical_port_offsets[port][2] - self.precharge_offsets[port] = self.vertical_port_offsets[port][3] + self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0) # UPPER LEFT QUADRANT # 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.wordline_driver.width - self.wordline_driver_offsets[port] = vector(-x_offset,0) - x_offset += self.row_decoder.width + self.m2_gap - self.row_decoder_offsets[port] = vector(-x_offset,0) + x_offset = self.m2_gap + self.port_address.width + self.port_address_offsets[port] = vector(-x_offset,self.main_bitcell_array_bottom) # LOWER LEFT QUADRANT - # Place the col decoder left aligned with wordline driver plus halfway under row decoder - # Place the col decoder left aligned with row decoder (x_offset doesn't change) - # Below the bitcell array with well spacing - x_offset = self.central_bus_width[port] + self.wordline_driver.width + # Place the col decoder left aligned with wordline driver + # This is also placed so that it's supply rails do not align with the SRAM-level + # 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 if self.col_addr_size > 0: 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: y_offset = 0 - y_offset += 2*drc("well_to_well") self.column_decoder_offsets[port] = vector(-x_offset,-y_offset) # Bank select gets placed below the column decoder (x_offset doesn't change) if self.col_addr_size > 0: - y_offset = min(self.column_decoder_offsets[port].y, self.column_mux_offsets[port].y) + y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y) else: - y_offset = self.row_decoder_offsets[port].y + y_offset = self.port_address_offsets[port].y if self.num_banks > 1: y_offset += self.bank_select.height + drc("well_to_well") self.bank_select_offsets[port] = vector(-x_offset,-y_offset) 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 - # The center point for these cells are the upper-right corner of - # the bitcell array. - # The 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. - # LOWER LEFT QUADRANT # Bitcell array is placed at (0,0) # UPPER LEFT QUADRANT # Above the bitcell array - y_offset = self.bitcell_array.height + self.m2_gap - for i,p in enumerate(self.vertical_port_order[port]): - if p==None: - continue - y_offset += (p.height + self.m2_gap) - self.vertical_port_offsets[port][i]=vector(0,y_offset) - - # Reversed order - self.write_driver_offsets[port] = self.vertical_port_offsets[port][3] - self.sense_amp_offsets[port] = self.vertical_port_offsets[port][2] - self.column_mux_offsets[port] = self.vertical_port_offsets[port][1] - self.precharge_offsets[port] = self.vertical_port_offsets[port][0] + self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top) # LOWER RIGHT QUADRANT # 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.width + self.m2_gap + self.wordline_driver.width - self.wordline_driver_offsets[port] = vector(x_offset,0) - x_offset += self.row_decoder.width + self.m2_gap - self.row_decoder_offsets[port] = vector(x_offset,0) + x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap + self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom) # 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 - x_offset = self.bitcell_array.width + self.central_bus_width[port] + self.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: x_offset += self.column_decoder.width + self.col_addr_bus_width - y_offset = self.bitcell_array.height + self.column_decoder.height + self.m2_gap + y_offset = self.bitcell_array_top + 0.5*self.dff.height + self.column_decoder.height else: - y_offset = self.bitcell_array.height - y_offset += 2*drc("well_to_well") + y_offset = self.bitcell_array_top self.column_decoder_offsets[port] = vector(x_offset,y_offset) # Bank select gets placed above the column decoder (x_offset doesn't change) if self.col_addr_size > 0: y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height, - self.column_mux_offsets[port].y + self.column_mux_array[port].height) + self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height) else: - y_offset = self.row_decoder_offsets[port].y + y_offset = self.port_address_offsets[port].y self.bank_select_offsets[port] = vector(x_offset,y_offset) def place_instances(self): @@ -321,22 +273,12 @@ class bank(design.design): self.compute_instance_offsets() - # UPPER RIGHT QUADRANT self.place_bitcell_array(self.bitcell_array_offset) - # LOWER RIGHT QUADRANT - # These are fixed in the order: write driver, sense amp, clumn mux, precharge, - # even if the item is not used in a given port (it will be None then) - self.place_write_driver_array(self.write_driver_offsets) - self.place_sense_amp_array(self.sense_amp_offsets) - self.place_column_mux_array(self.column_mux_offsets) - self.place_precharge_array(self.precharge_offsets) + self.place_port_data(self.port_data_offsets) - # UPPER LEFT QUADRANT - self.place_row_decoder(self.row_decoder_offsets) - self.place_wordline_driver(self.wordline_driver_offsets) + self.place_port_address(self.port_address_offsets) - # LOWER LEFT QUADRANT self.place_column_decoder(self.column_decoder_offsets) self.place_bank_select(self.bank_select_offsets) @@ -354,22 +296,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.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: self.input_control_signals = [] port_num = 0 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(["w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) port_num += 1 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(["w_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) port_num += 1 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(["s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)]) port_num += 1 # Number of control lines in the bus for each port @@ -401,65 +338,40 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - - self.bitcell_array = factory.create(module_type="bitcell_array", - cols=self.num_cols, - rows=self.num_rows) - self.add_mod(self.bitcell_array) - # create arrays of bitline and bitline_bar names for read, write, or all ports self.bitcell = factory.create(module_type="bitcell") - self.bl_names = self.bitcell.list_all_bl_names() - self.br_names = self.bitcell.list_all_br_names() - self.wl_names = self.bitcell.list_all_wl_names() - self.bitline_names = self.bitcell.list_all_bitline_names() + self.bl_names = self.bitcell.get_all_bl_names() + self.br_names = self.bitcell.get_all_br_names() + self.wl_names = self.bitcell.get_all_wl_names() + self.bitline_names = self.bitcell.get_all_bitline_names() - self.precharge_array = [] + self.port_data = [] for port in self.all_ports: - if port in self.read_ports: - temp_pre = factory.create(module_type="precharge_array", - columns=self.num_cols, - bitcell_bl=self.bl_names[port], - bitcell_br=self.br_names[port]) - self.precharge_array.append(temp_pre) - self.add_mod(self.precharge_array[port]) - else: - self.precharge_array.append(None) - - if self.col_addr_size > 0: - self.column_mux_array = [] - for port in self.all_ports: - temp_col = factory.create(module_type="column_mux_array", - columns=self.num_cols, - word_size=self.word_size, - bitcell_bl=self.bl_names[port], - bitcell_br=self.br_names[port]) - self.column_mux_array.append(temp_col) - self.add_mod(self.column_mux_array[port]) + temp_pre = factory.create(module_type="port_data", + sram_config=self.sram_config, + port=port) + self.port_data.append(temp_pre) + self.add_mod(self.port_data[port]) - self.sense_amp_array = factory.create(module_type="sense_amp_array", - word_size=self.word_size, - words_per_row=self.words_per_row) - self.add_mod(self.sense_amp_array) + self.port_address = factory.create(module_type="port_address", + cols=self.num_cols, + rows=self.num_rows) + self.add_mod(self.port_address) - self.write_driver_array = factory.create(module_type="write_driver_array", - columns=self.num_cols, - word_size=self.word_size) - self.add_mod(self.write_driver_array) - self.row_decoder = factory.create(module_type="decoder", - rows=self.num_rows) - self.add_mod(self.row_decoder) + self.port_rbl_map = self.all_ports + self.num_rbl = len(self.all_ports) + + self.bitcell_array = factory.create(module_type="replica_bitcell_array", + cols=self.num_cols, + rows=self.num_rows, + left_rbl=1, + right_rbl=1 if len(self.all_ports)>1 else 0, + bitcell_ports=self.all_ports) + self.add_mod(self.bitcell_array) + - self.wordline_driver = factory.create(module_type="wordline_driver", - rows=self.num_rows, - cols=self.num_cols) - self.add_mod(self.wordline_driver) - - self.inv = factory.create(module_type="pinv") - self.add_mod(self.inv) - if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") self.add_mod(self.bank_select) @@ -468,17 +380,23 @@ class bank(design.design): def create_bitcell_array(self): """ 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) - temp = [] for col in range(self.num_cols): 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 wordline in self.wl_names: - temp.append(wordline+"_{0}".format(row)) + temp.append("{0}_{1}".format(wordline,row)) + for port in self.all_ports: + temp.append("wl_en{0}".format(port)) temp.append("vdd") temp.append("gnd") self.connect_inst(temp) @@ -489,161 +407,73 @@ class bank(design.design): self.bitcell_array_inst.place(offset) - def create_precharge_array(self): - """ Creating Precharge """ - - self.precharge_array_inst = [None]*len(self.all_ports) - for port in self.read_ports: - self.precharge_array_inst[port]=self.add_inst(name="precharge_array{}".format(port), - mod=self.precharge_array[port]) - temp = [] - for i in range(self.num_cols): - temp.append(self.bl_names[port]+"_{0}".format(i)) - temp.append(self.br_names[port]+"_{0}".format(i)) - temp.extend([self.prefix+"p_en_bar{0}".format(port), "vdd"]) - self.connect_inst(temp) - - - def place_precharge_array(self, offsets): - """ Placing Precharge """ - - debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place precharge array.") - - for port in self.read_ports: - if port%2 == 1: - mirror = "MX" - else: - mirror = "R0" - self.precharge_array_inst[port].place(offset=offsets[port], mirror=mirror) - - - def create_column_mux_array(self): - """ Creating Column Mux when words_per_row > 1 . """ - self.column_mux_array_inst = [None]*len(self.all_ports) - - if self.col_addr_size == 0: - return + def create_port_data(self): + """ Creating Port Data """ + self.port_data_inst = [None]*len(self.all_ports) for port in self.all_ports: - self.column_mux_array_inst[port] = self.add_inst(name="column_mux_array{}".format(port), - mod=self.column_mux_array[port]) + self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), + mod=self.port_data[port]) temp = [] - for col in range(self.num_cols): - temp.append(self.bl_names[port]+"_{0}".format(col)) - temp.append(self.br_names[port]+"_{0}".format(col)) - for word in range(self.words_per_row): - temp.append("sel{0}_{1}".format(port,word)) - for bit in range(self.word_size): - temp.append(self.bl_names[port]+"_out_{0}".format(bit)) - temp.append(self.br_names[port]+"_out_{0}".format(bit)) - temp.append("gnd") + 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): + temp.append("{0}_{1}".format(self.bl_names[port],col)) + temp.append("{0}_{1}".format(self.br_names[port],col)) + if port in self.read_ports: + for bit in range(self.word_size): + temp.append("dout{0}_{1}".format(port,bit)) + if port in self.write_ports: + for bit in range(self.word_size): + temp.append("din{0}_{1}".format(port,bit)) + # Will be empty if no col addr lines + sel_names = ["sel{0}_{1}".format(port,x) for x in range(self.num_col_addr_lines)] + temp.extend(sel_names) + if port in self.read_ports: + temp.append("s_en{0}".format(port)) + temp.append("p_en_bar{0}".format(port)) + if port in self.write_ports: + temp.append("w_en{0}".format(port)) + for bit in range(self.num_wmasks): + temp.append("bank_wmask{0}_{1}".format(port, bit)) + temp.extend(["vdd","gnd"]) + self.connect_inst(temp) - - def place_column_mux_array(self, offsets): - """ Placing Column Mux when words_per_row > 1 . """ - if self.col_addr_size == 0: - return - - debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column mux array.") + def place_port_data(self, offsets): + """ Placing Port Data """ for port in self.all_ports: + # Top one is unflipped, bottom is flipped along X direction if port%2 == 1: - mirror = "MX" - else: mirror = "R0" - self.column_mux_array_inst[port].place(offset=offsets[port], mirror=mirror) - - - def create_sense_amp_array(self): - """ Creating Sense amp """ - - self.sense_amp_array_inst = [None]*len(self.all_ports) - for port in self.read_ports: - self.sense_amp_array_inst[port] = self.add_inst(name="sense_amp_array{}".format(port), - mod=self.sense_amp_array) - - temp = [] - for bit in range(self.word_size): - temp.append("dout{0}_{1}".format(port,bit)) - if self.words_per_row == 1: - temp.append(self.bl_names[port]+"_{0}".format(bit)) - temp.append(self.br_names[port]+"_{0}".format(bit)) - else: - temp.append(self.bl_names[port]+"_out_{0}".format(bit)) - temp.append(self.br_names[port]+"_out_{0}".format(bit)) - - temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"]) - self.connect_inst(temp) - - - def place_sense_amp_array(self, offsets): - """ Placing Sense amp """ - - debug.check(len(offsets)>=len(self.read_ports), "Insufficient offsets to place sense amp array.") - for port in self.read_ports: - if port%2 == 1: - mirror = "MX" else: - mirror = "R0" - self.sense_amp_array_inst[port].place(offset=offsets[port], mirror=mirror) - - - def create_write_driver_array(self): - """ Creating Write Driver """ - - self.write_driver_array_inst = [None]*len(self.all_ports) - for port in self.write_ports: - self.write_driver_array_inst[port] = self.add_inst(name="write_driver_array{}".format(port), - mod=self.write_driver_array) - - temp = [] - for bit in range(self.word_size): - temp.append("din{0}_{1}".format(port,bit)) - for bit in range(self.word_size): - if (self.words_per_row == 1): - temp.append(self.bl_names[port]+"_{0}".format(bit)) - temp.append(self.br_names[port]+"_{0}".format(bit)) - else: - temp.append(self.bl_names[port]+"_out_{0}".format(bit)) - temp.append(self.br_names[port]+"_out_{0}".format(bit)) - temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"]) - self.connect_inst(temp) - - - def place_write_driver_array(self, offsets): - """ Placing Write Driver """ - - debug.check(len(offsets)>=len(self.write_ports), "Insufficient offsets to place write driver array.") - - for port in self.write_ports: - if port%2 == 1: mirror = "MX" - else: - mirror = "R0" - self.write_driver_array_inst[port].place(offset=offsets[port], mirror=mirror) - + self.port_data_inst[port].place(offset=offsets[port], mirror=mirror) - def create_row_decoder(self): + def create_port_address(self): """ Create the hierarchical row decoder """ - self.row_decoder_inst = [None]*len(self.all_ports) + self.port_address_inst = [None]*len(self.all_ports) for port in self.all_ports: - self.row_decoder_inst[port] = self.add_inst(name="row_decoder{}".format(port), - mod=self.row_decoder) + self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port), + mod=self.port_address) temp = [] for bit in range(self.row_addr_size): temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size)) + temp.append("wl_en{0}".format(port)) for row in range(self.num_rows): - temp.append("dec_out{0}_{1}".format(port,row)) + temp.append("{0}_{1}".format(self.wl_names[port],row)) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) - def place_row_decoder(self, offsets): + def place_port_address(self, offsets): """ Place the hierarchical row decoder """ debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.") @@ -655,43 +485,11 @@ class bank(design.design): # The address flop and decoder are aligned in the x coord. for port in self.all_ports: - if port%2 == 1: + if port%2: mirror = "MY" else: mirror = "R0" - self.row_decoder_inst[port].place(offset=offsets[port], mirror=mirror) - - - def create_wordline_driver(self): - """ Create the Wordline Driver """ - - self.wordline_driver_inst = [None]*len(self.all_ports) - for port in self.all_ports: - self.wordline_driver_inst[port] = self.add_inst(name="wordline_driver{}".format(port), - mod=self.wordline_driver) - - temp = [] - for row in range(self.num_rows): - temp.append("dec_out{0}_{1}".format(port,row)) - for row in range(self.num_rows): - temp.append(self.wl_names[port]+"_{0}".format(row)) - temp.append(self.prefix+"wl_en{0}".format(port)) - temp.append("vdd") - temp.append("gnd") - self.connect_inst(temp) - - - def place_wordline_driver(self, offsets): - """ Place the Wordline Driver """ - - debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place wordline driver array.") - - for port in self.all_ports: - if port%2 == 1: - mirror = "MY" - else: - mirror = "R0" - self.wordline_driver_inst[port].place(offset=offsets[port], mirror=mirror) + self.port_address_inst[port].place(offset=offsets[port], mirror=mirror) def create_column_decoder(self): @@ -699,16 +497,16 @@ class bank(design.design): 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: return 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: - 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: - 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: # No error checking before? debug.error("Invalid column decoder?",-1) @@ -790,8 +588,8 @@ class bank(design.design): 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"] elif self.port_id[port] == "w": - bank_sel_signals = ["clk_buf", "w_en", "bank_sel"] - gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en"] + bank_sel_signals = ["clk_buf", "w_en", "p_en_bar", "bank_sel"] + gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_p_en_bar"] else: 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"] @@ -845,9 +643,9 @@ class bank(design.design): # Port 0 # 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 - 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 - 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", pitch=self.m2_pitch, offset=control_bus_offset, @@ -859,122 +657,52 @@ class bank(design.design): # Port 1 if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array - control_bus_length = self.max_y_offset - self.bitcell_array.height - 2*self.m1_pitch - control_bus_offset = vector(self.bitcell_array.width + self.m2_width, + control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch + control_bus_offset = vector(self.bitcell_array_right + self.m2_pitch, 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", pitch=self.m2_pitch, offset=control_bus_offset, - names=self.control_signals[1], + names=list(reversed(self.control_signals[1])), length=control_bus_length, vertical=True, make_pins=(self.num_banks==1)) - def route_precharge_to_bitcell_array(self, port): - """ Routing of BL and BR between pre-charge and bitcell array """ + def route_port_data_to_bitcell_array(self, port): + """ Routing of BL and BR between port data and bitcell array """ - inst2 = self.precharge_array_inst[port] + # Connect the regular bitlines + inst2 = self.port_data_inst[port] inst1 = self.bitcell_array_inst inst1_bl_name = self.bl_names[port]+"_{}" inst1_br_name = self.br_names[port]+"_{}" + self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols, inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) + + # Connect the replica bitlines + 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_column_mux_to_precharge_array(self, port): - """ Routing of BL and BR between col mux and precharge array """ - - # Only do this if we have a column mux! - if self.col_addr_size==0: - return - inst1 = self.column_mux_array_inst[port] - inst2 = self.precharge_array_inst[port] - self.connect_bitlines(inst1, inst2, self.num_cols) + def route_port_data_out(self, port): + """ Add pins for the port data out """ - def route_column_mux_to_bitcell_array(self, port): - """ Routing of BL and BR between col mux bitcell array """ - - # Only do this if we have a column mux! - if self.col_addr_size==0: - return - - inst2 = self.column_mux_array_inst[port] - inst1 = self.bitcell_array_inst - inst1_bl_name = self.bl_names[port]+"_{}" - inst1_br_name = self.br_names[port]+"_{}" - - # The column mux is constructed to match the bitline pitch, so we can directly connect - # here and not channel route the bitlines. - self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) - - - - def route_sense_amp_to_column_mux_or_precharge_array(self, port): - """ Routing of BL and BR between sense_amp and column mux or precharge array """ - inst2 = self.sense_amp_array_inst[port] - - if self.col_addr_size>0: - # Sense amp is connected to the col mux - inst1 = self.column_mux_array_inst[port] - inst1_bl_name = "bl_out_{}" - inst1_br_name = "br_out_{}" - else: - # Sense amp is directly connected to the precharge array - inst1 = self.precharge_array_inst[port] - inst1_bl_name = "bl_{}" - inst1_br_name = "br_{}" - - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) - - def route_write_driver_to_column_mux_or_bitcell_array(self, port): - """ Routing of BL and BR between sense_amp and column mux or bitcell array """ - inst2 = self.write_driver_array_inst[port] - - if self.col_addr_size>0: - # Write driver is connected to the col mux - inst1 = self.column_mux_array_inst[port] - inst1_bl_name = "bl_out_{}" - inst1_br_name = "br_out_{}" - else: - # Write driver is directly connected to the bitcell array - inst1 = self.bitcell_array_inst - inst1_bl_name = self.bl_names[port]+"_{}" - inst1_br_name = self.br_names[port]+"_{}" - - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) - - def route_write_driver_to_sense_amp(self, port): - """ Routing of BL and BR between write driver and sense amp """ - - inst1 = self.write_driver_array_inst[port] - inst2 = self.sense_amp_array_inst[port] - - # These should be pitch matched in the cell library, - # but just in case, do a channel route. - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) - - - - def route_sense_amp_out(self, port): - """ Add pins for the sense amp output """ - for bit in range(self.word_size): - data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit)) + data_pin = self.port_data_inst[port].get_pin("dout_{0}".format(bit)) self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit), layer=data_pin.layer, offset=data_pin.center(), height=data_pin.height(), width=data_pin.width()) + - - def route_row_decoder(self, port): + def route_port_address_in(self, port): """ Routes the row decoder inputs and supplies """ # Create inputs for the row address lines @@ -982,16 +710,25 @@ class bank(design.design): addr_idx = row + self.col_addr_size decoder_name = "addr_{}".format(row) addr_name = "addr{0}_{1}".format(port,addr_idx) - self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name) - - - def route_write_driver_in(self, port): - """ Connecting write driver """ + self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name) + + + + def route_port_data_in(self, port): + """ Connecting port data in """ for row in range(self.word_size): - data_name = "data_{}".format(row) + data_name = "din_{}".format(row) din_name = "din{0}_{1}".format(port,row) - self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name) + self.copy_layout_pin(self.port_data_inst[port], data_name, din_name) + + if self.word_size: + for row in range(self.num_wmasks): + wmask_name = "bank_wmask_{}".format(row) + bank_wmask_name = "bank_wmask{0}_{1}".format(port, row) + self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name) + + def channel_route_bitlines(self, inst1, inst2, num_bits, inst1_bl_name="bl_{}", inst1_br_name="br_{}", @@ -1019,12 +756,9 @@ class bank(design.design): route_map = list(zip(bottom_names, top_names)) self.create_horizontal_channel_route(route_map, offset) - - def connect_bitlines(self, inst1, inst2, num_bits, - inst1_bl_name="bl_{}", inst1_br_name="br_{}", - inst2_bl_name="bl_{}", inst2_br_name="br_{}"): + def connect_bitline(self, inst1, inst2, inst1_name, inst2_name): """ - 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 in the middle between the two modules (if needed). """ @@ -1032,66 +766,66 @@ class bank(design.design): # determine top and bottom automatically. # since they don't overlap, we can just check the bottom y coordinate. if inst1.by() < inst2.by(): - (bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name) - (top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name) + (bottom_inst, bottom_name) = (inst1, inst1_name) + (top_inst, top_name) = (inst2, inst2_name) else: - (bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) - (top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) + (bottom_inst, bottom_name) = (inst2, inst2_name) + (top_inst, top_name) = (inst1, inst1_name) - for col in range(num_bits): - bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col)).uc() - bottom_br = bottom_inst.get_pin(bottom_br_name.format(col)).uc() - 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]) + 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 route_wordline_driver(self, port): + 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): + self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col)) + self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col)) + + + def route_port_address(self, port): """ Connect Wordline driver to bitcell array wordline """ + + self.route_port_address_in(port) + if port%2: - self.route_wordline_driver_right(port) + self.route_port_address_right(port) else: - self.route_wordline_driver_left(port) + self.route_port_address_left(port) - def route_wordline_driver_left(self, port): + def route_port_address_left(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ for row in range(self.num_rows): - # The pre/post is to access the pin from "outside" the cell to avoid DRCs - decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc() - driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).lc() - mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) - mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) - self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) - # The mid guarantees we exit the input cell to the right. - driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() + driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() - mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) - def route_wordline_driver_right(self, port): + def route_port_address_right(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ for row in range(self.num_rows): - # The pre/post is to access the pin from "outside" the cell to avoid DRCs - decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).lc() - driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).rc() - mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) - mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) - self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) - # The mid guarantees we exit the input cell to the right. - driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() + driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() - mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) @@ -1126,7 +860,7 @@ class bank(design.design): decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names] sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] - column_mux_pins = [self.column_mux_array_inst[port].get_pin(x) for x in sel_names] + column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names] route_map = list(zip(decode_pins, column_mux_pins)) self.create_vertical_channel_route(route_map, offset) @@ -1188,86 +922,58 @@ class bank(design.design): read_inst = 0 connection = [] - if port in self.read_ports: - connection.append((self.prefix+"p_en_bar{}".format(port), self.precharge_array_inst[port].get_pin("en_bar").lc())) - + 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+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc())) + if port in self.write_ports: - connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[port].get_pin("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: - connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[port].get_pin("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: + control_mid_pos = self.bus_xoffset[port][control_signal] 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"), offset=control_pos) + # clk to wordline_driver control_signal = self.prefix+"wl_en{}".format(port) if port%2: - pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").uc() - mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus + pin_pos = self.port_address_inst[port].get_pin("wl_en").uc() + mid_pos = pin_pos + vector(0,2*self.m2_gap) # to route down to the top of the bus else: - pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").bc() - mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus + pin_pos = self.port_address_inst[port].get_pin("wl_en").bc() + mid_pos = pin_pos - vector(0,2*self.m2_gap) # to route down to the top of the bus control_x_offset = self.bus_xoffset[port][control_signal].x control_pos = vector(control_x_offset, mid_pos.y) self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos]) self.add_via_center(layers=("metal1", "via1", "metal2"), offset=control_pos) - - def analytical_delay(self, corner, slew, load, port): - """ return analytical delay of the bank. This will track the clock to output path""" - #FIXME: This delay is determined in the control logic. Should be moved here. - # word_driver_delay = self.wordline_driver.analytical_delay(corner, - # slew, - # self.bitcell_array.input_load()) - - #FIXME: Array delay is the same for every port. - word_driver_slew = 0 - if self.words_per_row > 1: - bitline_ext_load = self.column_mux_array[port].get_drain_cin() - else: - bitline_ext_load = self.sense_amp_array.get_drain_cin() - - bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew, bitline_ext_load) - - bitcell_array_slew = 0 - #This also essentially creates the same delay for each port. Good structure, no substance - if self.words_per_row > 1: - sa_load = self.sense_amp_array.get_drain_cin() - column_mux_delay = self.column_mux_array[port].analytical_delay(corner, - bitcell_array_slew, - sa_load) - else: - column_mux_delay = [] - - column_mux_slew = 0 - sense_amp_delay = self.sense_amp_array.analytical_delay(corner, - column_mux_slew, - load) - # output load of bitcell_array is set to be only small part of bl for sense amp. - return bitcell_array_delay + column_mux_delay + sense_amp_delay - + def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" #Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption stage_effort_list = [] wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout - stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise) + stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise) return stage_effort_list def get_wl_en_cin(self): """Get the relative capacitance of all the clk connections in the bank""" #wl_en only used in the wordline driver. - return self.wordline_driver.get_wl_en_cin() + return self.port_address.wordline_driver.get_wl_en_cin() def get_w_en_cin(self): """Get the relative capacitance of all the clk connections in the bank""" #wl_en only used in the wordline driver. - return self.write_driver.get_w_en_cin() + port = self.write_ports[0] + return self.port_data[port].write_driver.get_w_en_cin() def get_clk_bar_cin(self): """Get the relative capacitance of all the clk_bar connections in the bank""" @@ -1275,9 +981,21 @@ class bank(design.design): #Precharges are the all the same in Mulitport, one is picked port = self.read_ports[0] - return self.precharge_array[port].get_en_cin() + return self.port_data[port].precharge_array.get_en_cin() def get_sen_cin(self): """Get the relative capacitance of all the sense amp enable connections in the bank""" #Current bank only uses sen as an enable for the sense amps. - return self.sense_amp_array.get_en_cin() + port = self.read_ports[0] + return self.port_data[port].sense_amp_array.get_en_cin() + + def graph_exclude_precharge(self): + """Precharge adds a loop between bitlines, can be excluded to reduce complexity""" + for port in self.read_ports: + if self.port_data[port]: + self.port_data[port].graph_exclude_precharge() + + def get_cell_name(self, inst_name, row, col): + """Gets the spice name of the target bitcell.""" + return self.bitcell_array_inst.mod.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col) + diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index ac866456..296cef8b 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, parameter @@ -42,6 +42,7 @@ class bank_select(design.design): self.place_instances() self.route_instances() + self.add_boundary() self.DRC_LVS() @@ -88,7 +89,7 @@ class bank_select(design.design): self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4) self.add_mod(self.inv4x_nor) - self.nand2 = factory.create(module_type="pnand2") + self.nand2 = factory.create(module_type="pnand2", height=height) self.add_mod(self.nand2) def calculate_module_offsets(self): diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index f2ab77ac..bf4932a3 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -45,8 +45,8 @@ class bitcell_array(design.design): def create_layout(self): # We increase it by a well enclosure so the precharges don't overlap our wells - self.height = self.row_size*self.cell.height + drc("well_enclosure_active") + self.m1_width - self.width = self.column_size*self.cell.width + self.m1_width + self.height = self.row_size*self.cell.height + self.width = self.column_size*self.cell.width xoffset = 0.0 for col in range(self.column_size): @@ -68,25 +68,45 @@ class bitcell_array(design.design): self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() def add_pins(self): - row_list = self.cell.list_all_wl_names() - column_list = self.cell.list_all_bitline_names() + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() for col in range(self.column_size): 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 cell_row in row_list: - self.add_pin(cell_row+"_{0}".format(row)) - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin(cell_row+"_{0}".format(row), "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type="bitcell") self.add_mod(self.cell) + 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 """ + + bitcell_pins = [] + + pin_names = self.cell.get_all_bitline_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(col)) + pin_names = self.cell.get_all_wl_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(row)) + bitcell_pins.append("vdd") + bitcell_pins.append("gnd") + + return bitcell_pins + + def create_instances(self): """ Create the module instances used in this design """ self.cell_inst = {} @@ -95,40 +115,32 @@ class bitcell_array(design.design): name = "bit_r{0}_c{1}".format(row, col) self.cell_inst[row,col]=self.add_inst(name=name, mod=self.cell) - self.connect_inst(self.cell.list_bitcell_pins(col, row)) + self.connect_inst(self.get_bitcell_pins(col, row)) def add_layout_pins(self): """ Add the layout pins """ - row_list = self.cell.list_all_wl_names() - column_list = self.cell.list_all_bitline_names() + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() - offset = vector(0.0, 0.0) for col in range(self.column_size): for cell_column in column_list: bl_pin = self.cell_inst[0,col].get_pin(cell_column) self.add_layout_pin(text=cell_column+"_{0}".format(col), - layer="metal2", - offset=bl_pin.ll(), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1,0), width=bl_pin.width(), height=self.height) - - # increments to the next column width - offset.x += self.cell.width - offset.x = 0.0 for row in range(self.row_size): for cell_row in row_list: wl_pin = self.cell_inst[row,0].get_pin(cell_row) self.add_layout_pin(text=cell_row+"_{0}".format(row), - layer="metal1", - offset=wl_pin.ll(), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0,1), width=self.width, height=wl_pin.height()) - # increments to the next row height - offset.y += self.cell.height - # For every second row and column, add a via for gnd and vdd for row in range(self.row_size): for col in range(self.column_size): @@ -136,17 +148,7 @@ class bitcell_array(design.design): for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) - - def analytical_delay(self, corner, slew, load): - """Returns relative delay of the bitline in the bitcell array""" - from tech import parameter - #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. - drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) - wire_unit_load = .05 * drain_load #Wires add 5% to this. - bitline_load = (drain_load+wire_unit_load)*self.row_size - return [self.cell.analytical_delay(corner, slew, load+bitline_load)] - + def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" from tech import drc, parameter @@ -154,7 +156,7 @@ class bitcell_array(design.design): # Dynamic Power from Bitline bl_wire = self.gen_bl_wire() 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"] bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) @@ -185,18 +187,22 @@ class bitcell_array(design.design): bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell return bl_wire - def output_load(self, bl_pos=0): - bl_wire = self.gen_bl_wire() - return bl_wire.wire_c # sense amp only need to charge small portion of the bl - # set as one segment for now - - def input_load(self): - wl_wire = self.gen_wl_wire() - return wl_wire.return_input_cap() - def get_wordline_cin(self): """Get the relative input capacitance from the wordline connections in all the bitcell""" #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns bitcell_wl_cin = self.cell.get_wl_cin() total_cin = bitcell_wl_cin * self.column_size return total_cin + + def graph_exclude_bits(self, targ_row, targ_col): + """Excludes bits in column from being added to graph except target""" + #Function is not robust with column mux configurations + for row in range(self.row_size): + for col in range(self.column_size): + if row == targ_row and col == targ_col: + continue + self.graph_inst_exclude.add(self.cell_inst[row,col]) + + def get_cell_name(self, inst_name, row, col): + """Gets the spice name of the target bitcell.""" + return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col] diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 0bf309a6..06883125 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -1,9 +1,9 @@ # 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. +# 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 math import log import design @@ -39,7 +39,7 @@ class control_logic(design.design): self.num_cols = word_size*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 #Determines how much larger the sen delay should be. Accounts for possible error in model. @@ -67,15 +67,14 @@ class control_logic(design.design): self.place_instances() self.route_all() #self.add_lvs_correspondence_points() + self.add_boundary() self.DRC_LVS() def add_pins(self): """ Add the pins to the control logic module. """ - for pin in self.input_list + ["clk"]: - self.add_pin(pin,"INPUT") - for pin in self.output_list: - self.add_pin(pin,"OUTPUT") + self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT") + self.add_pin_list(self.output_list,"OUTPUT") self.add_pin("vdd","POWER") self.add_pin("gnd","GROUND") @@ -95,18 +94,30 @@ class control_logic(design.design): size=4, height=dff_height) 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 + addr_flops = math.log(self.num_words,2) + math.log(self.words_per_row,2) + # plus data flops and control flops + num_flops = addr_flops + self.word_size + self.num_control_signals + # each flop internally has a FO 5 approximately # plus about 5 fanouts for the control logic - # each flop internally has a FO 4 approximately - clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \ - + self.num_control_signals) + 5 + clock_fanout = 5*num_flops + 5 self.clk_buf_driver = factory.create(module_type="pdriver", fanout=clock_fanout, height=dff_height) self.add_mod(self.clk_buf_driver) + # We will use the maximum since this same value is used to size the wl_en + # and the p_en_bar drivers + max_fanout = max(self.num_rows,self.num_cols) + # wl_en drives every row in the bank self.wl_en_driver = factory.create(module_type="pdriver", fanout=self.num_rows, @@ -114,70 +125,79 @@ class control_logic(design.design): self.add_mod(self.wl_en_driver) # w_en drives every write driver - self.w_en_driver = factory.create(module_type="pdriver", - fanout=self.word_size+8, - height=dff_height) - self.add_mod(self.w_en_driver) + self.wen_and = factory.create(module_type="pand3", + size=self.word_size+8, + height=dff_height) + self.add_mod(self.wen_and) # s_en drives every sense amp - self.s_en_driver = factory.create(module_type="pdriver", - fanout=self.word_size, - height=dff_height) - self.add_mod(self.s_en_driver) + self.sen_and3 = factory.create(module_type="pand3", + size=self.word_size, + height=dff_height) + self.add_mod(self.sen_and3) # used to generate inverted signals with low fanout self.inv = factory.create(module_type="pinv", - size=1, - height=dff_height) + size=1, + height=dff_height) 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 + # but it is sized the same as the wl_en driver with + # prepended 3 inverter stages to guarantee it is slower and odd polarity self.p_en_bar_driver = factory.create(module_type="pdriver", - neg_polarity=True, fanout=self.num_cols, height=dff_height) self.add_mod(self.p_en_bar_driver) + + + self.nand2 = factory.create(module_type="pnand2", + height=dff_height) + self.add_mod(self.nand2) - if (self.port_type == "rw") or (self.port_type == "r"): - from importlib import reload - self.delay_chain_resized = False - c = reload(__import__(OPTS.replica_bitline)) - replica_bitline = getattr(c, OPTS.replica_bitline) - bitcell_loads = int(math.ceil(self.num_rows * parameter["rbl_height_percentage"])) - #Use a model to determine the delays with that heuristic - if OPTS.use_tech_delay_chain_size: #Use tech parameters if set. - fanout_list = parameter["static_fanout_list"] - debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list)) - self.replica_bitline = factory.create(module_type="replica_bitline", - delay_fanout_list=fanout_list, - bitcell_loads=bitcell_loads) - if self.sram != None: #Calculate model value even for specified sizes - self.set_sen_wl_delays() + # if (self.port_type == "rw") or (self.port_type == "r"): + # from importlib import reload + # self.delay_chain_resized = False + # c = reload(__import__(OPTS.replica_bitline)) + # replica_bitline = getattr(c, OPTS.replica_bitline) + # bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage)) + # #Use a model to determine the delays with that heuristic + # if OPTS.use_tech_delay_chain_size: #Use tech parameters if set. + # fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage] + # debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list)) + # self.replica_bitline = factory.create(module_type="replica_bitline", + # delay_fanout_list=fanout_list, + # bitcell_loads=bitcell_loads) + # 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. - #First use a heuristic - delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() - self.replica_bitline = factory.create(module_type="replica_bitline", - delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, - bitcell_loads=bitcell_loads) - #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(): - #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) - self.replica_bitline = factory.create(module_type="replica_bitline", - delay_fanout_list=stage_list, - bitcell_loads=bitcell_loads) + # else: #Otherwise, use a heuristic and/or model based sizing. + # #First use a heuristic + # delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() + # self.replica_bitline = factory.create(module_type="replica_bitline", + # delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, + # bitcell_loads=bitcell_loads) + # #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(): + # #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) + # self.replica_bitline = factory.create(module_type="replica_bitline", + # delay_fanout_list=stage_list, + # bitcell_loads=bitcell_loads) - #This resizes based on total delay. - # 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", - # delay_fanout_list=[delay_fanout]*delay_stages, - # bitcell_loads=bitcell_loads) + # #This resizes based on total delay. + # # 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", + # # delay_fanout_list=[delay_fanout]*delay_stages, + # # bitcell_loads=bitcell_loads) - self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing - self.delay_chain_resized = True - - self.add_mod(self.replica_bitline) + # self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing + # self.delay_chain_resized = True + + 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): """Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """ @@ -311,9 +331,11 @@ class control_logic(design.design): # List of input control signals if self.port_type == "rw": self.input_list = ["csb", "web"] + self.rbl_list = ["rbl_bl"] else: self.input_list = ["csb"] - + self.rbl_list = ["rbl_bl"] + if self.port_type == "rw": self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"] else: @@ -321,21 +343,22 @@ class control_logic(design.design): # list of output control signals (for making a vertical bus) if self.port_type == "rw": - self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"] + self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"] elif self.port_type == "r": - self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"] + self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"] else: - self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"] + self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"] # leave space for the bus plus one extra space self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch # Outputs to the bank if self.port_type == "rw": - self.output_list = ["s_en", "w_en", "p_en_bar"] + self.output_list = ["s_en", "w_en"] elif self.port_type == "r": - self.output_list = ["s_en", "p_en_bar"] + self.output_list = ["s_en"] else: self.output_list = ["w_en"] + self.output_list.append("p_en_bar") self.output_list.append("wl_en") self.output_list.append("clk_buf") @@ -358,13 +381,13 @@ class control_logic(design.design): self.create_gated_clk_buf_row() self.create_wlen_row() if (self.port_type == "rw") or (self.port_type == "w"): + self.create_rbl_delay_row() self.create_wen_row() - if self.port_type == "rw": - self.create_rbl_in_row() - if (self.port_type == "rw") or (self.port_type == "r"): - self.create_pen_row() + if (self.port_type == "rw") or (self.port_type == "r"): self.create_sen_row() - self.create_rbl() + self.create_delay() + self.create_pen_row() + def place_instances(self): @@ -391,20 +414,20 @@ class control_logic(design.design): row += 1 if (self.port_type == "rw") or (self.port_type == "w"): self.place_wen_row(row) - height = self.w_en_inst.uy() - control_center_y = self.w_en_inst.uy() + height = self.w_en_gate_inst.uy() + control_center_y = self.w_en_gate_inst.uy() row += 1 - if self.port_type == "rw": - self.place_rbl_in_row(row) + self.place_pen_row(row) + row += 1 + if (self.port_type == "rw") or (self.port_type == "w"): + self.place_rbl_delay_row(row) row += 1 if (self.port_type == "rw") or (self.port_type == "r"): - self.place_pen_row(row) - row += 1 self.place_sen_row(row) row += 1 - self.place_rbl(row) - height = self.rbl_inst.uy() - control_center_y = self.rbl_inst.by() + self.place_delay(row) + height = self.delay_inst.uy() + control_center_y = self.delay_inst.by() # This offset is used for placement of the control logic in the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y) @@ -414,7 +437,7 @@ class control_logic(design.design): # Max of modules or logic rows self.width = max([inst.rx() for inst in self.row_end_inst]) 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 def route_all(self): @@ -423,35 +446,48 @@ class control_logic(design.design): self.route_dffs() self.route_wlen() if (self.port_type == "rw") or (self.port_type == "w"): + self.route_rbl_delay() self.route_wen() if (self.port_type == "rw") or (self.port_type == "r"): - self.route_rbl_in() - self.route_pen() self.route_sen() + self.route_delay() + self.route_pen() self.route_clk_buf() self.route_gated_clk_bar() self.route_gated_clk_buf() self.route_supply() - def create_rbl(self): + def create_delay(self): """ Create the replica bitline """ - if self.port_type == "r": - input_name = "gated_clk_bar" - else: - 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"]) + self.delay_inst=self.add_inst(name="delay_chain", + mod=self.delay_chain) + self.connect_inst(["rbl_bl", "rbl_bl_delay", "vdd", "gnd"]) - def place_rbl(self,row): + def place_delay(self,row): """ Place the replica bitline """ y_off = row * self.and2.height + 2*self.m1_pitch # Add the RBL above the rows # Add to the right of the control rows and routing channel - offset = vector(0, y_off) - self.rbl_inst.place(offset) + offset = vector(self.delay_chain.width, y_off) + self.delay_inst.place(offset, mirror="MY") + + def route_delay(self): + + out_pos = self.delay_inst.get_pin("out").bc() + # Connect to the rail level with the vdd rail + # Use pen since it is in every type of control logic + vdd_ypos = self.p_en_bar_nand_inst.get_pin("vdd").by() + in_pos = vector(self.rail_offsets["rbl_bl_delay"].x,vdd_ypos) + mid1 = vector(out_pos.x,in_pos.y) + self.add_wire(("metal1","via1","metal2"),[out_pos, mid1, in_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=in_pos) + + + # Input from RBL goes to the delay line for futher delay + self.copy_layout_pin(self.delay_inst, "in", "rbl_bl") def create_clk_buf_row(self): @@ -461,12 +497,9 @@ class control_logic(design.design): self.connect_inst(["clk","clk_buf","vdd","gnd"]) def place_clk_buf_row(self,row): - """ Place the multistage clock buffer below the control flops """ - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) + x_offset = self.control_x_offset - offset = vector(x_off,y_off) - self.clk_buf_inst.place(offset, mirror) + x_offset = self.place_util(self.clk_buf_inst, x_offset, row) self.row_end_inst.append(self.clk_buf_inst) @@ -503,17 +536,10 @@ class control_logic(design.design): self.connect_inst(["cs","clk_bar","gated_clk_bar","vdd","gnd"]) def place_gated_clk_bar_row(self,row): - """ Place the gated clk logic below the control flops """ - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) + x_offset = self.control_x_offset - offset = vector(x_off,y_off) - self.clk_bar_inst.place(offset, mirror) - - x_off += self.inv.width - - offset = vector(x_off,y_off) - self.gated_clk_bar_inst.place(offset, mirror) + x_offset = self.place_util(self.clk_bar_inst, x_offset, row) + x_offset = self.place_util(self.gated_clk_bar_inst, x_offset, row) self.row_end_inst.append(self.gated_clk_bar_inst) @@ -547,12 +573,9 @@ class control_logic(design.design): self.connect_inst(["clk_buf", "cs","gated_clk_buf","vdd","gnd"]) def place_gated_clk_buf_row(self,row): - """ Place the gated clk logic below the control flops """ - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) - - offset = vector(x_off,y_off) - self.gated_clk_buf_inst.place(offset, mirror) + x_offset = self.control_x_offset + + x_offset = self.place_util(self.gated_clk_buf_inst, x_offset, row) self.row_end_inst.append(self.gated_clk_buf_inst) @@ -574,172 +597,139 @@ class control_logic(design.design): self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"]) def place_wlen_row(self, row): - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) - - offset = vector(x_off, y_off) - self.wl_en_inst.place(offset, mirror) + x_offset = self.control_x_offset + + x_offset = self.place_util(self.wl_en_inst, x_offset, row) self.row_end_inst.append(self.wl_en_inst) def route_wlen(self): wlen_map = zip(["A"], ["gated_clk_bar"]) - 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") - def create_rbl_in_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): - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) - - offset = vector(x_off, y_off) - self.rbl_in_inst.place(offset, mirror) - - self.row_end_inst.append(self.rbl_in_inst) - - def route_rbl_in(self): - """ Connect the logic for the rbl_in generation """ - - if self.port_type == "rw": - input_name = "we_bar" - # Connect the NAND gate inputs to the bus - 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) - - - # 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): - if self.port_type == "rw": - # input: gated_clk_bar, we_bar, output: pre_p_en - self.pre_p_en_inst=self.add_inst(name="and2_pre_p_en", - mod=self.and2) - self.connect_inst(["gated_clk_buf", "we_bar", "pre_p_en", "vdd", "gnd"]) - input_name = "pre_p_en" - else: - input_name = "gated_clk_buf" + self.p_en_bar_nand_inst=self.add_inst(name="nand_p_en_bar", + mod=self.nand2) + self.connect_inst(["gated_clk_buf", "rbl_bl_delay", "p_en_bar_unbuf", "vdd", "gnd"]) - # input: pre_p_en, output: p_en_bar - self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar", - mod=self.p_en_bar_driver) - self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"]) - + self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar", + mod=self.p_en_bar_driver) + self.connect_inst(["p_en_bar_unbuf", "p_en_bar", "vdd", "gnd"]) def place_pen_row(self,row): - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) - - if self.port_type == "rw": - offset = vector(x_off, y_off) - self.pre_p_en_inst.place(offset, mirror) + x_offset = self.control_x_offset - x_off += self.and2.width - - offset = vector(x_off,y_off) - self.p_en_bar_inst.place(offset, mirror) + x_offset = self.place_util(self.p_en_bar_nand_inst, x_offset, row) + x_offset = self.place_util(self.p_en_bar_driver_inst, x_offset, row) - self.row_end_inst.append(self.p_en_bar_inst) + self.row_end_inst.append(self.p_en_bar_driver_inst) def route_pen(self): - if self.port_type == "rw": - # Connect the NAND gate inputs to the bus - pre_p_en_in_map = zip(["A", "B"], ["gated_clk_buf", "we_bar"]) - self.connect_vertical_bus(pre_p_en_in_map, self.pre_p_en_inst, self.rail_offsets) + in_map = zip(["A", "B"], ["gated_clk_buf", "rbl_bl_delay"]) + self.connect_vertical_bus(in_map, self.p_en_bar_nand_inst, self.rail_offsets) - out_pos = self.pre_p_en_inst.get_pin("Z").center() - in_pos = self.p_en_bar_inst.get_pin("A").lc() - mid1 = vector(out_pos.x,in_pos.y) - self.add_wire(("metal1","via1","metal2"),[out_pos,mid1,in_pos]) - else: - in_map = zip(["A"], ["gated_clk_buf"]) - self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets) + out_pos = self.p_en_bar_nand_inst.get_pin("Z").rc() + in_pos = self.p_en_bar_driver_inst.get_pin("A").lc() + mid1 = vector(out_pos.x,in_pos.y) + self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos]) - self.connect_output(self.p_en_bar_inst, "Z", "p_en_bar") + self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar") def create_sen_row(self): """ Create the sense enable buffer. """ - # BUFFER FOR S_EN - # input: pre_s_en, output: s_en - self.s_en_inst=self.add_inst(name="buf_s_en", - mod=self.s_en_driver) - self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"]) + if self.port_type=="rw": + input_name = "we_bar" + else: + input_name = "cs_bar" + # GATE FOR S_EN + self.s_en_gate_inst = self.add_inst(name="buf_s_en_and", + mod=self.sen_and3) + self.connect_inst(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"]) + def place_sen_row(self,row): - """ - The sense enable buffer gets placed to the far right of the - row. - """ - x_off = self.control_x_offset - (y_off,mirror)=self.get_offset(row) + x_offset = self.control_x_offset - offset = vector(x_off, y_off) - self.s_en_inst.place(offset, mirror) + x_offset = self.place_util(self.s_en_gate_inst, x_offset, row) - self.row_end_inst.append(self.s_en_inst) + self.row_end_inst.append(self.s_en_gate_inst) def route_sen(self): - - out_pos = self.rbl_inst.get_pin("out").bc() - in_pos = self.s_en_inst.get_pin("A").lc() - mid1 = vector(out_pos.x,in_pos.y) - self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos]) - self.connect_output(self.s_en_inst, "Z", "s_en") + if self.port_type=="rw": + input_name = "we_bar" + else: + input_name = "cs_bar" + + sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name]) + self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets) + self.connect_output(self.s_en_gate_inst, "Z", "s_en") + + + def create_rbl_delay_row(self): + + self.rbl_bl_delay_inv_inst = self.add_inst(name="rbl_bl_delay_inv", + mod=self.inv) + self.connect_inst(["rbl_bl_delay", "rbl_bl_delay_bar", "vdd", "gnd"]) + + def place_rbl_delay_row(self,row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.rbl_bl_delay_inv_inst, x_offset, row) + + self.row_end_inst.append(self.rbl_bl_delay_inv_inst) + + def route_rbl_delay(self): + # Connect from delay line + # Connect to rail + + rbl_map = zip(["Z"], ["rbl_bl_delay_bar"]) + self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets, ("metal3", "via2", "metal2")) + # The pin is on M1, so we need another via as well + self.add_via_center(layers=("metal1","via1","metal2"), + offset=self.rbl_bl_delay_inv_inst.get_pin("Z").center()) + + + rbl_map = zip(["A"], ["rbl_bl_delay"]) + self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets) def create_wen_row(self): + # input: we (or cs) output: w_en if self.port_type == "rw": input_name = "we" else: # No we for write-only reports, so use 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_and) + self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"]) + def place_wen_row(self,row): - x_off = self.ctrl_dff_inst.width + self.internal_bus_width - (y_off,mirror)=self.get_offset(row) - - offset = vector(x_off, y_off) - self.w_en_inst.place(offset, mirror) + x_offset = self.control_x_offset + + x_offset = self.place_util(self.w_en_gate_inst, x_offset, row) - self.row_end_inst.append(self.w_en_inst) + self.row_end_inst.append(self.w_en_gate_inst) def route_wen(self): - if self.port_type == "rw": input_name = "we" else: # No we for write-only reports, so use cs input_name = "cs" - wen_map = zip(["A"], [input_name]) - self.connect_vertical_bus(wen_map, self.w_en_inst, self.rail_offsets) + wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay_bar", "gated_clk_bar"]) + 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): self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs", @@ -751,7 +741,7 @@ class control_logic(design.design): def route_dffs(self): if self.port_type == "rw": - dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"]) + dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"]) elif self.port_type == "r": dff_out_map = zip(["dout_bar_0", "dout_0"], ["cs", "cs_bar"]) else: @@ -815,9 +805,8 @@ class control_logic(design.design): self.add_power_pin("gnd", pin_loc) self.add_path("metal1", [row_loc, pin_loc]) - if (self.port_type == "rw") or (self.port_type == "r"): - self.copy_layout_pin(self.rbl_inst,"gnd") - self.copy_layout_pin(self.rbl_inst,"vdd") + self.copy_layout_pin(self.delay_inst,"gnd") + 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,"vdd") @@ -843,7 +832,7 @@ class control_logic(design.design): # height=pin.height(), # width=pin.width()) - pin=self.rbl_inst.get_pin("out") + pin=self.delay_inst.get_pin("out") self.add_label_pin(text="out", layer=pin.layer, offset=pin.ll(), @@ -904,7 +893,7 @@ class control_logic(design.design): last_stage_rise = stage_effort_list[-1].is_rise #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) last_stage_rise = stage_effort_list[-1].is_rise @@ -917,6 +906,7 @@ class control_logic(design.design): def get_wl_sen_delays(self): """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: debug.error("Model delays not calculated for SRAM.", 1) wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts) @@ -925,6 +915,7 @@ class control_logic(design.design): def analytical_delay(self, corner, slew, load): """Gets the analytical delay from clk input to wl_en output""" + stage_effort_list = [] #Calculate the load on clk_buf_bar ext_clk_buf_cout = self.sram.get_clk_bar_cin() @@ -933,7 +924,8 @@ class control_logic(design.design): last_stage_rise = False #First stage(s), clk -(pdriver)-> clk_buf. - clk_buf_cout = self.replica_bitline.get_en_cin() + #clk_buf_cout = self.replica_bitline.get_en_cin() + clk_buf_cout = 0 stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise @@ -952,8 +944,10 @@ class control_logic(design.design): return stage_effort_list 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 int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin() @@ -965,8 +959,24 @@ class control_logic(design.design): def get_gated_clk_bar_cin(self): """Get intermediates net gated_clk_bar's capacitance""" + total_cin = 0 total_cin += self.wl_en_driver.get_cin() if self.port_type == 'rw': total_cin +=self.and2.get_cin() - return total_cin \ No newline at end of file + return total_cin + + def graph_exclude_dffs(self): + """Exclude dffs from graph as they do not represent critical path""" + + 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) + + def place_util(self, inst, x_offset, row): + """ Utility to place a row and compute the next offset """ + + (y_offset,mirror)=self.get_offset(row) + offset = vector(x_offset, y_offset) + inst.place(offset, mirror) + return x_offset+inst.width diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 188efffa..bc932a26 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -52,14 +52,15 @@ class delay_chain(design.design): self.place_inverters() self.route_inverters() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() - + def add_pins(self): """ Add the pins of the delay chain""" - self.add_pin("in") - self.add_pin("out") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("in", "INPUT") + self.add_pin("out", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): self.inv = factory.create(module_type="pinv", route_output=False) diff --git a/compiler/modules/dff.py b/compiler/modules/dff.py index e1139e09..083d92b7 100644 --- a/compiler/modules/dff.py +++ b/compiler/modules/dff.py @@ -1,9 +1,9 @@ # 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. +# 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 globals import design @@ -18,6 +18,7 @@ class dff(design.design): """ pin_names = ["D", "Q", "clk", "vdd", "gnd"] + type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] (width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"]) @@ -27,6 +28,7 @@ class dff(design.design): self.width = dff.width self.height = dff.height self.pin_map = dff.pin_map + self.add_pin_types(self.type_list) def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" @@ -46,14 +48,13 @@ class dff(design.design): transition_prob = spice["flop_transition_prob"] return transition_prob*(c_load + c_para) - def analytical_delay(self, corner, slew, load = 0.0): - # dont know how to calculate this now, use constant in tech file - result = self.return_delay(spice["dff_delay"], spice["dff_slew"]) - return result - def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" #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 gates and dividing by the minimum width. return parameter["dff_clk_cin"] + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) + \ No newline at end of file diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 8b03fe19..89b29476 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -44,6 +44,7 @@ class dff_array(design.design): self.place_dff_array() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_modules(self): @@ -53,13 +54,13 @@ class dff_array(design.design): def add_pins(self): for row in range(self.rows): 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 col in range(self.columns): - self.add_pin(self.get_dout_name(row,col)) - self.add_pin("clk") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin(self.get_dout_name(row,col), "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_dff_array(self): self.dff_insts={} @@ -159,11 +160,6 @@ class dff_array(design.design): self.add_via_center(layers=("metal2","via2","metal3"), offset=vector(clk_pin.cx(),clk_ypos)) - - - def analytical_delay(self, corner, slew, load=0.0): - return self.dff.analytical_delay(corner, slew=slew, load=load) - def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 42e86bc0..f6fc1cf2 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -55,6 +55,7 @@ class dff_buf(design.design): self.place_instances() self.route_wires() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_modules(self): @@ -74,12 +75,12 @@ class dff_buf(design.design): def add_pins(self): - self.add_pin("D") - self.add_pin("Q") - self.add_pin("Qb") - self.add_pin("clk") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("D", "INPUT") + self.add_pin("Q", "OUTPUT") + self.add_pin("Qb", "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_instances(self): self.dff_inst=self.add_inst(name="dff_buf_dff", @@ -176,16 +177,7 @@ class dff_buf(design.design): self.add_path("metal1", [self.mid_qb_pos, qb_pos]) self.add_via_center(layers=("metal1","via1","metal2"), offset=qb_pos) - - - - def analytical_delay(self, corner, slew, load=0.0): - """ Calculate the analytical delay of DFF-> INV -> INV """ - dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load()) - inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=self.inv2.input_load()) - inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load) - return dff_delay + inv1_delay + inv2_delay - + def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" #This is a handmade cell so the value must be entered in the tech.py file or estimated. diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index dfd38760..2fafee76 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -49,19 +49,20 @@ class dff_buf_array(design.design): self.height = self.rows * self.dff.height self.place_dff_array() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_pins(self): for row in range(self.rows): 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 col in range(self.columns): - self.add_pin(self.get_dout_name(row,col)) - self.add_pin(self.get_dout_bar_name(row,col)) - self.add_pin("clk") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin(self.get_dout_name(row,col), "OUTPUT") + self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): self.dff = factory.create(module_type="dff_buf", @@ -192,11 +193,6 @@ class dff_buf_array(design.design): self.add_via_center(layers=("metal2","via2","metal3"), offset=vector(clk_pin.cx(),clk_ypos)) - - - def analytical_delay(self, corner, slew, load=0.0): - return self.dff.analytical_delay(slew=slew, load=load) - def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 2f831570..207a5ad0 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -53,6 +53,7 @@ class dff_inv(design.design): self.add_wires() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_pins(self): @@ -149,15 +150,7 @@ class dff_inv(design.design): offset=dout_pin.center()) self.add_via_center(layers=("metal1","via1","metal2"), offset=dout_pin.center()) - - - - def analytical_delay(self, corner, slew, load=0.0): - """ Calculate the analytical delay of DFF-> INV -> INV """ - dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load()) - inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=load) - return dff_delay + inv1_delay - + def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" return self.dff.get_clk_cin() diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 3ae50a08..760a2337 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -49,6 +49,7 @@ class dff_inv_array(design.design): self.place_dff_array() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_modules(self): @@ -58,14 +59,14 @@ class dff_inv_array(design.design): def add_pins(self): for row in range(self.rows): 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 col in range(self.columns): - self.add_pin(self.get_dout_name(row,col)) - self.add_pin(self.get_dout_bar_name(row,col)) - self.add_pin("clk") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin(self.get_dout_name(row,col), "OUTPUT") + self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_dff_array(self): self.dff_insts={} @@ -189,12 +190,6 @@ class dff_inv_array(design.design): self.add_via_center(layers=("metal2","via2","metal3"), offset=vector(clk_pin.cx(),clk_ypos)) - - - - def analytical_delay(self, corner, slew, load=0.0): - return self.dff.analytical_delay(corner, slew=slew, load=load) - def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py new file mode 100644 index 00000000..f1f433ce --- /dev/null +++ b/compiler/modules/dummy_array.py @@ -0,0 +1,157 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# 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 dummy_array(design.design): + """ + Generate a dummy row/column for the replica array. + """ + def __init__(self, cols, rows, mirror=0, name=""): + design.design.__init__(self, name) + debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + + self.column_size = cols + self.row_size = rows + self.mirror = mirror + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + + def create_netlist(self): + """ Create and connect the netlist """ + self.add_modules() + self.add_pins() + self.create_instances() + + def create_layout(self): + + # We increase it by a well enclosure so the precharges don't overlap our wells + self.height = self.row_size*self.dummy_cell.height + self.width = self.column_size*self.dummy_cell.width + + xoffset = 0.0 + for col in range(self.column_size): + yoffset = 0.0 + for row in range(self.row_size): + name = "dummy_r{0}_c{1}".format(row, col) + + if (row+self.mirror) % 2: + tempy = yoffset + self.dummy_cell.height + dir_key = "MX" + else: + tempy = yoffset + dir_key = "" + + self.cell_inst[row,col].place(offset=[xoffset, tempy], + mirror=dir_key) + yoffset += self.dummy_cell.height + xoffset += self.dummy_cell.width + + self.add_layout_pins() + + self.add_boundary() + + self.DRC_LVS() + + def add_pins(self): + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() + for col in range(self.column_size): + for cell_column in column_list: + self.add_pin(cell_column+"_{0}".format(col), "INOUT") + for row in range(self.row_size): + for cell_row in row_list: + self.add_pin(cell_row+"_{0}".format(row), "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + """ Add the modules used in this design """ + self.dummy_cell = factory.create(module_type="dummy_bitcell") + self.add_mod(self.dummy_cell) + + self.cell = factory.create(module_type="bitcell") + + 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 """ + + bitcell_pins = [] + + pin_names = self.cell.get_all_bitline_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(col)) + pin_names = self.cell.get_all_wl_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(row)) + bitcell_pins.append("vdd") + bitcell_pins.append("gnd") + + return bitcell_pins + + + def create_instances(self): + """ Create the module instances used in this design """ + self.cell_inst = {} + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row,col]=self.add_inst(name=name, + mod=self.dummy_cell) + self.connect_inst(self.get_bitcell_pins(col, row)) + + def add_layout_pins(self): + """ Add the layout pins """ + + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() + + for col in range(self.column_size): + for cell_column in column_list: + bl_pin = self.cell_inst[0,col].get_pin(cell_column) + self.add_layout_pin(text=cell_column+"_{0}".format(col), + layer="metal2", + offset=bl_pin.ll(), + width=bl_pin.width(), + height=self.height) + + for row in range(self.row_size): + for cell_row in row_list: + wl_pin = self.cell_inst[row,0].get_pin(cell_row) + self.add_layout_pin(text=cell_row+"_{0}".format(row), + layer="metal1", + offset=wl_pin.ll(), + width=self.width, + height=wl_pin.height()) + + # For every second row and column, add a via for gnd and vdd + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row,col] + for pin_name in ["vdd", "gnd"]: + for pin in inst.get_pins(pin_name): + self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) + + + def input_load(self): + wl_wire = self.gen_wl_wire() + return wl_wire.return_input_cap() + + def get_wordline_cin(self): + """Get the relative input capacitance from the wordline connections in all the bitcell""" + #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns + bitcell_wl_cin = self.cell.get_wl_cin() + total_cin = bitcell_wl_cin * self.column_size + return total_cin diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 1eac268d..0e70db55 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc import debug @@ -54,6 +54,7 @@ class hierarchical_decoder(design.design): self.route_predecode_rails() self.route_vdd_gnd() self.offset_all_coordinates() + self.add_boundary() self.DRC_LVS() def add_modules(self): @@ -230,12 +231,12 @@ class hierarchical_decoder(design.design): """ Add the module pins """ 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): - self.add_pin("decode_{0}".format(j)) - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("decode_{0}".format(j), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_pre_decoder(self): @@ -595,31 +596,10 @@ class hierarchical_decoder(design.design): self.add_via_center(layers=("metal2", "via2", "metal3"), offset=rail_pos) - - def analytical_delay(self, corner, slew, load = 0.0): - # A -> out - if self.determine_predecodes(self.num_inputs)[1]==0: - pre = self.pre2_4 - nand = self.nand2 - else: - pre = self.pre3_8 - nand = self.nand3 - a_t_out_delay = pre.analytical_delay(corner, slew=slew,load = nand.input_load()) - - # out -> z - out_t_z_delay = nand.analytical_delay(corner, slew= a_t_out_delay.slew, - load = self.inv.input_load()) - result = a_t_out_delay + out_t_z_delay - - # Z -> decode_out - z_t_decodeout_delay = self.inv.analytical_delay(corner, slew = out_t_z_delay.slew , load = load) - result = result + z_t_decodeout_delay - return result - - def input_load(self): if self.determine_predecodes(self.num_inputs)[1]==0: pre = self.pre2_4 else: pre = self.pre3_8 return pre.input_load() + diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 0449280a..bec0ce06 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -26,11 +26,11 @@ class hierarchical_predecode(design.design): def add_pins(self): 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): - self.add_pin("out_{0}".format(i)) - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("out_{0}".format(i), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): """ Add the INV and NAND gate modules """ diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index 938196d3..f05f54b0 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc import debug @@ -47,6 +47,7 @@ class hierarchical_predecode2x4(hierarchical_predecode): self.place_output_inverters() self.place_nand_array() self.route() + self.add_boundary() self.DRC_LVS() def get_nand_input_line_combination(self): @@ -55,21 +56,4 @@ class hierarchical_predecode2x4(hierarchical_predecode): ["A_0", "Abar_1"], ["Abar_0", "A_1"], ["A_0", "A_1"]] - return combination - - - def analytical_delay(self, corner, slew, load = 0.0 ): - # in -> inbar - a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load()) - - # inbar -> z - b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load()) - - # Z -> out - a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load) - - return a_t_b_delay + b_t_z_delay + a_t_out_delay - - - def input_load(self): - return self.nand.input_load() + return combination \ No newline at end of file diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index 77d9ce01..20b629bb 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc import debug @@ -52,6 +52,7 @@ class hierarchical_predecode3x8(hierarchical_predecode): self.place_output_inverters() self.place_nand_array() self.route() + self.add_boundary() self.DRC_LVS() def get_nand_input_line_combination(self): @@ -64,21 +65,4 @@ class hierarchical_predecode3x8(hierarchical_predecode): ["A_0", "Abar_1", "A_2"], ["Abar_0", "A_1", "A_2"], ["A_0", "A_1", "A_2"]] - return combination - - - def analytical_delay(self, corner, slew, load = 0.0 ): - # A -> Abar - a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load()) - - # Abar -> z - b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load()) - - # Z -> out - a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load) - - return a_t_b_delay + b_t_z_delay + a_t_out_delay - - - def input_load(self): - return self.nand.input_load() + return combination \ No newline at end of file diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index 667c6380..2f933a2d 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, parameter @@ -65,11 +65,11 @@ class multibank(design.design): def add_pins(self): """ Adding pins for Bank module""" for i in range(self.word_size): - self.add_pin("DOUT_{0}".format(i),"OUT") + self.add_pin("dout_{0}".format(i),"OUT") for i in range(self.word_size): - self.add_pin("BANK_DIN_{0}".format(i),"IN") + self.add_pin("bank_din_{0}".format(i),"IN") for i in range(self.addr_size): - self.add_pin("A_{0}".format(i),"INPUT") + self.add_pin("a_{0}".format(i),"INPUT") # For more than one bank, we have a bank select and name # the signals gated_*. @@ -187,9 +187,15 @@ class multibank(design.design): words_per_row=self.words_per_row) self.add_mod(self.sense_amp_array) - self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, - word_size=self.word_size) - self.add_mod(self.write_driver_array) + if self.write_size: + self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols, + word_size=self.word_size, + write_size=self.write_size) + self.add_mod(self.write_mask_driver_array) + else: + self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, + word_size=self.word_size) + self.add_mod(self.write_driver_array) self.row_decoder = self.mod_decoder(rows=self.num_rows) self.add_mod(self.row_decoder) @@ -296,7 +302,7 @@ class multibank(design.design): temp = [] for i in range(self.word_size): - temp.append("BANK_DIN_{0}".format(i)) + temp.append("bank_din_{0}".format(i)) for i in range(self.word_size): if (self.words_per_row == 1): temp.append("bl_{0}".format(i)) @@ -319,7 +325,7 @@ class multibank(design.design): for i in range(self.word_size): temp.append("sa_out_{0}".format(i)) for i in range(self.word_size): - temp.append("DOUT_{0}".format(i)) + temp.append("dout_{0}".format(i)) temp.extend([self.prefix+"tri_en", self.prefix+"tri_en_bar", "vdd", "gnd"]) self.connect_inst(temp) @@ -590,7 +596,7 @@ class multibank(design.design): """ Add pins for the sense amp output """ for i in range(self.word_size): data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(i)) - self.add_layout_pin_rect_center(text="DOUT_{}".format(i), + self.add_layout_pin_rect_center(text="dout_{}".format(i), layer=data_pin.layer, offset=data_pin.center(), height=data_pin.height(), @@ -600,7 +606,7 @@ class multibank(design.design): """ Metal 3 routing of tri_gate output data """ for i in range(self.word_size): data_pin = self.tri_gate_array_inst.get_pin("out_{}".format(i)) - self.add_layout_pin_rect_center(text="DOUT_{}".format(i), + self.add_layout_pin_rect_center(text="dout_{}".format(i), layer=data_pin.layer, offset=data_pin.center(), height=data_pin.height(), @@ -613,8 +619,8 @@ class multibank(design.design): # Create inputs for the row address lines for i in range(self.row_addr_size): addr_idx = i + self.col_addr_size - decoder_name = "A_{}".format(i) - addr_name = "A_{}".format(addr_idx) + decoder_name = "a_{}".format(i) + addr_name = "a_{}".format(addr_idx) self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name) @@ -623,7 +629,7 @@ class multibank(design.design): for i in range(self.word_size): data_name = "data_{}".format(i) - din_name = "BANK_DIN_{}".format(i) + din_name = "bank_din_{}".format(i) self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name) @@ -662,7 +668,7 @@ class multibank(design.design): decode_names = ["Zb", "Z"] # The Address LSB - self.copy_layout_pin(self.col_decoder_inst, "A", "A[0]") + self.copy_layout_pin(self.col_decoder_inst, "A", "a[0]") elif self.col_addr_size > 1: decode_names = [] @@ -671,7 +677,7 @@ class multibank(design.design): for i in range(self.col_addr_size): decoder_name = "in_{}".format(i) - addr_name = "A_{}".format(i) + addr_name = "a_{}".format(i) self.copy_layout_pin(self.col_decoder_inst, decoder_name, addr_name) @@ -822,21 +828,3 @@ class multibank(design.design): self.add_via(layers=("metal2","via2","metal3"), offset=in_pin + self.m2m3_via_offset, rotate=90) - - def analytical_delay(self, corner, slew, load): - """ return analytical delay of the bank""" - decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load()) - - word_driver_delay = self.wordline_driver.analytical_delay(corner, decoder_delay.slew, self.bitcell_array.input_load()) - - bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew) - - bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, bitcell_array_delay.slew, - self.bitcell_array.output_load()) - # output load of bitcell_array is set to be only small part of bl for sense amp. - - data_t_DATA_delay = self.tri_gate_array.analytical_delay(corner, bl_t_data_out_delay.slew, load) - - result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay - return result - diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py new file mode 100644 index 00000000..0a624c60 --- /dev/null +++ b/compiler/modules/port_address.py @@ -0,0 +1,162 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +import sys +from tech import drc, parameter +from math import log +import debug +import design +from sram_factory import factory +from vector import vector + +from globals import OPTS + +class port_address(design.design): + """ + Create the address port (row decoder and wordline driver).. + """ + + def __init__(self, cols, rows, name=""): + + self.num_cols = cols + self.num_rows = rows + self.addr_size = int(log(self.num_rows, 2)) + + if name == "": + name = "port_address_{0}_{1}".format(cols,rows) + design.design.__init__(self, name) + debug.info(2, "create data port of cols {0} rows {1}".format(cols,rows)) + + self.create_netlist() + if not OPTS.netlist_only: + debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.") + self.create_layout() + self.add_boundary() + + + def create_netlist(self): + self.add_pins() + self.add_modules() + self.create_row_decoder() + self.create_wordline_driver() + + def create_layout(self): + self.place_instances() + self.route_layout() + self.DRC_LVS() + + def add_pins(self): + """ Adding pins for port address module""" + + for bit in range(self.addr_size): + self.add_pin("addr_{0}".format(bit),"INPUT") + + self.add_pin("wl_en", "INPUT") + + for bit in range(self.num_rows): + self.add_pin("wl_{0}".format(bit),"OUTPUT") + + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") + + + def route_layout(self): + """ Create routing amoung the modules """ + self.route_pins() + self.route_internal() + self.route_supplies() + + def route_supplies(self): + """ Propagate all vdd/gnd pins up to this level for all modules """ + for inst in self.insts: + self.copy_power_pins(inst,"vdd") + self.copy_power_pins(inst,"gnd") + + def route_pins(self): + for row in range(self.addr_size): + decoder_name = "addr_{}".format(row) + self.copy_layout_pin(self.row_decoder_inst, decoder_name) + + for row in range(self.num_rows): + driver_name = "wl_{}".format(row) + self.copy_layout_pin(self.wordline_driver_inst, driver_name) + + self.copy_layout_pin(self.wordline_driver_inst, "en", "wl_en") + + def route_internal(self): + for row in range(self.num_rows): + # The pre/post is to access the pin from "outside" the cell to avoid DRCs + decoder_out_pos = self.row_decoder_inst.get_pin("decode_{}".format(row)).rc() + driver_in_pos = self.wordline_driver_inst.get_pin("in_{}".format(row)).lc() + mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) + mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) + self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) + + + + + def add_modules(self): + + self.row_decoder = factory.create(module_type="decoder", + rows=self.num_rows) + self.add_mod(self.row_decoder) + + self.wordline_driver = factory.create(module_type="wordline_driver", + rows=self.num_rows, + cols=self.num_cols) + self.add_mod(self.wordline_driver) + + + def create_row_decoder(self): + """ Create the hierarchical row decoder """ + + self.row_decoder_inst = self.add_inst(name="row_decoder", + mod=self.row_decoder) + + temp = [] + for bit in range(self.addr_size): + temp.append("addr_{0}".format(bit)) + for row in range(self.num_rows): + temp.append("dec_out_{0}".format(row)) + temp.extend(["vdd", "gnd"]) + self.connect_inst(temp) + + + + def create_wordline_driver(self): + """ Create the Wordline Driver """ + + self.wordline_driver_inst = self.add_inst(name="wordline_driver", + mod=self.wordline_driver) + + temp = [] + for row in range(self.num_rows): + temp.append("dec_out_{0}".format(row)) + for row in range(self.num_rows): + temp.append("wl_{0}".format(row)) + temp.append("wl_en") + temp.append("vdd") + temp.append("gnd") + self.connect_inst(temp) + + + + def place_instances(self): + """ + Compute the offsets and place the instances. + """ + + # A space for wells or jogging m2 + self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"), + 3*self.m2_pitch) + + row_decoder_offset = vector(0,0) + wordline_driver_offset = vector(self.row_decoder.width + self.m2_gap,0) + + self.wordline_driver_inst.place(wordline_driver_offset) + self.row_decoder_inst.place(row_decoder_offset) + + self.height = self.row_decoder.height + self.width = self.wordline_driver_inst.rx() diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py new file mode 100644 index 00000000..4bd49c4f --- /dev/null +++ b/compiler/modules/port_data.py @@ -0,0 +1,666 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +import sys +from tech import drc, parameter +import debug +import design +from sram_factory import factory +from vector import vector + +from globals import OPTS + +class port_data(design.design): + """ + 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=""): + + sram_config.set_local_config(self) + self.port = port + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + else: + self.num_wmasks = 0 + + if name == "": + name = "port_data_{0}".format(self.port) + design.design.__init__(self, name) + debug.info(2, "create data port of size {0} with {1} words per row".format(self.word_size,self.words_per_row)) + + self.create_netlist() + if not OPTS.netlist_only: + debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.") + self.create_layout() + self.add_boundary() + + + def create_netlist(self): + self.precompute_constants() + self.add_pins() + self.add_modules() + self.create_instances() + + def create_instances(self): + if self.precharge_array: + self.create_precharge_array() + else: + self.precharge_array_inst = None + + if self.sense_amp_array: + self.create_sense_amp_array() + else: + self.sense_amp_array_inst = None + + if self.write_driver_array: + self.create_write_driver_array() + if self.write_size: + self.create_write_mask_and_array() + else: + self.write_mask_and_array_inst = None + else: + self.write_driver_array_inst = None + self.write_mask_and_array_inst = None + + if self.column_mux_array: + self.create_column_mux_array() + else: + self.column_mux_array_inst = None + + + + def create_layout(self): + self.compute_instance_offsets() + self.place_instances() + self.route_layout() + self.DRC_LVS() + + def add_pins(self): + """ Adding pins for port address module""" + + self.add_pin("rbl_bl","INOUT") + self.add_pin("rbl_br","INOUT") + for bit in range(self.num_cols): + self.add_pin("{0}_{1}".format(self.bl_names[self.port], bit),"INOUT") + self.add_pin("{0}_{1}".format(self.br_names[self.port], bit),"INOUT") + if self.port in self.read_ports: + for bit in range(self.word_size): + self.add_pin("dout_{}".format(bit),"OUTPUT") + if self.port in self.write_ports: + for bit in range(self.word_size): + self.add_pin("din_{}".format(bit),"INPUT") + # Will be empty if no col addr lines + sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] + for pin_name in sel_names: + self.add_pin(pin_name,"INPUT") + if self.port in self.read_ports: + self.add_pin("s_en", "INPUT") + self.add_pin("p_en_bar", "INPUT") + if self.port in self.write_ports: + self.add_pin("w_en", "INPUT") + for bit in range(self.num_wmasks): + self.add_pin("bank_wmask_{}".format(bit),"INPUT") + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") + + + def route_layout(self): + """ Create routing among the modules """ + self.route_data_lines() + self.route_layout_pins() + self.route_supplies() + + def route_layout_pins(self): + """ Add the pins """ + self.route_bitline_pins() + self.route_control_pins() + + def route_data_lines(self): + """ Route the bitlines depending on the port type rw, w, or r. """ + + if self.port in self.readwrite_ports: + # (write_mask_and ->) write_driver -> sense_amp -> (column_mux ->) precharge -> bitcell_array + self.route_write_mask_and_array_in(self.port) + self.route_write_mask_and_array_to_write_driver(self.port) + self.route_write_driver_in(self.port) + self.route_sense_amp_out(self.port) + self.route_write_driver_to_sense_amp(self.port) + self.route_sense_amp_to_column_mux_or_precharge_array(self.port) + self.route_column_mux_to_precharge_array(self.port) + elif self.port in self.read_ports: + # sense_amp -> (column_mux) -> precharge -> bitcell_array + self.route_sense_amp_out(self.port) + self.route_sense_amp_to_column_mux_or_precharge_array(self.port) + self.route_column_mux_to_precharge_array(self.port) + else: + # (write_mask_and ->) write_driver -> (column_mux ->) precharge -> bitcell_array + self.route_write_mask_and_array_in(self.port) + self.route_write_mask_and_array_to_write_driver(self.port) + self.route_write_driver_in(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): + """ Propagate all vdd/gnd pins up to this level for all modules """ + + for inst in self.insts: + self.copy_power_pins(inst,"vdd") + self.copy_power_pins(inst,"gnd") + + def add_modules(self): + + # Extra column +1 is for RBL + # Precharge will be shifted left if needed + self.precharge_array = factory.create(module_type="precharge_array", + columns=self.num_cols + 1, + bitcell_bl=self.bl_names[self.port], + bitcell_br=self.br_names[self.port]) + self.add_mod(self.precharge_array) + + if self.port in self.read_ports: + self.sense_amp_array = factory.create(module_type="sense_amp_array", + word_size=self.word_size, + words_per_row=self.words_per_row) + self.add_mod(self.sense_amp_array) + else: + self.sense_amp_array = None + + + if self.col_addr_size > 0: + self.column_mux_array = factory.create(module_type="column_mux_array", + columns=self.num_cols, + word_size=self.word_size, + bitcell_bl=self.bl_names[self.port], + bitcell_br=self.br_names[self.port]) + self.add_mod(self.column_mux_array) + else: + self.column_mux_array = None + + + if self.port in self.write_ports: + self.write_driver_array = factory.create(module_type="write_driver_array", + columns=self.num_cols, + word_size=self.word_size, + write_size=self.write_size) + self.add_mod(self.write_driver_array) + if self.write_size: + self.write_mask_and_array = factory.create(module_type="write_mask_and_array", + columns=self.num_cols, + word_size=self.word_size, + write_size=self.write_size) + self.add_mod(self.write_mask_and_array) + else: + self.write_mask_and_array = None + + else: + self.write_driver_array = None + self.write_mask_and_array = None + + def precompute_constants(self): + """ Get some preliminary data ready """ + + # The central bus is the column address (one hot) and row address (binary) + if self.col_addr_size>0: + self.num_col_addr_lines = 2**self.col_addr_size + else: + self.num_col_addr_lines = 0 + + + # A space for wells or jogging m2 between modules + self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"), + 3*self.m2_pitch) + + + # create arrays of bitline and bitline_bar names for read, write, or all ports + self.bitcell = factory.create(module_type="bitcell") + self.bl_names = self.bitcell.get_all_bl_names() + self.br_names = self.bitcell.get_all_br_names() + self.wl_names = self.bitcell.get_all_wl_names() + + def create_precharge_array(self): + """ Creating Precharge """ + if not self.precharge_array: + self.precharge_array_inst = None + return + + self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), + mod=self.precharge_array) + + temp = [] + # Use left BLs for RBL + if self.port==0: + temp.append("rbl_bl") + temp.append("rbl_br") + for bit in range(self.num_cols): + temp.append(self.bl_names[self.port]+"_{0}".format(bit)) + temp.append(self.br_names[self.port]+"_{0}".format(bit)) + # Use right BLs for RBL + if self.port==1: + temp.append("rbl_bl") + temp.append("rbl_br") + temp.extend(["p_en_bar", "vdd"]) + self.connect_inst(temp) + + + def place_precharge_array(self, offset): + """ Placing Precharge """ + + self.precharge_array_inst.place(offset=offset, mirror="MX") + + + def create_column_mux_array(self): + """ Creating Column Mux when words_per_row > 1 . """ + + self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port), + mod=self.column_mux_array) + + temp = [] + for col in range(self.num_cols): + temp.append(self.bl_names[self.port]+"_{0}".format(col)) + temp.append(self.br_names[self.port]+"_{0}".format(col)) + for word in range(self.words_per_row): + temp.append("sel_{}".format(word)) + for bit in range(self.word_size): + temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) + temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) + temp.append("gnd") + self.connect_inst(temp) + + + def place_column_mux_array(self, offset): + """ Placing Column Mux when words_per_row > 1 . """ + if self.col_addr_size == 0: + return + + self.column_mux_array_inst.place(offset=offset, mirror="MX") + + + def create_sense_amp_array(self): + """ Creating Sense amp """ + self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port), + mod=self.sense_amp_array) + + temp = [] + for bit in range(self.word_size): + temp.append("dout_{}".format(bit)) + if self.words_per_row == 1: + temp.append(self.bl_names[self.port]+"_{0}".format(bit)) + temp.append(self.br_names[self.port]+"_{0}".format(bit)) + else: + temp.append(self.bl_names[self.port]+"_out_{0}".format(bit)) + temp.append(self.br_names[self.port]+"_out_{0}".format(bit)) + + temp.extend(["s_en", "vdd", "gnd"]) + self.connect_inst(temp) + + + def place_sense_amp_array(self, offset): + """ Placing Sense amp """ + self.sense_amp_array_inst.place(offset=offset, mirror="MX") + + + def create_write_driver_array(self): + """ Creating Write Driver """ + self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port), + mod=self.write_driver_array) + + temp = [] + for bit in range(self.word_size): + temp.append("din_{}".format(bit)) + + for bit in range(self.word_size): + if (self.words_per_row == 1): + temp.append(self.bl_names[self.port] + "_{0}".format(bit)) + temp.append(self.br_names[self.port] + "_{0}".format(bit)) + else: + temp.append(self.bl_names[self.port] + "_out_{0}".format(bit)) + temp.append(self.br_names[self.port] + "_out_{0}".format(bit)) + + if self.write_size: + for i in range(self.num_wmasks): + temp.append("wdriver_sel_{}".format(i)) + else: + temp.append("w_en") + temp.extend(["vdd", "gnd"]) + + self.connect_inst(temp) + + + def place_write_driver_array(self, offset): + """ Placing Write Driver """ + self.write_driver_array_inst.place(offset=offset, mirror="MX") + + + def create_write_mask_and_array(self): + """ Creating Write Mask AND Array """ + self.write_mask_and_array_inst = self.add_inst(name="write_mask_and_array{}".format(self.port), + mod=self.write_mask_and_array) + + temp = [] + for bit in range(self.num_wmasks): + temp.append("bank_wmask_{}".format(bit)) + temp.extend(["w_en"]) + for bit in range(self.num_wmasks): + temp.append("wdriver_sel_{}".format(bit)) + temp.extend(["vdd", "gnd"]) + self.connect_inst(temp) + + + def place_write_mask_and_array(self, offset): + """ Placing Write Mask AND array """ + self.write_mask_and_array_inst.place(offset=offset, mirror="MX") + + + def compute_instance_offsets(self): + """ + Compute the empty instance offsets for port0 and port1 (if needed) + """ + + vertical_port_order = [] + vertical_port_order.append(self.precharge_array_inst) + vertical_port_order.append(self.column_mux_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_mask_and_array_inst) + + # Add one column for the the RBL + if self.port==0: + x_offset = self.bitcell.width + else: + x_offset = 0 + + vertical_port_offsets = 5 * [None] + self.width = x_offset + self.height = 0 + for i, p in enumerate(vertical_port_order): + if p == None: + continue + self.height += (p.height + self.m2_gap) + self.width = max(self.width, p.width) + vertical_port_offsets[i] = vector(x_offset, self.height) + + # Reversed order + self.write_mask_and_offset = vertical_port_offsets[4] + self.write_driver_offset = vertical_port_offsets[3] + self.sense_amp_offset = vertical_port_offsets[2] + self.column_mux_offset = vertical_port_offsets[1] + 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) + + def place_instances(self): + """ Place the instances. """ + + # These are fixed in the order: write mask ANDs, write driver, sense amp, column mux, precharge, + # even if the item is not used in a given port (it will be None then) + if self.write_mask_and_offset: + self.place_write_mask_and_array(self.write_mask_and_offset) + if self.write_driver_offset: + self.place_write_driver_array(self.write_driver_offset) + if self.sense_amp_offset: + self.place_sense_amp_array(self.sense_amp_offset) + if self.precharge_offset: + self.place_precharge_array(self.precharge_offset) + if self.column_mux_offset: + self.place_column_mux_array(self.column_mux_offset) + + + def route_sense_amp_out(self, port): + """ Add pins for the sense amp output """ + + for bit in range(self.word_size): + data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit)) + self.add_layout_pin_rect_center(text="dout_{0}".format(bit), + layer=data_pin.layer, + offset=data_pin.center(), + height=data_pin.height(), + width=data_pin.width()) + + + def route_write_driver_in(self, port): + """ Connecting write driver """ + + for row in range(self.word_size): + data_name = "data_{}".format(row) + din_name = "din_{}".format(row) + self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name) + + + def route_write_mask_and_array_in(self, port): + """ Add pins for the write mask and array input """ + + for bit in range(self.num_wmasks): + wmask_in_name = "wmask_in_{}".format(bit) + bank_wmask_name = "bank_wmask_{}".format(bit) + self.copy_layout_pin(self.write_mask_and_array_inst, wmask_in_name, bank_wmask_name) + + + def route_write_mask_and_array_to_write_driver(self,port): + """ Routing of wdriver_sel_{} between write mask AND array and write driver array. Adds layout pin for write + mask AND array output and via for write driver enable """ + + inst1 = self.write_mask_and_array_inst + inst2 = self.write_driver_array_inst + + loc = 0 + for bit in range(self.num_wmasks): + # Bring write mask AND array output pin to port data level + self.copy_layout_pin(inst1, "wmask_out_{0}".format(bit), "wdriver_sel_{0}".format(bit)) + + wmask_out_pin = inst1.get_pin("wmask_out_{0}".format(bit)) + wdriver_en_pin = inst2.get_pin("en_{0}".format(bit)) + + # The metal2 wdriver_sel_{} wire must hit the en_{} pin after the closest bitline pin that's right of the + # the wdriver_sel_{} pin in the write driver AND array. + if bit == 0: + # When the write mask output pin is right of the bitline, the target is found + while (wmask_out_pin.lx() + self.m2_pitch > inst2.get_pin("data_{0}".format(loc)).rx()): + loc += 1 + length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch + debug.check(loc<=self.num_wmasks,"Couldn't route the write mask select.") + else: + # Stride by the write size rather than finding the next pin to the right + loc += self.write_size + length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch + + + beg_pos = wmask_out_pin.center() + middle_pos = vector(length,wmask_out_pin.cy()) + end_pos = vector(length, wdriver_en_pin.cy()) + + # Add via for the write driver array's enable input + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=end_pos) + + # Route between write mask AND array and write driver array + self.add_wire(("metal1","via1","metal2"), [beg_pos, middle_pos, end_pos]) + + + def route_column_mux_to_precharge_array(self, port): + """ Routing of BL and BR between col mux and precharge array """ + + # Only do this if we have a column mux! + if self.col_addr_size==0: + return + + inst1 = self.column_mux_array_inst + inst2 = self.precharge_array_inst + if 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): + """ Routing of BL and BR between sense_amp and column mux or precharge array """ + inst2 = self.sense_amp_array_inst + + if self.col_addr_size>0: + # Sense amp is connected to the col mux + inst1 = self.column_mux_array_inst + inst1_bl_name = "bl_out_{}" + inst1_br_name = "br_out_{}" + start_bit = 0 + else: + # Sense amp is directly connected to the precharge array + inst1 = self.precharge_array_inst + inst1_bl_name = "bl_{}" + inst1_br_name = "br_{}" + if self.port==0: + start_bit=1 + else: + start_bit=0 + + + 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 + + if self.col_addr_size>0: + # Write driver is connected to the col mux + inst1 = self.column_mux_array_inst + inst1_bl_name = "bl_out_{}" + inst1_br_name = "br_out_{}" + start_bit = 0 + else: + # Sense amp is directly connected to the precharge array + inst1 = self.precharge_array_inst + inst1_bl_name = "bl_{}" + inst1_br_name = "br_{}" + if self.port==0: + start_bit=1 + else: + start_bit=0 + + 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_sense_amp(self, port): + """ Routing of BL and BR between write driver and sense amp """ + + inst1 = self.write_driver_array_inst + inst2 = self.sense_amp_array_inst + + # These should be pitch matched in the cell library, + # but just in case, do a channel route. + self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) + + + def route_bitline_pins(self): + """ Add the bitline pins for the given port """ + + # Connect one bitline to the RBL and offset the indices for the other BLs + if 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.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): + if self.precharge_array_inst: + 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+bit_offset), "br_{}".format(bit)) + else: + debug.error("Didn't find precharge array.") + + + def route_control_pins(self): + """ Add the control pins: s_en, p_en_bar, w_en """ + if self.precharge_array_inst: + self.copy_layout_pin(self.precharge_array_inst, "en_bar", "p_en_bar") + if self.column_mux_array_inst: + sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] + for pin_name in sel_names: + self.copy_layout_pin(self.column_mux_array_inst, pin_name) + if self.sense_amp_array_inst: + self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en") + if self.write_driver_array_inst: + if self.write_mask_and_array_inst: + for bit in range(self.num_wmasks): + # Add write driver's en_{} pins + self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit)) + else: + self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en") + if self.write_mask_and_array_inst: + self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en") + + + + def channel_route_bitlines(self, inst1, inst2, num_bits, + inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, + inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): + """ + Route the bl and br of two modules using the channel router. + """ + + # determine top and bottom automatically. + # since they don't overlap, we can just check the bottom y coordinate. + if inst1.by() < inst2.by(): + (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) + (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) + else: + (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, 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 + # of tracks in teh channel router yet. If we did, we could route all the bits at once! + offset = bottom_inst.ul() + vector(0,self.m1_pitch) + for bit in range(num_bits): + bottom_names = [bottom_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_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))] + route_map = list(zip(bottom_names, top_names)) + self.create_horizontal_channel_route(route_map, offset) + + + def connect_bitlines(self, inst1, inst2, num_bits, + inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, + inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): + + """ + Connect the bl and br of two modules. + This assumes that they have sufficient space to create a jog + in the middle between the two modules (if needed). + """ + + # determine top and bottom automatically. + # since they don't overlap, we can just check the bottom y coordinate. + if inst1.by() < inst2.by(): + (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) + (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) + else: + (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, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) + + for col in range(num_bits): + 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+bottom_start_bit)).uc() + 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+top_start_bit)).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 graph_exclude_precharge(self): + """Precharge adds a loop between bitlines, can be excluded to reduce complexity""" + if self.precharge_array_inst: + self.graph_inst_exclude.add(self.precharge_array_inst) + diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index f88938c8..2d98ba14 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -35,10 +35,11 @@ class precharge_array(design.design): def add_pins(self): """Adds pins for spice file""" for i in range(self.columns): - self.add_pin("bl_{0}".format(i)) - self.add_pin("br_{0}".format(i)) - self.add_pin("en_bar") - self.add_pin("vdd") + # These are outputs from the precharge only + self.add_pin("bl_{0}".format(i), "OUTPUT") + self.add_pin("br_{0}".format(i), "OUTPUT") + self.add_pin("en_bar", "INPUT") + self.add_pin("vdd", "POWER") def create_netlist(self): self.add_modules() @@ -51,6 +52,7 @@ class precharge_array(design.design): self.place_insts() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_modules(self): @@ -114,3 +116,4 @@ class precharge_array(design.design): #Assume single port precharge_en_cin = self.pc_cell.get_en_cin() return precharge_en_cin*self.columns + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py new file mode 100644 index 00000000..b70a7bce --- /dev/null +++ b/compiler/modules/replica_bitcell_array.py @@ -0,0 +1,425 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# + +import debug +import design +from tech import drc, spice +from vector import vector +from globals import OPTS +from sram_factory import factory +import logical_effort +import bitcell_array +import replica_column +import dummy_array + +class replica_bitcell_array(design.design): + """ + Creates a bitcell arrow of cols x rows and then adds the replica + 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. + Requires a regular bitcell array, replica bitcell, and dummy + bitcell (Bl/BR disconnected). + """ + def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name): + design.design.__init__(self, name) + debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + + self.column_size = cols + 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.all_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() + if not OPTS.netlist_only: + self.create_layout() + + # We don't offset this because we need to align + # the replica bitcell in the control logic + #self.offset_all_coordinates() + + + def create_netlist(self): + """ Create and connect the netlist """ + self.add_modules() + self.add_pins() + self.create_instances() + + def add_modules(self): + """ Array and dummy/replica columns + + d or D = dummy cell (caps to distinguish grouping) + r or R = replica cell (caps to distinguish grouping) + b or B = bitcell + replica columns 1 + v v + bdDDDDDDDDDDDDDDdb <- Dummy row + bdDDDDDDDDDDDDDDrb <- Dummy row + br--------------rb + br| Array |rb + br| row x col |rb + br--------------rb + brDDDDDDDDDDDDDDdb <- Dummy row + bdDDDDDDDDDDDDDDdb <- Dummy row + + ^^^^^^^^^^^^^^^ + dummy rows cols x 1 + + ^ dummy columns ^ + 1 x (rows + 4) + """ + + # Bitcell for port names only + self.cell = factory.create(module_type="bitcell") + + # Bitcell array + self.bitcell_array = factory.create(module_type="bitcell_array", + cols=self.column_size, + rows=self.row_size) + self.add_mod(self.bitcell_array) + + # Replica bitlines + self.replica_columns = {} + for bit in range(self.left_rbl+self.right_rbl): + if bit1 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 + + + # 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): + """ Create the module instances used in this design """ + + supplies = ["vdd", "gnd"] + + # Used for names/dimensions only + self.cell = factory.create(module_type="bitcell") + + # Main array + self.bitcell_array_inst=self.add_inst(name="bitcell_array", + mod=self.bitcell_array) + self.connect_inst(self.bitcell_array_bl_names + self.bitcell_array_wl_names + supplies) + + # Replica columns + self.replica_col_inst = {} + for port in range(self.left_rbl+self.right_rbl): + self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port), + mod=self.replica_columns[port]) + self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies) + + + # Dummy rows under the bitcell array (connected with with the replica cell wl) + self.dummy_row_replica_inst = {} + for port in range(self.left_rbl+self.right_rbl): + self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), + mod=self.dummy_row) + self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies) + + + # Top/bottom dummy rows + self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot", + mod=self.dummy_row) + self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies) + self.dummy_row_top_inst=self.add_inst(name="dummy_row_top", + mod=self.dummy_row) + self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies) + + + # Left/right Dummy columns + self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", + mod=self.dummy_col) + 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", + mod=self.dummy_col) + self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) + + + + def create_layout(self): + + self.height = (self.row_size+self.extra_rows)*self.dummy_row.height + self.width = (self.column_size+self.extra_cols)*self.cell.width + + # This is a bitcell x bitcell offset to scale + offset = vector(self.cell.width, self.cell.height) + + self.bitcell_array_inst.place(offset=[0,0]) + + # To the left of the bitcell array + 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()) + + + # 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_boundary() + + self.DRC_LVS() + + + def add_layout_pins(self): + """ Add the layout pins """ + + # Main array wl and bl/br + pin_names = self.bitcell_array.get_pin_names() + for pin_name in pin_names: + if pin_name.startswith("wl"): + pin_list = self.bitcell_array_inst.get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(0,1), + width=self.width, + height=pin.height()) + elif pin_name.startswith("bl") or pin_name.startswith("br"): + pin_list = self.bitcell_array_inst.get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(1,0), + width=pin.width(), + height=self.height) + + + # Replica wordlines + for port in range(self.left_rbl+self.right_rbl): + inst = self.replica_col_inst[port] + for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]): + # +1 for dummy row + pin_bit = port+1 + # +row_size if above the array + if port>=self.left_rbl: + pin_bit += self.row_size + + pin_name += "_{}".format(pin_bit) + pin = inst.get_pin(pin_name) + 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 bitlines + for port in range(self.left_rbl+self.right_rbl): + inst = self.replica_col_inst[port] + for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(),self.replica_bl_names[port]): + pin = inst.get_pin(pin_name) + if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names: + name = bl_name + else: + name = "rbl_{0}_{1}".format(pin_name,port) + self.add_layout_pin(text=name, + layer=pin.layer, + offset=pin.ll().scale(1,0), + width=pin.width(), + height=self.height) + + + for pin_name in ["vdd","gnd"]: + for inst in self.insts: + pin_list = inst.get_pins(pin_name) + for pin in pin_list: + self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) + + + + + 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_power(self, corner, load): + """Power of Bitcell array and bitline in nW.""" + from tech import drc, parameter + + # Dynamic Power from Bitline + bl_wire = self.gen_bl_wire() + cell_load = 2 * bl_wire.return_input_cap() + bl_swing = OPTS.rbl_delay_percentage + freq = spice["default_event_rate"] + bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) + + #Calculate the bitcell power which currently only includes leakage + cell_power = self.cell.analytical_power(corner, load) + + #Leakage power grows with entire array and bitlines. + total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size, + cell_power.leakage * self.column_size * self.row_size) + return total_power + + def gen_bl_wire(self): + if OPTS.netlist_only: + height = 0 + else: + height = self.height + bl_pos = 0 + bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), height, drc("minwidth_metal1")) + bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell + return bl_wire + + def get_wordline_cin(self): + """Get the relative input capacitance from the wordline connections in all the bitcell""" + #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns + bitcell_wl_cin = self.cell.get_wl_cin() + total_cin = bitcell_wl_cin * self.column_size + 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) diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py deleted file mode 100644 index acd1f5d0..00000000 --- a/compiler/modules/replica_bitline.py +++ /dev/null @@ -1,618 +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 - - 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.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 - diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py new file mode 100644 index 00000000..c3f63b19 --- /dev/null +++ b/compiler/modules/replica_column.py @@ -0,0 +1,161 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# 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_column(design.design): + """ + 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, left_rbl, right_rbl, replica_bit): + design.design.__init__(self, name) + + 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() + 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.height = self.total_size*self.cell.height + self.width = self.cell.width + + self.place_instances() + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + + for bl_name in self.cell.get_all_bitline_names(): + # In the replica column, these are only outputs! + self.add_pin("{0}_{1}".format(bl_name,0), "OUTPUT") + + for row in range(self.total_size): + for wl_name in self.cell.get_all_wl_names(): + self.add_pin("{0}_{1}".format(wl_name,row), "INPUT") + + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + self.replica_cell = factory.create(module_type="replica_bitcell") + self.add_mod(self.replica_cell) + self.dummy_cell = factory.create(module_type="dummy_bitcell") + self.add_mod(self.dummy_cell) + # Used for pin names only + self.cell = factory.create(module_type="bitcell") + + def create_instances(self): + self.cell_inst = {} + for row in range(self.total_size): + name="rbc_{0}".format(row) + # Top/bottom cell are always dummy cells. + # Regular array cells are replica cells (>left_rbl and self.left_rbl and row net - decode_t_net = self.nand2.analytical_delay(corner, slew, self.inv.input_load()) - - # net -> wl - net_t_wl = self.inv.analytical_delay(corner, decode_t_net.slew, load) - - return decode_t_net + net_t_wl - - - def input_load(self): - """Gets the capacitance of the wordline driver in absolute units (fF)""" - return self.nand2.input_load() - def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): """Follows the clk_buf to a wordline signal adding each stages stage effort to a list""" stage_effort_list = [] diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index bbe676c0..85a58fd5 100644 --- a/compiler/modules/write_driver.py +++ b/compiler/modules/write_driver.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -18,7 +18,8 @@ class write_driver(design.design): the technology library. """ - pin_names = ["din", "bl", "br", "en", "gnd", "vdd"] + pin_names = ["din", "bl", "br", "en", "vdd", "gnd"] + type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] (width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"]) @@ -29,9 +30,13 @@ class write_driver(design.design): self.width = write_driver.width self.height = write_driver.height self.pin_map = write_driver.pin_map - + self.add_pin_types(self.type_list) def get_w_en_cin(self): """Get the relative capacitance of a single input""" # This is approximated from SCMOS. It has roughly 5 3x transistor gates. return 5*3 + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) \ No newline at end of file diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 27da84b0..100ee3a2 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -1,9 +1,9 @@ # 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. +# 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 math import log import design @@ -19,7 +19,7 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, name, columns, word_size): + def __init__(self, name, columns, word_size,write_size=None): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) @@ -27,8 +27,12 @@ class write_driver_array(design.design): self.columns = columns self.word_size = word_size + self.write_size = write_size self.words_per_row = int(columns / word_size) + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -45,22 +49,26 @@ class write_driver_array(design.design): self.width = self.columns * self.bitcell.width else: self.width = self.columns * self.driver.width - self.height = self.driver.height self.place_write_array() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_pins(self): 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): - self.add_pin("bl_{0}".format(i)) - self.add_pin("br_{0}".format(i)) - self.add_pin("en") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("bl_{0}".format(i), "OUTPUT") + self.add_pin("br_{0}".format(i), "OUTPUT") + if self.write_size: + for i in range(self.num_wmasks): + self.add_pin("en_{0}".format(i), "INPUT") + else: + self.add_pin("en", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): self.driver = factory.create(module_type="write_driver") @@ -72,27 +80,39 @@ class write_driver_array(design.design): def create_write_array(self): self.driver_insts = {} + w = 0 + windex=0 for i in range(0,self.columns,self.words_per_row): name = "write_driver{}".format(i) index = int(i/self.words_per_row) self.driver_insts[index]=self.add_inst(name=name, mod=self.driver) - self.connect_inst(["data_{0}".format(index), - "bl_{0}".format(index), - "br_{0}".format(index), - "en", "vdd", "gnd"]) + if self.write_size: + self.connect_inst(["data_{0}".format(index), + "bl_{0}".format(index), + "br_{0}".format(index), + "en_{0}".format(windex), "vdd", "gnd"]) + w+=1 + # when w equals write size, the next en pin can be connected since we are now at the next wmask bit + if w == self.write_size: + w = 0 + windex+=1 + else: + self.connect_inst(["data_{0}".format(index), + "bl_{0}".format(index), + "br_{0}".format(index), + "en", "vdd", "gnd"]) def place_write_array(self): if self.bitcell.width > self.driver.width: - driver_spacing = self.bitcell.width + self.driver_spacing = self.bitcell.width else: - driver_spacing = self.driver.width - + self.driver_spacing = self.driver.width for i in range(0,self.columns,self.words_per_row): - index = int(i/self.words_per_row) - base = vector(i * driver_spacing,0) + index = int(i/self.words_per_row) + base = vector(i * self.driver_spacing, 0) self.driver_insts[index].place(base) @@ -128,15 +148,28 @@ class write_driver_array(design.design): self.add_layout_pin_rect_center(text=n, layer="metal3", offset=pin_pos) + if self.write_size: + for bit in range(self.num_wmasks): + en_pin = self.driver_insts[bit*self.write_size].get_pin("en") + # Determine width of wmask modified en_pin with/without col mux + wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing) + if (self.words_per_row == 1): + en_gap = self.driver_spacing - en_pin.width() + else: + en_gap = self.driver_spacing + + self.add_layout_pin(text="en_{0}".format(bit), + layer=en_pin.layer, + offset=en_pin.ll(), + width=wmask_en_len-en_gap, + height=en_pin.height()) + else: + self.add_layout_pin(text="en", + layer="metal1", + offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), + width=self.width) - - self.add_layout_pin(text="en", - layer="metal1", - offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), - width=self.width, - height=drc('minwidth_metal1')) - def get_w_en_cin(self): diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py new file mode 100644 index 00000000..9d29cbea --- /dev/null +++ b/compiler/modules/write_mask_and_array.py @@ -0,0 +1,164 @@ +# 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 math import log +import design +from tech import drc +import debug +from sram_factory import factory +from vector import vector +from globals import OPTS + + +class write_mask_and_array(design.design): + """ + Array of AND gates to turn write mask signal on only when w_en is on. + The write mask AND array goes between the write driver array and the sense amp array. + """ + + def __init__(self, name, columns, word_size, write_size): + design.design.__init__(self, name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("columns: {0}".format(columns)) + self.add_comment("word_size {0}".format(word_size)) + self.add_comment("write_size {0}".format(write_size)) + + self.columns = columns + self.word_size = word_size + self.write_size = write_size + self.words_per_row = int(columns / word_size) + self.num_wmasks = int(word_size / write_size) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_and2_array() + + + def create_layout(self): + self.place_and2_array() + spacing = self.wmask_en_len - self.and2.width + self.width = (self.num_wmasks*self.and2.width) + ((self.num_wmasks-1)*spacing) + self.height = self.and2.height + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + for bit in range(self.num_wmasks): + self.add_pin("wmask_in_{}".format(bit),"INPUT") + self.add_pin("en", "INPUT") + for bit in range(self.num_wmasks): + self.add_pin("wmask_out_{}".format(bit),"OUTPUT") + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") + + def add_modules(self): + # Size the AND gate for the number of write drivers it drives, which is equal to the write size. + # Assume stage effort of 3 to compute the size + self.and2 = factory.create(module_type="pand2", + size=self.write_size/4.0) + self.add_mod(self.and2) + + + def create_and2_array(self): + self.and2_insts = {} + for bit in range(self.num_wmasks): + name = "and2_{}".format(bit) + self.and2_insts[bit] = self.add_inst(name=name, + mod=self.and2) + self.connect_inst(["wmask_in_{}".format(bit), + "en", + "wmask_out_{}".format(bit), + "vdd", "gnd"]) + + + def place_and2_array(self): + # Place the write mask AND array at the start of each write driver enable length. + # This ensures the write mask AND array will be directly under the corresponding write driver enable wire. + + # This is just used for measurements, so don't add the module + self.bitcell = factory.create(module_type="bitcell") + self.driver = factory.create(module_type="write_driver") + if self.bitcell.width > self.driver.width: + self.driver_spacing = self.bitcell.width + else: + self.driver_spacing = self.driver.width + + self.wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing) + debug.check(self.wmask_en_len >= self.and2.width, + "Write mask AND is wider than the corresponding write drivers {0} vs {1}.".format(self.and2.width,self.wmask_en_len)) + + for i in range(self.num_wmasks): + base = vector(i * self.wmask_en_len, 0) + self.and2_insts[i].place(base) + + + def add_layout_pins(self): + self.nand2 = factory.create(module_type="pnand2") + supply_pin=self.nand2.get_pin("vdd") + for i in range(self.num_wmasks): + wmask_in_pin = self.and2_insts[i].get_pin("A") + self.add_layout_pin(text="wmask_in_{0}".format(i), + layer=wmask_in_pin.layer, + offset=wmask_in_pin.ll(), + width=wmask_in_pin.width(), + height=wmask_in_pin.height()) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=wmask_in_pin.center()) + + en_pin = self.and2_insts[i].get_pin("B") + # Add the M1->M2 stack + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=en_pin.center()) + # Add the M2->M3 stack + self.add_via_center(layers=("metal2", "via2", "metal3"), + offset=en_pin.center()) + + # Route en pin between AND gates + if i < self.num_wmasks-1: + self.add_layout_pin(text="en", + layer="metal3", + offset=en_pin.bc(), + width = self.en_width(i), + height = drc('minwidth_metal3')) + + wmask_out_pin = self.and2_insts[i].get_pin("Z") + self.add_layout_pin(text="wmask_out_{0}".format(i), + layer=wmask_out_pin.layer, + offset=wmask_out_pin.ll(), + width=wmask_out_pin.width(), + height=wmask_out_pin.height()) + + self.add_power_pin("gnd", vector(supply_pin.width() + i * self.wmask_en_len, 0)) + self.add_power_pin("vdd", vector(supply_pin.width() + i * self.wmask_en_len, self.height)) + + if i < self.num_wmasks-1: + for n in ["gnd","vdd"]: + pin = self.and2_insts[i].get_pin(n) + next_pin = self.and2_insts[i+1].get_pin(n) + self.add_path("metal1",[pin.center(),next_pin.center()]) + + + def en_width(self, pin): + en_pin = self.and2_insts[pin].get_pin("B") + next_en_pin = self.and2_insts[pin+1].get_pin("B") + width = next_en_pin.center() - en_pin.center() + # Return x coordinates only + return width[0] + + + def get_cin(self): + """Get the relative capacitance of all the input connections in the bank""" + # The enable is connected to an and2 for every row. + return self.and2.get_cin() * len(self.and2_insts) + + diff --git a/compiler/openram.py b/compiler/openram.py index daef3b9c..9bd3b898 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -1,10 +1,10 @@ #!/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. +# 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. # """ SRAM Compiler @@ -50,7 +50,8 @@ from sram_config import sram_config # Configure the SRAM organization c = sram_config(word_size=OPTS.word_size, - num_words=OPTS.num_words) + num_words=OPTS.num_words, + write_size=OPTS.write_size) debug.print_raw("Words per row: {}".format(c.words_per_row)) #from parser import * diff --git a/compiler/options.py b/compiler/options.py index b3ac813a..ce974d63 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -1,13 +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. +# 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 optparse import getpass import os +#import sram_config class options(optparse.Values): """ @@ -28,6 +29,9 @@ class options(optparse.Values): num_rw_ports = 1 num_r_ports = 0 num_w_ports = 0 + + # Write mask size, default will be overwritten with word_size if not user specified + write_size = None # These will get initialized by the user or the tech file supply_voltages = "" @@ -42,10 +46,15 @@ class options(optparse.Values): ################### # Optimization options - ################### - # Uses the delay chain size in the tech.py file rather automatic sizing. + ################### + rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines + + # Allow manual adjustment of the delay chain over automatic use_tech_delay_chain_size = False - + delay_chain_stages = 9 + delay_chain_fanout_per_stage = 4 + + ################### # Debug options. @@ -75,7 +84,7 @@ class options(optparse.Values): # This determines whether LVS and DRC is checked for every submodule. inline_lvsdrc = False # Remove noncritical memory cells for characterization speed-up - trim_netlist = True + trim_netlist = False # Run with extracted parasitics use_pex = False @@ -122,6 +131,7 @@ class options(optparse.Values): delay_chain = "delay_chain" dff_array = "dff_array" dff = "dff" + dummy_bitcell = "dummy_bitcell" precharge_array = "precharge_array" ptx = "ptx" replica_bitcell = "replica_bitcell" @@ -133,4 +143,5 @@ class options(optparse.Values): wordline_driver = "wordline_driver" write_driver_array = "write_driver_array" write_driver = "write_driver" + write_mask_and_array = "write_mask_and_array" diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index add59565..d71b1e92 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc @@ -18,7 +18,7 @@ class pand2(pgate.pgate): This is a simple buffer used for driving loads. """ def __init__(self, name, size=1, height=None): - debug.info(1, "reating pnand2 {}".format(name)) + debug.info(1, "Creating pnand2 {}".format(name)) self.add_comment("size: {}".format(size)) self.size = size @@ -35,8 +35,8 @@ class pand2(pgate.pgate): # Shield the cap, but have at least a stage effort of 4 self.nand = factory.create(module_type="pnand2",height=self.height) self.add_mod(self.nand) - - self.inv = factory.create(module_type="pinv", size=self.size, height=self.height) + + self.inv = factory.create(module_type="pdriver", neg_polarity=True, fanout=3*self.size, height=self.height) self.add_mod(self.inv) def create_layout(self): @@ -47,11 +47,11 @@ class pand2(pgate.pgate): self.DRC_LVS() def add_pins(self): - self.add_pin("A") - self.add_pin("B") - self.add_pin("Z") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("A", "INPUT") + self.add_pin("B", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_insts(self): self.nand_inst=self.add_inst(name="pand2_nand", @@ -110,14 +110,6 @@ class pand2(pgate.pgate): width=pin.width(), height=pin.height()) - - - def analytical_delay(self, corner, slew, load=0.0): - """ Calculate the analytical delay of DFF-> INV -> INV """ - nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load()) - inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load) - return nand_delay + inv_delay - def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A or B -> Z path""" stage_effort_list = [] diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py new file mode 100644 index 00000000..22864e5a --- /dev/null +++ b/compiler/pgates/pand3.py @@ -0,0 +1,138 @@ +# 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 +from tech import drc +from math import log +from vector import vector +from globals import OPTS +import pgate +from sram_factory import factory + +class pand3(pgate.pgate): + """ + This is a simple buffer used for driving loads. + """ + def __init__(self, name, size=1, height=None): + debug.info(1, "Creating pand3 {}".format(name)) + self.add_comment("size: {}".format(size)) + + self.size = size + + # Creates the netlist and layout + pgate.pgate.__init__(self, name, height) + + def create_netlist(self): + self.add_pins() + self.create_modules() + self.create_insts() + + def create_modules(self): + # Shield the cap, but have at least a stage effort of 4 + self.nand = factory.create(module_type="pnand3",height=self.height) + self.add_mod(self.nand) + + self.inv = factory.create(module_type="pinv", size=self.size, height=self.height) + self.add_mod(self.inv) + + def create_layout(self): + self.width = self.nand.width + self.inv.width + self.place_insts() + self.add_wires() + self.add_layout_pins() + self.DRC_LVS() + + def add_pins(self): + self.add_pin("A", "INPUT") + self.add_pin("B", "INPUT") + self.add_pin("C", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_insts(self): + self.nand_inst=self.add_inst(name="pand3_nand", + mod=self.nand) + self.connect_inst(["A", "B", "C", "zb_int", "vdd", "gnd"]) + + self.inv_inst=self.add_inst(name="pand3_inv", + mod=self.inv) + self.connect_inst(["zb_int", "Z", "vdd", "gnd"]) + + def place_insts(self): + # Add NAND to the right + self.nand_inst.place(offset=vector(0,0)) + + # Add INV to the right + self.inv_inst.place(offset=vector(self.nand_inst.rx(),0)) + + def add_wires(self): + # nand Z to inv A + z1_pin = self.nand_inst.get_pin("Z") + a2_pin = self.inv_inst.get_pin("A") + mid1_point = vector(0.5*(z1_pin.cx()+a2_pin.cx()), z1_pin.cy()) + mid2_point = vector(mid1_point, a2_pin.cy()) + self.add_path("metal1", [z1_pin.center(), mid1_point, mid2_point, a2_pin.center()]) + + + def add_layout_pins(self): + # Continous vdd rail along with label. + vdd_pin=self.inv_inst.get_pin("vdd") + self.add_layout_pin(text="vdd", + layer="metal1", + offset=vdd_pin.ll().scale(0,1), + width=self.width, + height=vdd_pin.height()) + + # Continous gnd rail along with label. + gnd_pin=self.inv_inst.get_pin("gnd") + self.add_layout_pin(text="gnd", + layer="metal1", + offset=gnd_pin.ll().scale(0,1), + width=self.width, + height=vdd_pin.height()) + + pin = self.inv_inst.get_pin("Z") + self.add_layout_pin_rect_center(text="Z", + layer=pin.layer, + offset=pin.center(), + width=pin.width(), + height=pin.height()) + + for pin_name in ["A","B", "C"]: + pin = self.nand_inst.get_pin(pin_name) + self.add_layout_pin_rect_center(text=pin_name, + layer=pin.layer, + offset=pin.center(), + width=pin.width(), + height=pin.height()) + + + + def analytical_delay(self, corner, slew, load=0.0): + """ Calculate the analytical delay of DFF-> INV -> INV """ + nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load()) + inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load) + return nand_delay + inv_delay + + def get_stage_efforts(self, external_cout, inp_is_rise=False): + """Get the stage efforts of the A or B -> Z path""" + stage_effort_list = [] + stage1_cout = self.inv.get_cin() + stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise) + stage_effort_list.append(stage1) + last_stage_is_rise = stage1.is_rise + + stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) + stage_effort_list.append(stage2) + + return stage_effort_list + + def get_cin(self): + """Return the relative input capacitance of a single input""" + return self.nand.get_cin() + diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index f34a1827..fcfc6586 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc @@ -42,10 +42,10 @@ class pbuf(pgate.pgate): self.add_layout_pins() def add_pins(self): - self.add_pin("A") - self.add_pin("Z") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("A", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def create_modules(self): # Shield the cap, but have at least a stage effort of 4 @@ -113,14 +113,6 @@ class pbuf(pgate.pgate): width=a_pin.width(), height=a_pin.height()) - - - def analytical_delay(self, corner, slew, load=0.0): - """ Calculate the analytical delay of DFF-> INV -> INV """ - inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load()) - inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load) - return inv1_delay + inv2_delay - def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A -> Z path""" stage_effort_list = [] diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 39428515..ec55f0c7 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -1,9 +1,9 @@ # 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. +# 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 pgate @@ -45,7 +45,7 @@ class pdriver(pgate.pgate): self.num_stages = len(self.size_list) else: # Find the optimal number of stages for the given effort - self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort)))) + self.num_stages = max(1,int(round(self.fanout**(1/self.stage_effort)))) # Increase the number of stages if we need to fix polarity if self.neg_polarity and (self.num_stages%2==0): @@ -53,15 +53,15 @@ class pdriver(pgate.pgate): elif not self.neg_polarity and (self.num_stages%2): self.num_stages += 1 - self.size_list = [] - # compute sizes backwards from the fanout - fanout_prev = self.fanout - for x in range(self.num_stages): - fanout_prev = max(round(fanout_prev/self.stage_effort),1) - self.size_list.append(fanout_prev) + self.size_list = [] + # compute sizes backwards from the fanout + fanout_prev = self.fanout + for x in range(self.num_stages): + fanout_prev = max(round(fanout_prev/self.stage_effort),1) + self.size_list.append(fanout_prev) - # reverse the sizes to be from input to output - self.size_list.reverse() + # reverse the sizes to be from input to output + self.size_list.reverse() def create_netlist(self): @@ -81,10 +81,10 @@ class pdriver(pgate.pgate): def add_pins(self): - self.add_pin("A") - self.add_pin("Z") - self.add_pin("vdd") - self.add_pin("gnd") + self.add_pin("A", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_modules(self): self.inv_list = [] @@ -173,34 +173,13 @@ class pdriver(pgate.pgate): offset=a_pin.center(), width = a_pin.width(), height = a_pin.height()) - - def input_load(self): - return self.inv_list[0].input_load() - - def analytical_delay(self, corner, slew, load=0.0): - """Calculate the analytical delay of INV1 -> ... -> INVn""" - - cout_list = [] - for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): - cout_list.append(inv.input_load()) - cout_list.append(load) - - input_slew = slew - - delays = [] - for inv,cout in zip(self.inv_list,cout_list): - delays.append(inv.analytical_delay(corner, slew=input_slew, load=cout)) - input_slew = delays[-1].slew - - delay = delays[0] - for i in range(len(delays)-1): - delay += delays[i] - - 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): - """Get the stage efforts of the A -> Z path""" + """ Get the stage efforts of the A -> Z path """ cout_list = [] for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): cout_list.append(inv.get_cin()) @@ -217,5 +196,5 @@ class pdriver(pgate.pgate): return stage_effort_list 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() diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 57b73a21..f974f0c4 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import design @@ -31,17 +31,18 @@ class pgate(design.design): self.create_netlist() if not OPTS.netlist_only: self.create_layout() + self.add_boundary() self.DRC_LVS() - def create_netlist(): + def create_netlist(self): """ Pure virtual function """ debug.error("Must over-ride create_netlist.",-1) - def create_layout(): + def create_layout(self): """ Pure virtual function """ debug.error("Must over-ride create_layout.",-1) - + def connect_pin_to_rail(self,inst,pin,supply): """ Connects a ptx pin to a supply rail. """ source_pin = inst.get_pin(pin) @@ -245,4 +246,3 @@ class pgate(design.design): # offset=implant_offset, # width=implant_width, # height=implant_height) - diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 8f05c2b1..0844c762 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import pgate @@ -37,7 +37,6 @@ class pinv(pgate.pgate): self.beta = beta self.route_output = False - # Creates the netlist and layout pgate.pgate.__init__(self, name, height) def create_netlist(self): @@ -60,7 +59,9 @@ class pinv(pgate.pgate): def add_pins(self): """ Adds pins for spice netlist """ - self.add_pin_list(["A", "Z", "vdd", "gnd"]) + pin_list = ["A", "Z", "vdd", "gnd"] + dir_list = ["INPUT", "OUTPUT", "POWER", "GROUND"] + self.add_pin_list(pin_list, dir_list) def determine_tx_mults(self): @@ -254,15 +255,6 @@ class pinv(pgate.pgate): self.connect_pin_to_rail(self.pmos_inst,"S","vdd") - - def input_load(self): - return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"] - - def analytical_delay(self, corner, slew, load=0.0): - r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"]) - c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff - return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) - def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" c_eff = self.calculate_effective_capacitance(load) @@ -280,13 +272,23 @@ class pinv(pgate.pgate): transition_prob = spice["inv_transition_prob"] return transition_prob*(c_load + c_para) - def get_cin(self): - """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" + def input_load(self): + """Return the capacitance of the gate connection in generic capacitive + units relative to the minimum width of a transistor""" return self.nmos_size + self.pmos_size - + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 1 - return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) + return logical_effort.logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 75c64b08..a8d2c8b8 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -1,9 +1,9 @@ # 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. +# 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 pgate @@ -178,15 +178,7 @@ class pinvbuf(pgate.pgate): offset=a_pin.center()) self.add_via_center(layers=("metal1","via1","metal2"), offset=a_pin.center()) - - - - def analytical_delay(self, corner, slew, load=0.0): - """ Calculate the analytical delay of DFF-> INV -> INV """ - inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load()) - inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load) - return inv1_delay + inv2_delay - + def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the clk -> clk_buf path""" stage_effort_list = [] diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 865e1c60..21ca4184 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import pgate @@ -37,8 +37,7 @@ class pnand2(pgate.pgate): # Creates the netlist and layout pgate.pgate.__init__(self, name, height) - - + def create_netlist(self): self.add_pins() self.add_ptx() @@ -58,7 +57,9 @@ class pnand2(pgate.pgate): def add_pins(self): """ Adds pins for spice netlist """ - self.add_pin_list(["A", "B", "Z", "vdd", "gnd"]) + pin_list = ["A", "B", "Z", "vdd", "gnd"] + dir_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] + self.add_pin_list(pin_list, dir_list) def add_ptx(self): @@ -229,17 +230,6 @@ class pnand2(pgate.pgate): width=contact.m1m2.first_layer_height, height=contact.m1m2.first_layer_width) - - - - def input_load(self): - return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"] - - def analytical_delay(self, corner, slew, load=0.0): - r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"]) - c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff - return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) - def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" c_eff = self.calculate_effective_capacitance(load) @@ -257,13 +247,17 @@ class pnand2(pgate.pgate): transition_prob = spice["nand2_transition_prob"] return transition_prob*(c_load + c_para) - def get_cin(self): + def input_load(self): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size - + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) + return logical_effort.logical_effort(self.name, self.size, self.input_load(), cout, parasitic_delay, not inp_is_rise) + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 6f9d138d..89628267 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import pgate @@ -43,7 +43,9 @@ class pnand3(pgate.pgate): def add_pins(self): """ Adds pins for spice netlist """ - self.add_pin_list(["A", "B", "C", "Z", "vdd", "gnd"]) + pin_list = ["A", "B", "C", "Z", "vdd", "gnd"] + dir_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] + self.add_pin_list(pin_list, dir_list) def create_netlist(self): self.add_pins() @@ -241,16 +243,6 @@ class pnand3(pgate.pgate): width=contact.m1m2.first_layer_width, height=contact.m1m2.first_layer_height) - - - def input_load(self): - return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"] - - def analytical_delay(self, corner, slew, load=0.0): - r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"]) - c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff - return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) - def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" c_eff = self.calculate_effective_capacitance(load) @@ -268,7 +260,7 @@ class pnand3(pgate.pgate): transition_prob = spice["nand3_transition_prob"] return transition_prob*(c_load + c_para) - def get_cin(self): + def input_load(self): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size @@ -277,4 +269,8 @@ class pnand3(pgate.pgate): Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 3 - return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) + return logical_effort.logical_effort(self.name, self.size, self.input_load(), cout, parasitic_delay, not inp_is_rise) + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 3cc01f1a..472c75a8 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -1,16 +1,17 @@ # 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. +# 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 contact import pgate import debug from tech import drc, parameter, spice from vector import vector from globals import OPTS -import contact +import logical_effort from sram_factory import factory class pnor2(pgate.pgate): @@ -38,26 +39,30 @@ class pnor2(pgate.pgate): pgate.pgate.__init__(self, name, height) - def add_pins(self): - """ Adds pins for spice netlist """ - self.add_pin_list(["A", "B", "Z", "vdd", "gnd"]) - def create_netlist(self): self.add_pins() + self.add_ptx() self.create_ptx() - self.setup_layout_constants() def create_layout(self): """ Calls all functions related to the generation of the layout """ - self.add_supply_rails() - self.add_ptx() + + self.setup_layout_constants() + self.route_supply_rails() + self.place_ptx() self.connect_rails() self.add_well_contacts() self.extend_wells(self.well_pos) self.route_inputs() self.route_output() - def create_ptx(self): + def add_pins(self): + """ Adds pins for spice netlist """ + pin_list = ["A", "B", "Z", "vdd", "gnd"] + dir_list = ["INPUT", "INPUT", "OUTPUT", "INOUT", "INOUT"] + self.add_pin_list(pin_list, dir_list) + + def add_ptx(self): """ Create the PMOS and NMOS transistors. """ self.nmos = factory.create(module_type="ptx", width=self.nmos_width, @@ -102,7 +107,7 @@ class pnor2(pgate.pgate): self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space, drc("poly_extend_active"), self.poly_space) - def add_supply_rails(self): + def route_supply_rails(self): """ Add vdd/gnd rails to the top and bottom. """ self.add_layout_pin_rect_center(text="gnd", layer="metal1", @@ -114,7 +119,31 @@ class pnor2(pgate.pgate): offset=vector(0.5*self.width,self.height), width=self.width) - def add_ptx(self): + def create_ptx(self): + """ + Add PMOS and NMOS to the layout at the upper-most and lowest position + to provide maximum routing in channel + """ + + self.pmos1_inst=self.add_inst(name="pnor2_pmos1", + mod=self.pmos) + self.connect_inst(["vdd", "A", "net1", "vdd"]) + + self.pmos2_inst = self.add_inst(name="pnor2_pmos2", + mod=self.pmos) + self.connect_inst(["net1", "B", "Z", "vdd"]) + + + self.nmos1_inst=self.add_inst(name="pnor2_nmos1", + mod=self.nmos) + self.connect_inst(["Z", "A", "gnd", "gnd"]) + + self.nmos2_inst=self.add_inst(name="pnor2_nmos2", + mod=self.nmos) + self.connect_inst(["Z", "B", "gnd", "gnd"]) + + + def place_ptx(self): """ Add PMOS and NMOS to the layout at the upper-most and lowest position to provide maximum routing in channel @@ -122,29 +151,16 @@ class pnor2(pgate.pgate): pmos1_pos = vector(self.pmos.active_offset.x, self.height - self.pmos.active_height - self.top_bottom_space) - self.pmos1_inst=self.add_inst(name="pnor2_pmos1", - mod=self.pmos, - offset=pmos1_pos) - self.connect_inst(["vdd", "A", "net1", "vdd"]) + self.pmos1_inst.place(pmos1_pos) self.pmos2_pos = pmos1_pos + self.overlap_offset - self.pmos2_inst = self.add_inst(name="pnor2_pmos2", - mod=self.pmos, - offset=self.pmos2_pos) - self.connect_inst(["net1", "B", "Z", "vdd"]) - + self.pmos2_inst.place(self.pmos2_pos) nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space) - self.nmos1_inst=self.add_inst(name="pnor2_nmos1", - mod=self.nmos, - offset=nmos1_pos) - self.connect_inst(["Z", "A", "gnd", "gnd"]) - + self.nmos1_inst.place(nmos1_pos) + self.nmos2_pos = nmos1_pos + self.overlap_offset - self.nmos2_inst=self.add_inst(name="pnor2_nmos2", - mod=self.nmos, - offset=self.nmos2_pos) - self.connect_inst(["Z", "B", "gnd", "gnd"]) + self.nmos2_inst.place(self.nmos2_pos) # Output position will be in between the PMOS and NMOS self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height)) @@ -211,16 +227,6 @@ class pnor2(pgate.pgate): width=contact.m1m2.first_layer_height, height=contact.m1m2.first_layer_width) - - - def input_load(self): - return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"] - - def analytical_delay(self, corner, slew, load=0.0): - r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"]) - c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff - return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) - def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" c_eff = self.calculate_effective_capacitance(load) @@ -238,3 +244,6 @@ class pnor2(pgate.pgate): transition_prob = spice["nor2_transition_prob"] return transition_prob*(c_load + c_para) + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 61785d9d..b4423bed 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import design @@ -53,7 +53,7 @@ class precharge(design.design): self.connect_to_bitlines() 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): """ diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index 531ce160..0564bf86 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -1,9 +1,9 @@ # 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. +# 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 contact import pgate @@ -210,18 +210,11 @@ class ptristate_inv(pgate.pgate): self.connect_pin_to_rail(self.nmos1_inst,"S","gnd") self.connect_pin_to_rail(self.pmos1_inst,"S","vdd") - - def analytical_delay(self, corner, slew, load=0.0): - from tech import spice - r = spice["min_tx_r"] - c_para = spice["min_tx_drain_c"] - return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew) - def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" #Power in this module currently not defined. Returns 0 nW (leakage and dynamic). total_power = self.return_power() return total_power - def input_load(self): + def get_cin(self): return 9*spice["min_tx_gate_c"] diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index eade6682..79a29d07 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -1,9 +1,9 @@ # 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. +# 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 @@ -26,7 +26,7 @@ class ptx(design.design): # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't # have poly connected, for example. - name = "{0}_m{1}_w{2}".format(tx_type, mults, width) + name = "{0}_m{1}_w{2:.3f}".format(tx_type, mults, width) if connect_active: name += "_a" if connect_poly: @@ -68,7 +68,13 @@ class ptx(design.design): #self.DRC() def create_netlist(self): - self.add_pin_list(["D", "G", "S", "B"]) + pin_list = ["D", "G", "S", "B"] + if self.tx_type=="nmos": + body_dir = 'GROUND' + else: #Assumed that the check for either pmos or nmos is done elsewhere. + body_dir = 'POWER' + dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir] + self.add_pin_list(pin_list, dir_list) # self.spice.append("\n.SUBCKT {0} {1}".format(self.name, # " ".join(self.pins))) @@ -366,3 +372,8 @@ class ptx(design.design): def get_cin(self): """Returns the relative gate cin of the tx""" return self.tx_width/drc("minwidth_tx") + + def build_graph(self, graph, inst_name, port_nets): + """Adds edges based on inputs/outputs. Overrides base class function.""" + self.add_graph_edges(graph, port_nets) + \ No newline at end of file diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index caf01862..999d3ccd 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -1,9 +1,9 @@ # 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. +# 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 pgate import debug @@ -189,7 +189,7 @@ class single_level_column_mux(pgate.pgate): width=self.bitcell.width, height=self.height) - def analytical_delay(self, corner, slew, load): + def get_stage_effort(self, corner, slew, load): """Returns relative delay that the column mux. Difficult to convert to LE model.""" parasitic_delay = 1 cin = 2*self.tx_size #This is not CMOS, so using this may be incorrect. diff --git a/compiler/router/direction.py b/compiler/router/direction.py index 7508823d..a04fc18c 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -1,9 +1,9 @@ # 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. +# 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 from vector3d import vector3d diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 4533b8e7..af182125 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -1,9 +1,9 @@ # 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. +# 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 numpy as np import string @@ -50,7 +50,7 @@ class grid: self.add_map(vector3d(x,y,1)) def set_blocked(self,n,value=True): - if isinstance(n, (list,tuple,set,frozenset)): + if not isinstance(n, vector3d): for item in n: self.set_blocked(item,value) else: @@ -58,7 +58,7 @@ class grid: self.map[n].blocked=value def is_blocked(self,n): - if isinstance(n, (list,tuple,set,frozenset)): + if not isinstance(n, vector3d): for item in n: if self.is_blocked(item): return True @@ -82,7 +82,7 @@ class grid: self.map[k].blocked=False def set_source(self,n,value=True): - if isinstance(n, (list,tuple,set,frozenset)): + if not isinstance(n, vector3d): for item in n: self.set_source(item,value) else: @@ -91,7 +91,7 @@ class grid: self.source.add(n) def set_target(self,n,value=True): - if isinstance(n, (list,tuple,set,frozenset)): + if not isinstance(n, vector3d): for item in n: self.set_target(item,value) else: @@ -125,7 +125,7 @@ class grid: """ Add a point to the map if it doesn't exist. """ - if isinstance(n, (list,tuple,set,frozenset)): + if not isinstance(n, vector3d): for item in n: self.add_map(item) else: diff --git a/compiler/router/grid_cell.py b/compiler/router/grid_cell.py index d2816c28..2a09477a 100644 --- a/compiler/router/grid_cell.py +++ b/compiler/router/grid_cell.py @@ -1,9 +1,9 @@ # 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. +# 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 grid_cell: """ @@ -36,16 +36,21 @@ class grid_cell: def get_type(self): + type_string = "" + if self.blocked: - return "X" + type_string += "X" if self.source: - return "S" + type_string += "S" if self.target: - return "T" + type_string += "T" if self.path: - return "P" + type_string += "P" + if type_string != "": + return type_string + return None diff --git a/compiler/router/grid_path.py b/compiler/router/grid_path.py index f914e477..e4e0995d 100644 --- a/compiler/router/grid_path.py +++ b/compiler/router/grid_path.py @@ -1,9 +1,9 @@ # 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. +# 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 from vector3d import vector3d diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py index 6524a9d5..a9a4c08d 100644 --- a/compiler/router/grid_utils.py +++ b/compiler/router/grid_utils.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ Some utility functions for sets of grid cells. diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index bef538e3..99986e76 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -1,9 +1,9 @@ # 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. +# 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 direction import direction from pin_layout import pin_layout @@ -470,9 +470,9 @@ class pin_group: # Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. # This could only happen when there was no enclosure in any cardinal direction from a pin if not self.overlap_any_shape(self.pins, self.enclosures): - connector = self.find_smallest_connector(pin_list, self.enclosures) + connector = self.find_smallest_connector(self.pins, self.enclosures) if connector==None: - debug.error("Could not find a connector for {} with {}".format(pin_list, self.enclosures)) + debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures)) self.router.write_debug_gds("no_connector.gds") self.enclosures.append(connector) diff --git a/compiler/router/router.py b/compiler/router/router.py index f4e570a7..fd95def6 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -1,9 +1,9 @@ # 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. +# 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 import gdsMill @@ -668,7 +668,10 @@ class router(router_tech): track. """ # to scale coordinates to tracks - x = track[0]*self.track_width - 0.5*self.track_width + try: + x = track[0]*self.track_width - 0.5*self.track_width + except TypeError: + print(track[0],type(track[0]),self.track_width,type(self.track_width)) y = track[1]*self.track_width - 0.5*self.track_width # offset lowest corner object to to (-track halo,-track halo) ll = snap_to_grid(vector(x,y)) @@ -832,13 +835,22 @@ class router(router_tech): This will mark only the pin tracks from the indexed pin component as a target. It also unsets it as a blockage. """ - debug.check(index1: + self.cell.add_route(layers=self.layers, + coordinates=abs_path, + layer_widths=self.layer_widths) + else: + self.cell.add_path(layer=self.layers[0], + coordinates=abs_path, + width=self.layer_widths[0]) def add_single_enclosure(self, track): """ @@ -956,12 +973,19 @@ class router(router_tech): """ This assumes the blockages, source, and target are all set up. """ + + # Double check source and taget are not same node, if so, we are done! + for k,v in self.rg.map.items(): + if v.source and v.target: + debug.error("Grid cell is source and target! {}".format(k)) + return False + # returns the path in tracks (path,cost) = self.rg.route(detour_scale) if path: - debug.info(2,"Found path: cost={0} ".format(cost)) - debug.info(3,str(path)) - + debug.info(1,"Found path: cost={0} ".format(cost)) + debug.info(1,str(path)) + self.paths.append(path) self.add_route(path) @@ -1002,6 +1026,7 @@ class router(router_tech): Write out a GDS file with the routing grid and search information annotated on it. """ debug.info(0,"Writing annotated router gds file to {}".format(gds_name)) + self.del_router_info() self.add_router_info() self.cell.gds_write(gds_name) @@ -1053,6 +1078,15 @@ class router(router_tech): offset=shape[0], zoom=0.05) + def del_router_info(self): + """ + Erase all of the comments on the current level. + """ + debug.info(0,"Erasing router info") + layer_num = techlayer["text"] + self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num] + + def add_router_info(self): """ Write the routing grid and router cost, blockage, pins on diff --git a/compiler/router/router_tech.py b/compiler/router/router_tech.py index b82d4ac1..49df06fd 100644 --- a/compiler/router/router_tech.py +++ b/compiler/router/router_tech.py @@ -1,9 +1,9 @@ # 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. +# 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 tech import drc,layer from contact import contact @@ -24,19 +24,28 @@ class router_tech: """ self.layers = layers self.rail_track_width = rail_track_width - - (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers - # This is the minimum routed track spacing - via_connect = contact(self.layers, (1, 1)) - max_via_size = max(via_connect.width,via_connect.height) - self.horiz_layer_number = layer[self.horiz_layer_name] - self.vert_layer_number = layer[self.vert_layer_name] - - if self.rail_track_width>1: + if len(self.layers)==1: + self.horiz_layer_name = self.vert_layer_name = self.layers[0] + self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]] + (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) + + self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing + self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing + else: + (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers + via_connect = contact(self.layers, (1, 1)) + max_via_size = max(via_connect.width,via_connect.height) + + self.horiz_layer_number = layer[self.horiz_layer_name] + self.vert_layer_number = layer[self.vert_layer_name] + + (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) + (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) + # For supplies, we will make the wire wider than the vias self.vert_layer_minwidth = max(self.vert_layer_minwidth, max_via_size) self.horiz_layer_minwidth = max(self.horiz_layer_minwidth, max_via_size) @@ -44,13 +53,6 @@ class router_tech: self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing - else: - (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1) - (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0) - - self.horiz_track_width = max_via_size + self.horiz_layer_spacing - self.vert_track_width = max_via_size + self.vert_layer_spacing - # We'll keep horizontal and vertical tracks the same for simplicity. self.track_width = max(self.horiz_track_width,self.vert_track_width) debug.info(1,"Track width: {:.3f}".format(self.track_width)) @@ -80,24 +82,6 @@ class router_tech: else: debug.error("Invalid zindex {}".format(zindex),-1) - def get_layer_width_space(self, zindex, width=0, length=0): - """ - Return the width and spacing of a given layer - and wire of a given width and length. - """ - if zindex==1: - layer_name = self.vert_layer_name - elif zindex==0: - layer_name = self.horiz_layer_name - else: - debug.error("Invalid zindex for track", -1) - - min_width = drc("minwidth_{0}".format(layer_name), width, length) - min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length) - - return (min_width,min_spacing) - - def get_supply_layer_width_space(self, zindex): """ These are the width and spacing of a supply layer given a supply rail diff --git a/compiler/router/signal_grid.py b/compiler/router/signal_grid.py index 38d65053..cb012a5e 100644 --- a/compiler/router/signal_grid.py +++ b/compiler/router/signal_grid.py @@ -1,9 +1,9 @@ # 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. +# 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 itertools import tee import debug diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index da94c4f2..9390deaf 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -1,9 +1,9 @@ # 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. +# 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 gdsMill import tech diff --git a/compiler/router/supply_grid.py b/compiler/router/supply_grid.py index 839fc910..98c6f031 100644 --- a/compiler/router/supply_grid.py +++ b/compiler/router/supply_grid.py @@ -1,9 +1,9 @@ # 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. +# 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 from vector3d import vector3d diff --git a/compiler/router/supply_router.py b/compiler/router/supply_grid_router.py similarity index 98% rename from compiler/router/supply_router.py rename to compiler/router/supply_grid_router.py index 060451de..5ddabc98 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_grid_router.py @@ -1,9 +1,9 @@ # 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. +# 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 gdsMill import tech @@ -20,7 +20,7 @@ from datetime import datetime import grid import grid_utils -class supply_router(router): +class supply_grid_router(router): """ A router class to read an obstruction map from a gds and routes a grid to connect the supply on the two layers. @@ -391,7 +391,7 @@ class supply_router(router): # Add the single component of the pin as the source # which unmarks it as a blockage too - self.add_pin_component_source(pin_name,index) + self.add_pin_component_source(pin_name, index) # Add all of the rails as targets # Don't add the other pins, but we could? diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py new file mode 100644 index 00000000..7def03e0 --- /dev/null +++ b/compiler/router/supply_tree_router.py @@ -0,0 +1,193 @@ +# 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 gdsMill +import tech +import math +import debug +from globals import OPTS,print_time +from contact import contact +from pin_group import pin_group +from pin_layout import pin_layout +from vector3d import vector3d +from router import router +from direction import direction +from datetime import datetime +import grid +import grid_utils + +class supply_tree_router(router): + """ + A router class to read an obstruction map from a gds and + routes a grid to connect the supply on the two layers. + """ + + def __init__(self, layers, design, gds_filename=None): + """ + This will route on layers in design. It will get the blockages from + either the gds file name or the design itself (by saving to a gds file). + """ + # Power rail width in minimum wire widths + self.rail_track_width = 3 + + router.__init__(self, layers, design, gds_filename, self.rail_track_width) + + + def create_routing_grid(self): + """ + Create a sprase routing grid with A* expansion functions. + """ + size = self.ur - self.ll + debug.info(1,"Size: {0} x {1}".format(size.x,size.y)) + + import supply_grid + self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) + + def route(self, vdd_name="vdd", gnd_name="gnd"): + """ + Route the two nets in a single layer) + """ + debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) + self.vdd_name = vdd_name + self.gnd_name = gnd_name + + # Clear the pins if we have previously routed + if (hasattr(self,'rg')): + self.clear_pins() + else: + # Creat a routing grid over the entire area + # FIXME: This could be created only over the routing region, + # but this is simplest for now. + self.create_routing_grid() + + # Get the pin shapes + start_time = datetime.now() + self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) + print_time("Finding pins and blockages",datetime.now(), start_time, 3) + + # Add the supply rails in a mesh network and connect H/V with vias + start_time = datetime.now() + # Block everything + self.prepare_blockages(self.gnd_name) + self.prepare_blockages(self.vdd_name) + + # Route the supply pins to the supply rails + # Route vdd first since we want it to be shorter + start_time = datetime.now() + self.route_pins(vdd_name) + self.route_pins(gnd_name) + print_time("Maze routing supplies",datetime.now(), start_time, 3) + + #self.write_debug_gds("final.gds",False) + + # Did we route everything?? + if not self.check_all_routed(vdd_name): + return False + if not self.check_all_routed(gnd_name): + return False + + return True + + + def check_all_routed(self, pin_name): + """ + Check that all pin groups are routed. + """ + for pg in self.pin_groups[pin_name]: + if not pg.is_routed(): + return False + + def prepare_blockages(self, pin_name): + """ + Reset and add all of the blockages in the design. + Names is a list of pins to add as a blockage. + """ + debug.info(3,"Preparing blockages.") + + # Start fresh. Not the best for run-time, but simpler. + self.clear_blockages() + # This adds the initial blockges of the design + #print("BLOCKING:",self.blocked_grids) + self.set_blockages(self.blocked_grids,True) + + # Block all of the pin components (some will be unblocked if they're a source/target) + # Also block the previous routes + for name in self.pin_groups: + blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} + self.set_blockages(blockage_grids,True) + blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} + self.set_blockages(blockage_grids,True) + + # FIXME: These duplicate a bit of work + # These are the paths that have already been routed. + self.set_blockages(self.path_blockages) + + # Don't mark the other components as targets since we want to route + # directly to a rail, but unblock all the source components so we can + # route over them + blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} + self.set_blockages(blockage_grids,False) + + + + def route_pins(self, pin_name): + """ + This will route each of the remaining pin components to the other pins. + After it is done, the cells are added to the pin blockage list. + """ + + remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name]) + debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name, + remaining_components)) + + for index,pg in enumerate(self.pin_groups[pin_name]): + if pg.is_routed(): + continue + + debug.info(1,"Routing component {0} {1}".format(pin_name, index)) + + # Clear everything in the routing grid. + self.rg.reinit() + + # This is inefficient since it is non-incremental, but it was + # easier to debug. + self.prepare_blockages(pin_name) + + # Add the single component of the pin as the source + # which unmarks it as a blockage too + self.add_pin_component_source(pin_name,index) + + # Marks all pin components except index as target + self.add_pin_component_target_except(pin_name,index) + # Add the prevous paths as a target too + self.add_path_target(self.paths) + + print("SOURCE: ") + for k,v in self.rg.map.items(): + if v.source: + print(k) + + print("TARGET: ") + for k,v in self.rg.map.items(): + if v.target: + print(k) + + import pdb; pdb.set_trace() + if index==1: + self.write_debug_gds("debug{}.gds".format(pin_name),False) + + # Actually run the A* router + if not self.run_router(detour_scale=5): + self.write_debug_gds("debug_route.gds",True) + + #if index==3 and pin_name=="vdd": + # self.write_debug_gds("route.gds",False) + + + + + diff --git a/compiler/router/tests/01_no_blockages_test.py b/compiler/router/tests/01_no_blockages_test.py index 4529864a..4a673c24 100644 --- a/compiler/router/tests/01_no_blockages_test.py +++ b/compiler/router/tests/01_no_blockages_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/02_blockages_test.py b/compiler/router/tests/02_blockages_test.py index 3abe2e7e..e317b642 100644 --- a/compiler/router/tests/02_blockages_test.py +++ b/compiler/router/tests/02_blockages_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/03_same_layer_pins_test.py b/compiler/router/tests/03_same_layer_pins_test.py index af3d1ee8..10a3544a 100644 --- a/compiler/router/tests/03_same_layer_pins_test.py +++ b/compiler/router/tests/03_same_layer_pins_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/04_diff_layer_pins_test.py b/compiler/router/tests/04_diff_layer_pins_test.py index b70cba36..8966d2e4 100644 --- a/compiler/router/tests/04_diff_layer_pins_test.py +++ b/compiler/router/tests/04_diff_layer_pins_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/05_two_nets_test.py b/compiler/router/tests/05_two_nets_test.py index 10c157d7..ebf84745 100644 --- a/compiler/router/tests/05_two_nets_test.py +++ b/compiler/router/tests/05_two_nets_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/06_pin_location_test.py b/compiler/router/tests/06_pin_location_test.py index 7f75e541..a035cc59 100644 --- a/compiler/router/tests/06_pin_location_test.py +++ b/compiler/router/tests/06_pin_location_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/07_big_test.py b/compiler/router/tests/07_big_test.py index 6692cee0..5410dcbf 100644 --- a/compiler/router/tests/07_big_test.py +++ b/compiler/router/tests/07_big_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/08_expand_region_test.py b/compiler/router/tests/08_expand_region_test.py index 46af863d..ab4bce59 100644 --- a/compiler/router/tests/08_expand_region_test.py +++ b/compiler/router/tests/08_expand_region_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/10_supply_grid_test.py b/compiler/router/tests/10_supply_grid_test.py index 4910797a..73e41b86 100644 --- a/compiler/router/tests/10_supply_grid_test.py +++ b/compiler/router/tests/10_supply_grid_test.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 "Run a regresion test the library cells for DRC" diff --git a/compiler/router/tests/config_freepdk45.py b/compiler/router/tests/config_freepdk45.py index a6eb3bcc..bdc576bf 100644 --- a/compiler/router/tests/config_freepdk45.py +++ b/compiler/router/tests/config_freepdk45.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 diff --git a/compiler/router/tests/config_scn4m_subm.py b/compiler/router/tests/config_scn4m_subm.py index fdf7a2c3..bfaa01f8 100644 --- a/compiler/router/tests/config_scn4m_subm.py +++ b/compiler/router/tests/config_scn4m_subm.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 diff --git a/compiler/router/tests/gds_cell.py b/compiler/router/tests/gds_cell.py index 60c0f48e..b93b512a 100644 --- a/compiler/router/tests/gds_cell.py +++ b/compiler/router/tests/gds_cell.py @@ -1,9 +1,9 @@ # 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. +# 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 design import design class gds_cell(design): diff --git a/compiler/router/tests/regress.py b/compiler/router/tests/regress.py index 8f6c8938..db21bbd9 100644 --- a/compiler/router/tests/regress.py +++ b/compiler/router/tests/regress.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/env python3 diff --git a/compiler/router/tests/testutils.py b/compiler/router/tests/testutils.py index 447cace6..c90046f3 100644 --- a/compiler/router/tests/testutils.py +++ b/compiler/router/tests/testutils.py @@ -1,9 +1,9 @@ # 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. +# 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,warnings import sys,os,glob,copy diff --git a/compiler/router/vector3d.py b/compiler/router/vector3d.py index cc830faf..0d183021 100644 --- a/compiler/router/vector3d.py +++ b/compiler/router/vector3d.py @@ -1,9 +1,9 @@ # 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. +# 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 math diff --git a/compiler/sram.py b/compiler/sram/sram.py similarity index 95% rename from compiler/sram.py rename to compiler/sram/sram.py index d080acbc..5e7ac08a 100644 --- a/compiler/sram.py +++ b/compiler/sram/sram.py @@ -1,9 +1,9 @@ # 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. +# 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 import datetime @@ -34,7 +34,6 @@ class sram(): start_time = datetime.datetime.now() self.name = name - if self.num_banks == 1: from sram_1bank import sram_1bank as sram @@ -84,8 +83,6 @@ class sram(): self.gds_write(gdsname) print_time("GDS", datetime.datetime.now(), start_time) - - # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" @@ -133,4 +130,4 @@ class sram(): vname = OPTS.output_path + self.s.name + ".v" debug.print_raw("Verilog: Writing to {0}".format(vname)) self.verilog_write(vname) - print_time("Verilog", datetime.datetime.now(), start_time) + print_time("Verilog", datetime.datetime.now(), start_time) \ No newline at end of file diff --git a/compiler/sram_1bank.py b/compiler/sram/sram_1bank.py similarity index 51% rename from compiler/sram_1bank.py rename to compiler/sram/sram_1bank.py index 8edc317e..0ae294ec 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, spice @@ -43,9 +43,13 @@ class sram_1bank(sram_base): if self.col_addr_dff: self.col_addr_dff_insts = self.create_col_addr_dff() - - self.data_dff_insts = self.create_data_dff() - + + if self.write_size: + self.wmask_dff_insts = self.create_wmask_dff() + self.data_dff_insts = self.create_data_dff() + else: + self.data_dff_insts = self.create_data_dff() + def place_instances(self): """ This places the instances for a single bank SRAM with control @@ -63,6 +67,7 @@ class sram_1bank(sram_base): control_pos = [None]*len(self.all_ports) row_addr_pos = [None]*len(self.all_ports) col_addr_pos = [None]*len(self.all_ports) + wmask_pos = [None]*len(self.all_ports) data_pos = [None]*len(self.all_ports) # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk @@ -72,16 +77,52 @@ class sram_1bank(sram_base): # Port 0 port = 0 + if self.write_size: + if port in self.write_ports: + # Add the write mask flops below the write mask AND array. + wmask_pos[port] = vector(self.bank.bank_array_ll.x, + -0.5*max_gap_size - self.dff.height) + self.wmask_dff_insts[port].place(wmask_pos[port]) + + # Add the data flops below the write mask flops. + data_pos[port] = vector(self.bank.bank_array_ll.x, + -1.5*max_gap_size - 2*self.dff.height) + self.data_dff_insts[port].place(data_pos[port]) + else: + wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0) + data_pos[port] = vector(self.bank.bank_array_ll.x,0) + + else: + # Add the data flops below the bank to the right of the lower-left of bank array + # This relies on the lower-left 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_ll.x, + -max_gap_size - self.dff.height) + self.data_dff_insts[port].place(data_pos[port]) + + else: + data_pos[port] = vector(self.bank.bank_array_ll.x,0) + + # Add the col address flops below the bank to the left of the lower-left of bank array + if self.col_addr_dff: + col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap, + -max_gap_size - self.col_addr_dff_insts[port].height) + self.col_addr_dff_insts[port].place(col_addr_pos[port]) + else: + col_addr_pos[port] = vector(self.bank.bank_array_ll.x,0) + # This includes 2 M2 pitches for the row addr clock line. - # It is also placed to align with the column decoder (if it exists hence the bank gap) 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]) # 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 - # It is aove the control logic but below the top of the bitcell array - y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height) + # 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_inst.uy() - self.row_addr_dff_insts[port].height) row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(row_addr_pos[port]) @@ -91,51 +132,57 @@ class sram_1bank(sram_base): -max_gap_size - self.col_addr_dff_insts[port].height) self.col_addr_dff_insts[port].place(col_addr_pos[port]) - # Add the data flops below the bank to the right of the lower-left of bank array - # This relies on the lower-left 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_ll.x, - -max_gap_size - self.data_dff_insts[port].height) - self.data_dff_insts[port].place(data_pos[port]) - if len(self.all_ports)>1: # Port 1 port = 1 - # This includes 2 M2 pitches for the row addr clock line - # It is also placed to align with the column decoder (if it exists hence the bank gap) - control_pos[port] = vector(self.bank_inst.rx() + 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.control_logic_insts[port].place(control_pos[port], mirror="MY") - - # 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 - # It is above the control logic but below the top of the bitcell array - y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height) - row_addr_pos[port] = vector(x_offset, y_offset) - self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY") - + if port in self.write_ports: + if self.write_size: + # Add the write mask flops below the write mask AND array. + wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, + self.bank.height + 0.5*max_gap_size + self.dff.height) + self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") + + # Add the data flops below the write mask flops + data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, + self.bank.height + 1.5*max_gap_size + 2*self.dff.height) + self.data_dff_insts[port].place(data_pos[port], mirror="MX") + + else: + # 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. + 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 col address flops above the bank to the right of the upper-right of bank array if self.col_addr_dff: col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, - self.bank.height + max_gap_size + self.col_addr_dff_insts[port].height) + self.bank.height + max_gap_size + self.dff.height) self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX") - - # 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.data_dff_insts[port].height) - self.data_dff_insts[port].place(data_pos[port], mirror="MX") + else: + col_addr_pos[port] = self.bank_inst.ur() - + # 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, + 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") + + # 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 + # 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_inst.by() + self.row_addr_dff_insts[port].height) + row_addr_pos[port] = vector(x_offset, y_offset) + self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY") + + def add_layout_pins(self): """ Add the top-level pins for a single bank SRAM with control. @@ -147,18 +194,23 @@ class sram_1bank(sram_base): if port in self.read_ports: for bit in range(self.word_size): - self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "DOUT{0}[{1}]".format(port,bit)) + self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "dout{0}[{1}]".format(port,bit)) # Lower address bits for bit in range(self.col_addr_size): - self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit)) + self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"addr{0}[{1}]".format(port,bit)) # Upper address bits for bit in range(self.row_addr_size): - self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size)) + self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"addr{0}[{1}]".format(port,bit+self.col_addr_size)) if port in self.write_ports: for bit in range(self.word_size): - self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit)) + self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "din{0}[{1}]".format(port,bit)) + + if self.write_size: + for bit in range(self.num_wmasks): + self.copy_layout_pin(self.wmask_dff_insts[port], "din_{}".format(bit), "wmask{0}[{1}]".format(port,bit)) + def route_layout(self): """ Route a single bank SRAM """ @@ -175,6 +227,9 @@ class sram_1bank(sram_base): self.route_col_addr_dff() self.route_data_dff() + + if self.write_size: + self.route_wmask_dff() def route_clk(self): """ Route the clock network """ @@ -227,9 +282,19 @@ class sram_1bank(sram_base): self.add_path("metal2",[mid_pos, clk_steiner_pos], width=max(m2m3.width,m2m3.height)) self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos]) + if self.write_size: + wmask_dff_clk_pin = self.wmask_dff_insts[port].get_pin("clk") + wmask_dff_clk_pos = wmask_dff_clk_pin.center() + mid_pos = vector(clk_steiner_pos.x, wmask_dff_clk_pos.y) + # In some designs, the steiner via will be too close to the mid_pos via + # so make the wire as wide as the contacts + self.add_path("metal2", [mid_pos, clk_steiner_pos], width=max(m2m3.width, m2m3.height)) + self.add_wire(("metal3", "via2", "metal2"), [wmask_dff_clk_pos, mid_pos, clk_steiner_pos]) + 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 signal in self.control_logic_outputs[port]: # The clock gets routed separately and is not a part of the bank @@ -237,10 +302,14 @@ class sram_1bank(sram_base): continue src_pin = self.control_logic_insts[port].get_pin(signal) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) - self.connect_rail_from_left_m2m3(src_pin, dest_pin) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=src_pin.rc()) - + self.connect_vbus_m2m3(src_pin, dest_pin) + + for port in self.all_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): """ Connect the output of the row flops to the bank pins """ @@ -260,10 +329,15 @@ class sram_1bank(sram_base): def route_col_addr_dff(self): """ Connect the output of the row flops to the bank pins """ for port in self.all_ports: + if port%2: + offset = self.col_addr_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch) + else: + offset = self.col_addr_dff_insts[port].ul() + vector(0, 2*self.m1_pitch) + bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)] col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1", pitch=self.m1_pitch, - offset=self.col_addr_dff_insts[port].ul() + vector(0, self.m1_pitch), + offset=offset, names=bus_names, length=self.col_addr_dff_insts[port].width) @@ -283,19 +357,70 @@ class sram_1bank(sram_base): if port%2: offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch) else: - offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch) + offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch) dff_names = ["dout_{}".format(x) for x in range(self.word_size)] dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names] + if self.write_size: + for x in dff_names: + pin_offset = self.data_dff_insts[port].get_pin(x).center() + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=pin_offset, + directions = ("V", "V")) + self.add_via_center(layers=("metal2", "via2", "metal3"), + offset=pin_offset) + self.add_via_center(layers=("metal3", "via3", "metal4"), + offset=pin_offset) bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)] bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] - + if self.write_size: + for x in bank_names: + pin_offset = self.bank_inst.get_pin(x).bc() + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=pin_offset) + self.add_via_center(layers=("metal2", "via2", "metal3"), + offset=pin_offset) + self.add_via_center(layers=("metal3", "via3", "metal4"), + offset=pin_offset) + route_map = list(zip(bank_pins, dff_pins)) - self.create_horizontal_channel_route(route_map, offset) - - + if self.write_size: + self.create_horizontal_channel_route(netlist=route_map, + offset=offset, + layer_stack=("metal3", "via3", "metal4")) + else: + self.create_horizontal_channel_route(route_map, offset) + + def route_wmask_dff(self): + """ Connect the output of the wmask flops to the write mask AND array """ + # This is where the channel will start (y-dimension at least) + for port in self.write_ports: + if port % 2: + offset = self.wmask_dff_insts[port].ll() - vector(0, (self.word_size + 2) * self.m1_pitch) + else: + offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch) + + dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)] + dff_pins = [self.wmask_dff_insts[port].get_pin(x) for x in dff_names] + for x in dff_names: + offset_pin = self.wmask_dff_insts[port].get_pin(x).center() + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=offset_pin, + directions=("V", "V")) + + bank_names = ["bank_wmask{0}_{1}".format(port, x) for x in range(self.num_wmasks)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + for x in bank_names: + offset_pin = self.bank_inst.get_pin(x).center() + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=offset_pin) + + + route_map = list(zip(bank_pins, dff_pins)) + self.create_horizontal_channel_route(route_map,offset) + def add_lvs_correspondence_points(self): """ @@ -309,3 +434,49 @@ class sram_1bank(sram_base): self.add_label(text=n, layer=pin.layer, offset=pin.center()) + + def graph_exclude_data_dff(self): + """Removes data dff and wmask dff (if applicable) from search graph. """ + #Data dffs and wmask dffs are only for writing so are not useful for evaluating read delay. + for inst in self.data_dff_insts: + self.graph_inst_exclude.add(inst) + if self.write_size: + for inst in self.wmask_dff_insts: + self.graph_inst_exclude.add(inst) + + def graph_exclude_addr_dff(self): + """Removes data dff from search graph. """ + #Address is considered not part of the critical path, subjectively removed + for inst in self.row_addr_dff_insts: + self.graph_inst_exclude.add(inst) + + if self.col_addr_dff: + for inst in self.col_addr_dff_insts: + self.graph_inst_exclude.add(inst) + + def graph_exclude_ctrl_dffs(self): + """Exclude dffs for CSB, WEB, etc from graph""" + #Insts located in control logic, exclusion function called here + for inst in self.control_logic_insts: + inst.mod.graph_exclude_dffs() + + def get_sen_name(self, sram_name, port=0): + """Returns the s_en spice name.""" + #Naming scheme is hardcoded using this function, should be built into the + #graph in someway. + sen_name = "s_en{}".format(port) + control_conns = self.get_conns(self.control_logic_insts[port]) + #Sanity checks + if sen_name not in control_conns: + debug.error("Signal={} not contained in control logic connections={}"\ + .format(sen_name, control_conns)) + if sen_name in self.pins: + debug.error("Internal signal={} contained in port list. Name defined by the parent.") + return "X{}.{}".format(sram_name, sen_name) + + def get_cell_name(self, inst_name, row, col): + """Gets the spice name of the target bitcell.""" + #Sanity check in case it was forgotten + if inst_name.find('x') != 0: + inst_name = 'x'+inst_name + return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col) diff --git a/compiler/sram_2bank.py b/compiler/sram/sram_2bank.py similarity index 97% rename from compiler/sram_2bank.py rename to compiler/sram/sram_2bank.py index acf0e1a2..e1224795 100644 --- a/compiler/sram_2bank.py +++ b/compiler/sram/sram_2bank.py @@ -1,9 +1,9 @@ # 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. +# 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 from tech import drc, spice @@ -88,7 +88,7 @@ class sram_2bank(sram_base): mod=self.msb_address, offset=self.msb_address_position, rotate=270) - self.msb_bank_sel_addr = "ADDR[{}]".format(self.addr_size-1) + self.msb_bank_sel_addr = "addr[{}]".format(self.addr_size-1) self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"]) diff --git a/compiler/sram_base.py b/compiler/sram/sram_base.py similarity index 84% rename from compiler/sram_base.py rename to compiler/sram/sram_base.py index 192bc669..853772e8 100644 --- a/compiler/sram_base.py +++ b/compiler/sram/sram_base.py @@ -1,9 +1,9 @@ # 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. +# 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 import datetime @@ -34,19 +34,25 @@ class sram_base(design, verilog, lef): sram_config.set_local_config(self) self.bank_insts = [] - + + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + else: + self.num_wmasks = 0 + #For logical effort delay calculations. self.all_mods_except_control_done = False def add_pins(self): """ Add pins for entire SRAM. """ + for port in self.write_ports: for bit in range(self.word_size): - self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT") + self.add_pin("din{0}[{1}]".format(port,bit),"INPUT") for port in self.all_ports: 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") # These are used to create the physical pins self.control_logic_inputs = [] @@ -68,10 +74,13 @@ class sram_base(design, verilog, lef): self.add_pin("web{}".format(port),"INPUT") for port in self.all_ports: self.add_pin("clk{}".format(port),"INPUT") - + # add the optional write mask pins + for port in self.write_ports: + for bit in range(self.num_wmasks): + self.add_pin("wmask{0}[{1}]".format(port,bit),"INPUT") for port in self.read_ports: for bit in range(self.word_size): - self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT") + self.add_pin("dout{0}[{1}]".format(port,bit),"OUTPUT") self.add_pin("vdd","POWER") self.add_pin("gnd","GROUND") @@ -111,7 +120,7 @@ class sram_base(design, verilog, lef): self.add_lvs_correspondence_points() - self.offset_all_coordinates() + #self.offset_all_coordinates() highest_coord = self.find_highest_coords() self.width = highest_coord[0] @@ -129,22 +138,27 @@ class sram_base(design, verilog, lef): def route_supplies(self): """ Route the supply grid and connect the pins to them. """ - # Do not route the power supply - if not OPTS.route_supplies: - return - + # Copy the pins to the top level + # This will either be used to route or left unconnected. for inst in self.insts: self.copy_power_pins(inst,"vdd") self.copy_power_pins(inst,"gnd") + + import tech + if not OPTS.route_supplies: + # Do not route the power supply (leave as must-connect pins) + return + elif "metal4" in tech.layer: + # Route a M3/M4 grid + from supply_grid_router import supply_grid_router as router + rtr=router(("metal3","via3","metal4"), self) + elif "metal3" in tech.layer: + from supply_tree_router import supply_tree_router as router + rtr=router(("metal3",), self) - from supply_router import supply_router as router - layer_stack =("metal3","via3","metal4") - rtr=router(layer_stack, self) rtr.route() - - def compute_bus_sizes(self): """ Compute the independent bus widths shared between two and four bank SRAMs """ @@ -183,7 +197,7 @@ class sram_base(design, verilog, lef): if self.port_id[port] == "r": self.control_bus_names[port].extend([sen, pen]) elif self.port_id[port] == "w": - self.control_bus_names[port].extend([wen]) + self.control_bus_names[port].extend([wen, pen]) else: self.control_bus_names[port].extend([sen, wen, pen]) self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2", @@ -254,6 +268,7 @@ class sram_base(design, verilog, lef): def add_modules(self): self.bitcell = factory.create(module_type=OPTS.bitcell) + self.dff = factory.create(module_type="dff") # Create the address and control flops (but not the clk) from dff_array import dff_array @@ -268,6 +283,11 @@ class sram_base(design, verilog, lef): self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size) self.add_mod(self.data_dff) + + if self.write_size: + self.wmask_dff = dff_array(name="wmask_dff", rows=1, columns=self.num_wmasks) + self.add_mod(self.wmask_dff) + # Create the bank module (up to four are instantiated) from bank import bank @@ -281,9 +301,6 @@ class sram_base(design, verilog, lef): 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. self.all_mods_except_control_done = True @@ -295,21 +312,21 @@ class sram_base(design, verilog, lef): self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, - sram=self, + sram=self, port_type="rw") self.add_mod(self.control_logic_rw) if len(self.writeonly_ports)>0: self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, - sram=self, + sram=self, port_type="w") self.add_mod(self.control_logic_w) if len(self.readonly_ports)>0: self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, - sram=self, + sram=self, port_type="r") self.add_mod(self.control_logic_r) @@ -321,22 +338,26 @@ class sram_base(design, verilog, lef): temp = [] for port in self.read_ports: 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.all_ports: + temp.append("rbl_bl{0}".format(port)) for port in self.write_ports: 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)) for port in self.all_ports: for bit in range(self.bank_addr_size): - temp.append("A{0}[{1}]".format(port,bit)) + temp.append("a{0}[{1}]".format(port,bit)) if(self.num_banks > 1): for port in self.all_ports: temp.append("bank_sel{0}[{1}]".format(port,bank_num)) for port in self.read_ports: 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)) for port in self.write_ports: temp.append("w_en{0}".format(port)) + for bit in range(self.num_wmasks): + temp.append("bank_wmask{}[{}]".format(port, bit)) for port in self.all_ports: temp.append("wl_en{0}".format(port)) temp.extend(["vdd", "gnd"]) @@ -387,8 +408,8 @@ class sram_base(design, verilog, lef): inputs = [] outputs = [] for bit in range(self.row_addr_size): - inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size)) - outputs.append("A{}[{}]".format(port,bit+self.col_addr_size)) + inputs.append("addr{}[{}]".format(port,bit+self.col_addr_size)) + outputs.append("a{}[{}]".format(port,bit+self.col_addr_size)) self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"]) @@ -406,8 +427,8 @@ class sram_base(design, verilog, lef): inputs = [] outputs = [] for bit in range(self.col_addr_size): - inputs.append("ADDR{}[{}]".format(port,bit)) - outputs.append("A{}[{}]".format(port,bit)) + inputs.append("addr{}[{}]".format(port,bit)) + outputs.append("a{}[{}]".format(port,bit)) self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"]) @@ -429,13 +450,35 @@ class sram_base(design, verilog, lef): inputs = [] outputs = [] for bit in range(self.word_size): - inputs.append("DIN{}[{}]".format(port,bit)) - outputs.append("BANK_DIN{}[{}]".format(port,bit)) + inputs.append("din{}[{}]".format(port,bit)) + outputs.append("bank_din{}[{}]".format(port,bit)) self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"]) return insts + def create_wmask_dff(self): + """ Add and place all wmask flops """ + insts = [] + for port in self.all_ports: + if port in self.write_ports: + insts.append(self.add_inst(name="wmask_dff{}".format(port), + mod=self.wmask_dff)) + else: + insts.append(None) + continue + + # inputs, outputs/output/bar + inputs = [] + outputs = [] + for bit in range(self.num_wmasks): + inputs.append("wmask{}[{}]".format(port, bit)) + outputs.append("bank_wmask{}[{}]".format(port, bit)) + + self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"]) + + return insts + def create_control_logic(self): """ Add control logic instances """ @@ -456,35 +499,45 @@ class sram_base(design, verilog, lef): if port in self.readwrite_ports: temp.append("web{}".format(port)) temp.append("clk{}".format(port)) + temp.append("rbl_bl{}".format(port)) - # Ouputs + # Outputs if port in self.read_ports: temp.append("s_en{}".format(port)) if port in self.write_ports: 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"]) self.connect_inst(temp) return insts - def connect_rail_from_left_m2m3(self, src_pin, dest_pin): - """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pos = src_pin.rc() - out_pos = dest_pin.center() + def connect_vbus_m2m3(self, src_pin, dest_pin): + """ Helper routine to connect an instance to a vertical bus. + 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() DOUT - LH and HL are the same in analytical model. """ - delays = {} - for port in self.all_ports: - if port in self.readonly_ports: - control_logic = self.control_logic_r - elif port in self.readwrite_ports: - control_logic = self.control_logic_rw - else: - continue - clk_to_wlen_delays = control_logic.analytical_delay(corner, slew, load) - wlen_to_dout_delays = self.bank.analytical_delay(corner,slew,load,port) #port should probably be specified... - all_delays = clk_to_wlen_delays+wlen_to_dout_delays - total_delay = logical_effort.calculate_absolute_delay(all_delays) - total_delay = self.apply_corners_analytically(total_delay, corner) - last_slew = .1*all_delays[-1].get_absolute_delay() #slew approximated as 10% of delay - last_slew = self.apply_corners_analytically(last_slew, corner) - delays[port] = self.return_delay(delay=total_delay, slew=last_slew) - - return delays - + def get_wordline_stage_efforts(self, inp_is_rise=True): """Get the all the stage efforts for each stage in the path from clk_buf to a wordline""" stage_effort_list = [] @@ -579,4 +609,4 @@ class sram_base(design, verilog, lef): total_cin += self.data_dff.get_clk_cin() if self.col_addr_size > 0: total_cin += self.col_addr_dff.get_clk_cin() - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/sram_config.py b/compiler/sram/sram_config.py similarity index 83% rename from compiler/sram_config.py rename to compiler/sram/sram_config.py index 671bcf62..376bf42b 100644 --- a/compiler/sram_config.py +++ b/compiler/sram/sram_config.py @@ -1,9 +1,9 @@ # 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. +# 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 from math import log,sqrt,ceil @@ -14,16 +14,18 @@ from sram_factory import factory class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ - def __init__(self, word_size, num_words, num_banks=1, words_per_row=None): + def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None): self.word_size = word_size self.num_words = num_words + self.write_size = write_size self.num_banks = num_banks # This will get over-written when we determine the organization self.words_per_row = words_per_row + self.compute_sizes() - + def set_local_config(self, module): """ Copy all of the member variables to the given module for convenience """ @@ -37,7 +39,7 @@ class sram_config: def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" - self.bitcell = factory.create(module_type="bitcell") + bitcell = factory.create(module_type="bitcell") debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") @@ -48,18 +50,17 @@ class sram_config: # If this was hard coded, don't dynamically compute it! if not self.words_per_row: # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) - self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank + self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank self.bank_side_length = sqrt(self.bank_area) # Estimate the words per row given the height of the bitcell and the square side length - self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width) + self.tentative_num_cols = int(self.bank_side_length/bitcell.width) self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) # Estimate the number of rows given the tentative words per row 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) - debug.info(1,"Words per row: {}".format(self.words_per_row)) self.recompute_sizes() def recompute_sizes(self): @@ -69,6 +70,8 @@ class sram_config: SRAM for testing. """ + debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row)) + # If the banks changed self.num_words_per_bank = self.num_words/self.num_banks self.num_bits_per_bank = self.word_size*self.num_words_per_bank @@ -76,12 +79,16 @@ class sram_config: # Fix the number of columns and rows self.num_cols = int(self.words_per_row*self.word_size) 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 self.row_addr_size = int(log(self.num_rows, 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.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): diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 325261a0..0083841d 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -1,14 +1,12 @@ # 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. +# 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 from globals import OPTS -from importlib import reload - class sram_factory: """ @@ -46,16 +44,15 @@ class sram_factory: if hasattr(OPTS, module_type): # Retrieve the name from OPTS if it exists, # otherwise just use the name - module_name = getattr(OPTS, module_type) - else: - module_name = module_type - + module_type = getattr(OPTS, module_type) + # Either retrieve the already loaded module or load it try: mod = self.modules[module_type] except KeyError: - c = reload(__import__(module_name)) - mod = getattr(c, module_name) + import importlib + c = importlib.reload(__import__(module_type)) + mod = getattr(c, module_type) self.modules[module_type] = mod self.module_indices[module_type] = 0 self.objects[module_type] = [] @@ -75,15 +72,29 @@ class sram_factory: # This is especially for library cells so that the spice and gds files can be found. if len(kwargs)>0: # Create a unique name and increment the index - module_name = "{0}_{1}".format(module_name, self.module_indices[module_type]) + module_name = "{0}_{1}".format(module_type, self.module_indices[module_type]) self.module_indices[module_type] += 1 + else: + module_name = module_type #debug.info(0, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs))) obj = mod(name=module_name,**kwargs) self.objects[module_type].append((kwargs,obj)) return obj - + def get_mods(self, module_type): + """Returns list of all objects of module name's type.""" + if hasattr(OPTS, module_type): + # Retrieve the name from OPTS if it exists, + # otherwise just use the input + module_type = getattr(OPTS, module_type) + try: + mod_tuples = self.objects[module_type] + mods = [mod for kwargs,mod in mod_tuples] + except KeyError: + mods = [] + return mods + # Make a factory factory = sram_factory() diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index 373b1516..571f4be7 100755 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -1,16 +1,16 @@ #!/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. +# 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 header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals import debug @@ -51,7 +51,7 @@ def setup_files(path): files = [] for (dir, _, current_files) in os.walk(path): for f in current_files: - files.append(os.path.join(dir, f)) + files.append(os.getenv("OPENRAM_HOME")) nametest = re.compile("\.py$", re.IGNORECASE) select_files = list(filter(nametest.search, files)) return select_files @@ -122,4 +122,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py index c2052e4e..f8da685b 100755 --- a/compiler/tests/01_library_drc_test.py +++ b/compiler/tests/01_library_drc_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test the library cells for DRC" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -#sys.path.append(os.path.join(sys.path[0],"..")) +#sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -51,5 +49,5 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index 6775f41f..ad150a2b 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test the library cells for LVS" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -74,4 +72,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index 2aa79df6..3d7254c3 100755 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test for DRC on basic contacts of different array sizes" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -69,4 +67,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index 4748e18d..21001718 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic path" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -96,4 +94,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index cc6d6ed6..f436d7d0 100755 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -38,4 +36,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index cd2128be..ae8078e7 100755 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -38,4 +36,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index 8231f090..c010a948 100755 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -40,4 +38,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 16e3730b..85cca9e2 100755 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -40,4 +38,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py index c0a54d85..4a410d51 100755 --- a/compiler/tests/03_ptx_4finger_nmos_test.py +++ b/compiler/tests/03_ptx_4finger_nmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -40,4 +38,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py index afb874af..34fbaf9f 100755 --- a/compiler/tests/03_ptx_4finger_pmos_test.py +++ b/compiler/tests/03_ptx_4finger_pmos_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic parameterized transistors" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -40,4 +38,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index 3b3388e9..4ee360ce 100755 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -1,17 +1,15 @@ #!/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. +# 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. # -"Run a regression test on a basic wire" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -133,4 +131,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_test.py new file mode 100755 index 00000000..e8e3cc1c --- /dev/null +++ b/compiler/tests/04_dummy_pbitcell_test.py @@ -0,0 +1,50 @@ +#!/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_pbitcell_test(openram_test): + + def runTest(self): + 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 + + factory.reset() + debug.info(2, "Checking dummy bitcell using pbitcell (small cell)") + tx = dummy_pbitcell.dummy_pbitcell(name="rpbc") + self.local_check(tx) + + 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() + +# 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()) diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index af99f6ec..42045b43 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a pand2 cell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -39,4 +35,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py new file mode 100755 index 00000000..4408f6e8 --- /dev/null +++ b/compiler/tests/04_pand3_test.py @@ -0,0 +1,38 @@ +#!/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 pand3_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + global verify + import verify + + import pand3 + + debug.info(2, "Testing pand3 gate 4x") + a = pand3.pand3(name="pand3x4", size=4) + self.local_check(a) + + globals.end_openram() + +# instantiate a copdsay of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index e8b7cb55..0f14c4c5 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run regresion tests on a parameterized bitcell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -114,4 +110,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index 9eeaaeab..35db8ccf 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 2-row buffer cell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index ecd697c9..abaab4a0 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 2-row buffer cell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -51,4 +47,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index 0548cbf4..2ccce34a 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized inverter -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -36,4 +32,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index 1f8aae26..2f96020c 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized inverter -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index fd70d8dc..9b0f1bc6 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -1,18 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized inverter -""" import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -34,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index 6b472f9e..d8a7598f 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized inverter -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -36,4 +32,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index ea407d0c..86af0708 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 2-row buffer cell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index 527c6204..bc066cfc 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -1,21 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized nand 2. This module doesn't -generate a multi_finger 2-input nand gate. It generates only a minimum -size 2-input nand gate. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -38,4 +32,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index 6dba468a..8bf5098f 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -1,21 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized pnand3. -This module doesn't generate a multi-finger 3-input nand gate. -It generates only a minimum size 3-input nand gate. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -38,4 +32,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index 8a66324d..0e524506 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -1,21 +1,15 @@ #!/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. +# 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. # -""" -Run regression tests on a parameterized nor 2. This module doesn't -generate a multi_finger 2-input nor gate. It generates only a minimum -size 2-input nor gate. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -37,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 162f1091..9b2addd5 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a precharge cell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -57,4 +53,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index 1e028e40..65ce5ecf 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a replica pbitcell -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -51,4 +47,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index 151f2797..3ecbbe9d 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a wordline_driver array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -54,4 +50,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_bitcell_1rw_1r_array_test.py b/compiler/tests/05_bitcell_1rw_1r_array_test.py index 9df2c8c3..972fb8e6 100755 --- a/compiler/tests/05_bitcell_1rw_1r_array_test.py +++ b/compiler/tests/05_bitcell_1rw_1r_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a basic array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -24,16 +20,20 @@ import debug class bitcell_1rw_1r_array_test(openram_test): 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.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="bitcell_array", cols=4, rows=4) self.local_check(a) - + globals.end_openram() # run the test from the command line @@ -41,4 +41,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index 21943a5d..6a561019 100755 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a basic array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -29,7 +25,7 @@ class array_test(openram_test): debug.info(2, "Testing 4x4 array for 6t_cell") a = factory.create(module_type="bitcell_array", cols=4, rows=4) self.local_check(a) - + globals.end_openram() # run the test from the command line @@ -37,4 +33,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_dummy_array_test.py b/compiler/tests/05_dummy_array_test.py new file mode 100755 index 00000000..de379a97 --- /dev/null +++ b/compiler/tests/05_dummy_array_test.py @@ -0,0 +1,36 @@ +#!/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 dummy_row_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + debug.info(2, "Testing dummy row for 6t_cell") + a = factory.create(module_type="dummy_array", rows=1, cols=4) + self.local_check(a) + + debug.info(2, "Testing dummy column for 6t_cell") + a = factory.create(module_type="dummy_array", rows=4, cols=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()) diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index 45968266..91bf7522 100755 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a basic array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -56,4 +52,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_replica_pbitcell_array_test.py b/compiler/tests/05_replica_pbitcell_array_test.py new file mode 100755 index 00000000..2bc4a0d2 --- /dev/null +++ b/compiler/tests/05_replica_pbitcell_array_test.py @@ -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()) diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index bcc22ce8..c349e889 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a hierarchical_decoder. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -80,4 +76,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index e4687d5e..0a5363ab 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a hierarchical_predecode2x4. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -46,4 +42,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index 12e87d06..b2a8d438 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a hierarchical_predecode3x8. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -46,4 +42,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index 8da5f252..c6cd7ed2 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -1,18 +1,14 @@ #!/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. +# 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. # -""" -Run a regression test on a single transistor column_mux. -""" - -from testutils import header,openram_test,unittest +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -68,4 +64,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 86f308f4..ee29211b 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a precharge array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -55,4 +51,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 585b85cd..31415a6c 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a wordline_driver array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -49,4 +45,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index 12a20e8f..e35ea3c3 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a sense amp array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -55,4 +51,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index f5d0c23c..20dacca6 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a write driver array -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -55,4 +51,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/10_write_driver_array_wmask_test.py b/compiler/tests/10_write_driver_array_wmask_test.py new file mode 100755 index 00000000..d09286b5 --- /dev/null +++ b/compiler/tests/10_write_driver_array_wmask_test.py @@ -0,0 +1,61 @@ +#!/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 write_driver_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + # check write driver array for single port + debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=16, write_size=2") + a = factory.create(module_type="write_driver_array", columns=16, word_size=16, write_size=2) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4) + self.local_check(a) + + # check write driver array for multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 + + factory.reset() + debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4 (multi-port case)") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4) + 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()) \ No newline at end of file diff --git a/compiler/tests/10_write_mask_and_array_test.py b/compiler/tests/10_write_mask_and_array_test.py new file mode 100755 index 00000000..91155467 --- /dev/null +++ b/compiler/tests/10_write_mask_and_array_test.py @@ -0,0 +1,61 @@ +#!/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 write_mask_and_array_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + # check write driver array for single port + debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4") + a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=16, write_size=4") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=16, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) + self.local_check(a) + + # check write driver array for multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 + + factory.reset() + debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)") + a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) + 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()) diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py index fc48adce..b843a6bb 100755 --- a/compiler/tests/11_dff_array_test.py +++ b/compiler/tests/11_dff_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a dff_array. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -43,4 +39,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py index 7d614d1b..ec0e7742 100755 --- a/compiler/tests/11_dff_buf_array_test.py +++ b/compiler/tests/11_dff_buf_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a dff_array. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -43,4 +39,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/11_dff_buf_test.py b/compiler/tests/11_dff_buf_test.py index afb1f73b..161deaa2 100755 --- a/compiler/tests/11_dff_buf_test.py +++ b/compiler/tests/11_dff_buf_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a dff_buf. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py index 203c5f94..0bd5f60c 100755 --- a/compiler/tests/12_tri_gate_array_test.py +++ b/compiler/tests/12_tri_gate_array_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a tri_gate_array. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,7 +23,7 @@ class tri_gate_array_test(openram_test): debug.info(1, "Testing tri_gate_array for columns=8, word_size=8") a = factory.create(module_type="tri_gate_array", columns=8, word_size=8) self.local_check(a) - + debug.info(1, "Testing tri_gate_array for columns=16, word_size=8") a = factory.create(module_type="tri_gate_array", columns=16, word_size=8) self.local_check(a) @@ -39,4 +35,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index 498c1005..9dc8faeb 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a test on a delay chain -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,4 +31,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py new file mode 100755 index 00000000..bae7edde --- /dev/null +++ b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py @@ -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()) diff --git a/compiler/tests/14_replica_bitcell_array_test.py b/compiler/tests/14_replica_bitcell_array_test.py new file mode 100755 index 00000000..2b446758 --- /dev/null +++ b/compiler/tests/14_replica_bitcell_array_test.py @@ -0,0 +1,32 @@ +#!/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)) + + debug.info(2, "Testing 4x4 array for 6t_cell") + 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()) diff --git a/compiler/tests/14_replica_bitline_multiport_test.py b/compiler/tests/14_replica_bitline_multiport_test.py deleted file mode 100755 index 947f9c52..00000000 --- a/compiler/tests/14_replica_bitline_multiport_test.py +++ /dev/null @@ -1,70 +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. -# -""" -Run a test on a multiport replica bitline -""" - -import unittest -from testutils import header,openram_test -import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -from globals import OPTS -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() diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py deleted file mode 100755 index b5830d63..00000000 --- a/compiler/tests/14_replica_bitline_test.py +++ /dev/null @@ -1,48 +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. -# -""" -Run a test on a replica bitline -""" - -import unittest -from testutils import header,openram_test -import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - -class replica_bitline_test(openram_test): - - def runTest(self): - globals.init_openram("config_{0}".format(OPTS.tech_name)) - - # check replica bitline in single port - stages=4 - fanout=4 - rows=13 - 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) - - 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() diff --git a/compiler/tests/14_replica_column_test.py b/compiler/tests/14_replica_column_test.py new file mode 100755 index 00000000..c0db4d17 --- /dev/null +++ b/compiler/tests/14_replica_column_test.py @@ -0,0 +1,40 @@ +#!/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_column_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + debug.info(2, "Testing replica column for 6t_cell") + a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1) + 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() + +# 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()) diff --git a/compiler/tests/16_control_logic_multiport_test.py b/compiler/tests/16_control_logic_multiport_test.py new file mode 100755 index 00000000..66c34d24 --- /dev/null +++ b/compiler/tests/16_control_logic_multiport_test.py @@ -0,0 +1,59 @@ +#!/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. +# +""" +Run a regression test on a control_logic +""" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class control_logic_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + import control_logic + import tech + + # check control logic for multi-port + OPTS.bitcell = "pbitcell" + OPTS.replica_bitcell = "replica_pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + debug.info(1, "Testing sample for control_logic for multiport, only write control logic") + a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw") + self.local_check(a) + + # OPTS.num_rw_ports = 0 + # OPTS.num_w_ports = 1 + debug.info(1, "Testing sample for control_logic for multiport, only write control logic") + a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="w") + self.local_check(a) + + # OPTS.num_w_ports = 0 + # OPTS.num_r_ports = 1 + debug.info(1, "Testing sample for control_logic for multiport, only read control logic") + a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="r") + 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() diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index ed8a0088..92d5c94b 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a control_logic -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -26,48 +22,21 @@ class control_logic_test(openram_test): import control_logic import tech - # check control logic for single port - debug.info(1, "Testing sample for control_logic") + debug.info(1, "Testing sample for control_logic_rw") a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32) self.local_check(a) - - # check control logic for 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 - - debug.info(1, "Testing sample for control_logic for multiport") - a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8) - self.local_check(a) - - # Check port specific control logic - OPTS.num_rw_ports = 1 - OPTS.num_w_ports = 0 - OPTS.num_r_ports = 0 - debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw") - self.local_check(a) - - OPTS.num_rw_ports = 0 - OPTS.num_w_ports = 1 - debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="w") - self.local_check(a) - - OPTS.num_w_ports = 0 - OPTS.num_r_ports = 1 - debug.info(1, "Testing sample for control_logic for multiport, only read control logic") - a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="r") + 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) - globals.end_openram() + 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 if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_address_test.py b/compiler/tests/18_port_address_test.py new file mode 100755 index 00000000..c8db6ec2 --- /dev/null +++ b/compiler/tests/18_port_address_test.py @@ -0,0 +1,32 @@ +#!/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 port_address_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + + debug.info(1, "Port address 16 rows") + a = factory.create("port_address", cols=16, rows=16) + 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()) diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_test.py new file mode 100755 index 00000000..e5f94329 --- /dev/null +++ b/compiler/tests/18_port_data_test.py @@ -0,0 +1,110 @@ +#!/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 port_data_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + + c = sram_config(word_size=4, + num_words=16) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + OPTS.bitcell = "bitcell_1w_1r" + OPTS.num_rw_ports = 0 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + c.num_words=16 + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=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()) diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py new file mode 100755 index 00000000..e9b70337 --- /dev/null +++ b/compiler/tests/18_port_data_wmask_test.py @@ -0,0 +1,113 @@ +#!/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 port_data_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + + c = sram_config(word_size=16, + write_size=4, + num_words=16) + + c.words_per_row = 1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words = 32 + c.words_per_row = 2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words = 64 + c.words_per_row = 4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words = 128 + c.words_per_row = 8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + OPTS.bitcell = "bitcell_1w_1r" + OPTS.num_rw_ports = 0 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + c.num_words = 16 + c.words_per_row = 1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + # + c.num_words = 32 + c.words_per_row = 2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.num_words = 64 + c.words_per_row = 4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.word_size = 8 + c.num_words = 128 + c.words_per_row = 8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=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()) diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py index 5ea16052..e2f5a9a8 100755 --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -52,4 +48,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 3139b4eb..1816cd61 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -69,4 +65,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py index f31e2608..749460fa 100755 --- a/compiler/tests/19_pmulti_bank_test.py +++ b/compiler/tests/19_pmulti_bank_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -74,4 +70,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index 22c3da2f..90e886f4 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -24,14 +20,16 @@ class psingle_bank_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) - from bank import bank 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_w_ports = 0 OPTS.num_r_ports = 0 + c = sram_config(word_size=4, num_words=16) @@ -39,8 +37,7 @@ class psingle_bank_test(openram_test): factory.reset() c.recompute_sizes() 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 = bank(c, name=name) + a = factory.create(module_type="bank", sram_config=c) self.local_check(a) c.num_words=32 @@ -48,8 +45,7 @@ class psingle_bank_test(openram_test): factory.reset() c.recompute_sizes() 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 = bank(c, name=name) + a = factory.create(module_type="bank", sram_config=c) self.local_check(a) c.num_words=64 @@ -57,8 +53,7 @@ class psingle_bank_test(openram_test): factory.reset() c.recompute_sizes() 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 = bank(c, name=name) + a = factory.create(module_type="bank", sram_config=c) self.local_check(a) c.word_size=2 @@ -67,93 +62,9 @@ class psingle_bank_test(openram_test): factory.reset() c.recompute_sizes() 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 = bank(c, name=name) + a = factory.create(module_type="bank", sram_config=c) 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() # run the test from the command line @@ -161,4 +72,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_1rw_1r_test.py b/compiler/tests/19_single_bank_1rw_1r_test.py index fb0e1c66..ab5ce041 100755 --- a/compiler/tests/19_single_bank_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_1rw_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on 1rw 1r sram bank -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -23,13 +19,15 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config 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 - from sram_config import sram_config c = sram_config(word_size=4, num_words=16) @@ -72,4 +70,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_1w_1r_test.py b/compiler/tests/19_single_bank_1w_1r_test.py new file mode 100755 index 00000000..12b9f3a0 --- /dev/null +++ b/compiler/tests/19_single_bank_1w_1r_test.py @@ -0,0 +1,74 @@ +#!/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 single_bank_1w_1r_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + + OPTS.bitcell = "bitcell_1w_1r" + 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_w_ports = 1 + + c = sram_config(word_size=4, + num_words=16) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create(module_type="bank", sram_config=c) + 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()) diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 72e61c0d..1d010db5 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -67,4 +63,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_wmask_test.py b/compiler/tests/19_single_bank_wmask_test.py new file mode 100755 index 00000000..439ffeba --- /dev/null +++ b/compiler/tests/19_single_bank_wmask_test.py @@ -0,0 +1,68 @@ +#!/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 single_bank_wmask_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + + + c = sram_config(word_size=8, + write_size=4, + num_words=16, + num_banks=1) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("bank", sram_config=c) + 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()) diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py index 4bdad91f..fdeae56f 100755 --- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -25,9 +21,10 @@ class psram_1bank_2mux_1rw_1w_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) from sram_config import sram_config + OPTS.bitcell = "pbitcell" OPTS.replica_bitcell="replica_pbitcell" - + OPTS.dummy_bitcell="dummy_pbitcell" OPTS.num_rw_ports = 1 OPTS.num_w_ports = 1 OPTS.num_r_ports = 0 @@ -57,4 +54,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py index a0b2b242..a5c01d8f 100755 --- a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -25,9 +21,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) from sram_config import sram_config + OPTS.bitcell = "pbitcell" OPTS.replica_bitcell="replica_pbitcell" - + OPTS.dummy_bitcell="dummy_pbitcell" OPTS.num_rw_ports = 0 OPTS.num_w_ports = 1 OPTS.num_r_ports = 1 @@ -55,4 +52,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_psram_1bank_2mux_test.py b/compiler/tests/20_psram_1bank_2mux_test.py index c718daa3..64fa72ca 100755 --- a/compiler/tests/20_psram_1bank_2mux_test.py +++ b/compiler/tests/20_psram_1bank_2mux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,6 +23,7 @@ class psram_1bank_2mux_test(openram_test): from sram_config import sram_config OPTS.bitcell = "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) OPTS.num_rw_ports = 1 @@ -58,4 +55,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py index f415bd77..7779b794 100755 --- a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py +++ b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -24,9 +20,10 @@ class psram_1bank_4mux_1rw_1r_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) from sram_config import sram_config + OPTS.bitcell = "pbitcell" OPTS.replica_bitcell="replica_pbitcell" - + OPTS.dummy_bitcell="dummy_pbitcell" OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 1 @@ -56,4 +53,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py index 46725bc5..60192759 100755 --- a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank, 2 port SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,6 +23,7 @@ class sram_1bank_2mux_1rw_1r_test(openram_test): 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 @@ -56,4 +53,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py index fec42aeb..2e1e848f 100755 --- a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -25,9 +21,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) from sram_config import sram_config + OPTS.bitcell = "bitcell_1w_1r" OPTS.replica_bitcell="replica_bitcell_1w_1r" - + OPTS.dummy_bitcell="dummy_bitcell_1w_1r" OPTS.num_rw_ports = 0 OPTS.num_w_ports = 1 OPTS.num_r_ports = 1 @@ -57,4 +54,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index c61ebe4f..7e5a4f3a 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -50,4 +46,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_test.py new file mode 100755 index 00000000..65f025a7 --- /dev/null +++ b/compiler/tests/20_sram_1bank_2mux_wmask_test.py @@ -0,0 +1,54 @@ +#!/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 + + +# @unittest.skip("SKIPPING 20_sram_1bank_2mux_wmask_test") +class sram_1bank_2mux_wmask_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + c = sram_config(word_size=8, + write_size=4, + num_words=64, + num_banks=1) + + c.words_per_row = 2 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} bit writes, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.write_size, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 5d10903c..34af86a1 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -50,4 +46,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py index 3a2c34e6..48a42106 100755 --- a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,6 +23,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test): 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 @@ -56,4 +53,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index 94c073f9..c5eaea75 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -50,4 +46,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py index 2ce13456..f6bccc13 100755 --- a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank, 2 port SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,6 +23,7 @@ class sram_1bank_nomux_1rw_1r_test(openram_test): 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 @@ -56,4 +53,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index 272d16ee..650d2ac2 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -50,4 +46,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py new file mode 100755 index 00000000..e0292e95 --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py @@ -0,0 +1,54 @@ +#!/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 + + +# @unittest.skip("SKIPPING 20_sram_1bank_nomux_wmask_test") +class sram_1bank_nomux_wmask_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + from sram_config import sram_config + c = sram_config(word_size=8, + write_size=4, + num_words=16, + num_banks=1) + + c.words_per_row = 1 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} bit writes, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.write_size, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index b625f9ec..c5d9d3d0 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on a 2 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -100,4 +96,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index aa6cbf49..f4827db2 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -37,10 +33,17 @@ class timing_sram_test(openram_test): num_words=16, num_banks=1) c.words_per_row=1 + # c = sram_config(word_size=32, + # num_words=256, + # num_banks=1) + # c.words_per_row=2 + # OPTS.use_tech_delay_chain_size = True c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") s = factory.create(module_type="sram", sram_config=c) - + #import sys + #sys.exit(1) + tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) @@ -58,28 +61,27 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2121267], - 'delay_lh': [0.2121267], - 'leakage_power': 0.0023761999999999998, - 'min_period': 0.43, - 'read0_power': [0.5139368], - 'read1_power': [0.48940979999999995], - 'slew_hl': [0.0516745], - 'slew_lh': [0.0516745], - 'write0_power': [0.46267169999999996], - 'write1_power': [0.4670826]} + golden_data = {'delay_hl': [0.2181231], + 'delay_lh': [0.2181231], + 'leakage_power': 0.0025453999999999997, + 'min_period': 0.781, + 'read0_power': [0.34664159999999994], + 'read1_power': [0.32656349999999995], + 'slew_hl': [0.21136519999999998], + 'slew_lh': [0.21136519999999998], + 'write0_power': [0.37980179999999997], + 'write1_power': [0.3532026]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.288], - 'delay_lh': [1.288], - 'leakage_power': 0.0273896, - 'min_period': 2.578, - 'read0_power': [16.9996], - 'read1_power': [16.2616], - 'slew_hl': [0.47891700000000004], - 'slew_lh': [0.47891700000000004], - 'write0_power': [16.0656], - 'write1_power': [16.2616]} - + golden_data = {'delay_hl': [1.4082], + 'delay_lh': [1.4082], + 'leakage_power': 0.0267388, + 'min_period': 4.688, + 'read0_power': [11.5255], + 'read1_power': [10.9406], + 'slew_hl': [1.2979], + 'slew_lh': [1.2979], + 'write0_power': [12.9458], + 'write1_power': [11.7444]} else: self.assertTrue(False) # other techs fail # Check if no too many or too few results @@ -94,4 +96,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 49c0d2cb..ef5cf1a8 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -65,4 +61,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index c54a9118..114f0c6e 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -1,26 +1,24 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory 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): globals.init_openram("config_{0}".format(OPTS.tech_name)) OPTS.analytical_delay = False @@ -53,23 +51,28 @@ class model_delay_sram_test(openram_test): import tech loads = [tech.spice["msflop_in_cap"]*4] slews = [tech.spice["rise_time"]*2] + + # Run a spice characterization spice_data, port_data = d.analyze(probe_address, probe_data, slews, loads) spice_data.update(port_data[0]) + # Run analytical characterization model_data, port_data = d.analytical_delay(slews, loads) model_data.update(port_data[0]) - #Only compare the delays + # Only compare the delays spice_delays = {key:value for key, value in spice_data.items() if 'delay' in key} model_delays = {key:value for key, value in model_data.items() if 'delay' in key} debug.info(1,"Spice Delays={}".format(spice_delays)) debug.info(1,"Model Delays={}".format(model_delays)) + if OPTS.tech_name == "freepdk45": - error_tolerance = .25 + error_tolerance = 0.25 elif OPTS.tech_name == "scn4m_subm": - error_tolerance = .25 + error_tolerance = 0.25 else: self.assertTrue(False) # other techs fail + # Check if no too many or too few results self.assertTrue(len(spice_delays.keys())==len(model_delays.keys())) @@ -82,4 +85,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index c12d3835..39f0d5e0 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -58,28 +54,27 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2108836], - 'delay_lh': [0.2108836], - 'leakage_power': 0.001564799, - 'min_period': 0.508, - 'read0_power': [0.43916689999999997], - 'read1_power': [0.4198608], - 'slew_hl': [0.0455126], - 'slew_lh': [0.0455126], - 'write0_power': [0.40681890000000004], - 'write1_power': [0.4198608]} + golden_data = {'delay_hl': [0.2264205], + 'delay_lh': [0.2264205], + 'leakage_power': 0.0021017429999999997, + 'min_period': 0.859, + 'read0_power': [0.3339161], + 'read1_power': [0.31329440000000003], + 'slew_hl': [0.2590786], + 'slew_lh': [0.2590786], + 'write0_power': [0.36360849999999995], + 'write1_power': [0.3486931]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.5747600000000002], - 'delay_lh': [1.5747600000000002], - 'leakage_power': 0.00195795, - 'min_period': 3.281, - 'read0_power': [14.92874], - 'read1_power': [14.369810000000001], - 'slew_hl': [0.49631959999999997], - 'slew_lh': [0.49631959999999997], - 'write0_power': [13.79953], - 'write1_power': [14.369810000000001]} - + golden_data = {'delay_hl': [1.7083549999999998], + 'delay_lh': [1.7083549999999998], + 'leakage_power': 0.001119657, + 'min_period': 7.812, + 'read0_power': [8.013845], + 'read1_power': [7.6889389999999995], + 'slew_hl': [1.31918], + 'slew_lh': [1.31918], + 'write0_power': [8.791557000000001], + 'write1_power': [8.70443]} else: self.assertTrue(False) # other techs fail @@ -95,4 +90,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index abf64d33..4a289812 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -66,4 +62,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index 4a99f009..f986c3e7 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -1,36 +1,34 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -#@unittest.skip("SKIPPING 22_psram_1bank_2mux_1rw_1r_1w_func_test, third port reads are broken?") -class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test): +class psram_1bank_2mux_func_test(openram_test): def runTest(self): globals.init_openram("config_{0}".format(OPTS.tech_name)) OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False + 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_r_ports = 0 OPTS.num_w_ports = 1 # This is a hack to reload the characterizer __init__ with the spice version @@ -39,28 +37,25 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test): reload(characterizer) from characterizer import functional, delay from sram_config import sram_config - c = sram_config(word_size=4, - num_words=64, + c = sram_config(word_size=2, + num_words=32, num_banks=1) c.words_per_row=2 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, - OPTS.num_r_ports, - OPTS.num_w_ports, - c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for {}rw,{}r,{}w psram with" + "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -71,4 +66,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py index 9eaa2671..c5fd8945 100755 --- a/compiler/tests/22_psram_1bank_4mux_func_test.py +++ b/compiler/tests/22_psram_1bank_4mux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,10 +23,13 @@ class psram_1bank_4mux_func_test(openram_test): OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False + 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_r_ports = 0 OPTS.num_w_ports = 1 # This is a hack to reload the characterizer __init__ with the spice version @@ -39,28 +38,25 @@ class psram_1bank_4mux_func_test(openram_test): reload(characterizer) from characterizer import functional, delay from sram_config import sram_config - c = sram_config(word_size=4, + c = sram_config(word_size=2, num_words=256, num_banks=1) c.words_per_row=4 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, - OPTS.num_r_ports, - OPTS.num_w_ports, - c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for {}rw,{}r,{}w psram with" + "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -71,4 +67,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index a0d52d1b..acb168c0 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,10 +23,13 @@ class psram_1bank_8mux_func_test(openram_test): OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False + 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_r_ports = 0 OPTS.num_w_ports = 1 # This is a hack to reload the characterizer __init__ with the spice version @@ -44,23 +43,20 @@ class psram_1bank_8mux_func_test(openram_test): num_banks=1) c.words_per_row=8 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, - OPTS.num_r_ports, - OPTS.num_w_ports, - c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for {}rw,{}r,{}w psram with" + "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -71,4 +67,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index 7b76e0da..a2a2b41c 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a functioal test on 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -27,10 +23,13 @@ class psram_1bank_nomux_func_test(openram_test): OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False + 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_r_ports = 0 OPTS.num_w_ports = 1 # This is a hack to reload the characterizer __init__ with the spice version @@ -39,28 +38,25 @@ class psram_1bank_nomux_func_test(openram_test): reload(characterizer) from characterizer import functional, delay from sram_config import sram_config - c = sram_config(word_size=4, + c = sram_config(word_size=2, num_words=32, num_banks=1) c.words_per_row=1 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, - OPTS.num_r_ports, - OPTS.num_w_ports, - c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for {}rw,{}r,{}w psram with" + "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -71,4 +67,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index e5fa9280..2037169e 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,25 +31,22 @@ class sram_1bank_2mux_func_test(openram_test): from characterizer import functional, delay from sram_config import sram_config c = sram_config(word_size=4, - num_words=64, + num_words=32, num_banks=1) c.words_per_row=2 c.recompute_sizes() - debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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(feasible_period) + (fail, error) = f.run() self.assertTrue(fail,error) globals.end_openram() @@ -63,4 +56,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index dc06a882..178f955b 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -35,24 +31,21 @@ class sram_1bank_4mux_func_test(openram_test): from characterizer import functional, delay from sram_config import sram_config c = sram_config(word_size=4, - num_words=256, + num_words=128, num_banks=1) c.words_per_row=4 c.recompute_sizes() - debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -63,4 +56,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index ee3449ab..d531163a 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on various srams -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -38,24 +34,21 @@ class sram_1bank_8mux_func_test(openram_test): from sram_config import sram_config c = sram_config(word_size=4, - num_words=256, + num_words=128, num_banks=1) c.words_per_row=8 c.recompute_sizes() - debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -66,4 +59,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index bc626858..eb6d2412 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a functioal test on 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -34,22 +30,21 @@ class sram_1bank_nomux_func_test(openram_test): from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, - num_words=32, + num_words=16, num_banks=1) c.words_per_row=1 c.recompute_sizes() - debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) - f.num_cycles = 10 (fail, error) = f.run() self.assertTrue(fail,error) @@ -60,4 +55,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py index 0b8bffcc..169e34d0 100755 --- a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a functioal test on 1 bank SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -29,6 +25,7 @@ class psram_1bank_nomux_func_test(openram_test): OPTS.trim_netlist = False 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_w_ports = 0 OPTS.num_r_ports = 1 @@ -44,20 +41,17 @@ class psram_1bank_nomux_func_test(openram_test): num_banks=1) c.words_per_row=1 c.recompute_sizes() - debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, - c.num_words, - c.words_per_row, - c.num_banks)) + debug.info(1, "Functional test for sram 1rw,1r with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) 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) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) 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() self.assertTrue(fail,error) @@ -68,4 +62,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/22_sram_wmask_1w_1r_func_test.py b/compiler/tests/22_sram_wmask_1w_1r_func_test.py new file mode 100755 index 00000000..2ee79750 --- /dev/null +++ b/compiler/tests/22_sram_wmask_1w_1r_func_test.py @@ -0,0 +1,72 @@ +#!/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 + + +# @unittest.skip("SKIPPING sram_wmask_1w_1r_func_test") +class sram_wmask_1w_1r_func_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + OPTS.analytical_delay = False + OPTS.netlist_only = True + OPTS.trim_netlist = False + OPTS.bitcell = "bitcell_1w_1r" + OPTS.replica_bitcell = "replica_bitcell_1w_1r" + OPTS.dummy_bitcell = "dummy_bitcell_1w_1r" + + OPTS.num_rw_ports = 0 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import functional, delay + from sram_config import sram_config + c = sram_config(word_size=8, + num_words=16, + write_size=2, + num_banks=1) + c.words_per_row = 1 + c.recompute_sizes() + debug.info(1, + "Functional test for sram with {} bit words, {} words, {} words per row, {} bit writes, {} banks".format( + c.word_size, + c.num_words, + c.words_per_row, + c.write_size, + c.num_banks)) + s = factory.create(module_type="sram", sram_config=c) + tempspice = OPTS.openram_temp + "sram.sp" + s.sp_write(tempspice) + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + f = functional(s.s, tempspice, corner) + (fail, error) = f.run() + self.assertTrue(fail, error) + + 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()) diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py new file mode 100755 index 00000000..c390f030 --- /dev/null +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -0,0 +1,61 @@ +#!/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 + +#@unittest.skip("SKIPPING sram_wmask_func_test") +class sram_wmask_func_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + OPTS.analytical_delay = False + OPTS.netlist_only = True + OPTS.trim_netlist = False + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import functional, delay + from sram_config import sram_config + c = sram_config(word_size=8, + num_words=16, + write_size=4, + num_banks=1) + c.words_per_row=1 + c.recompute_sizes() + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} bit writes, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.write_size, + c.num_banks)) + s = factory.create(module_type="sram", sram_config=c) + tempspice = OPTS.openram_temp + "sram.sp" + s.sp_write(tempspice) + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + f = functional(s.s, tempspice, corner) + (fail, error) = f.run() + self.assertTrue(fail, error) + + 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()) diff --git a/compiler/tests/23_lib_sram_model_corners_test.py b/compiler/tests/23_lib_sram_model_corners_test.py index 85d96a73..84b54e3d 100755 --- a/compiler/tests/23_lib_sram_model_corners_test.py +++ b/compiler/tests/23_lib_sram_model_corners_test.py @@ -1,24 +1,21 @@ #!/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. +# 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. # -""" -Check the .lib file for an SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS 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): globals.init_openram("config_{0}".format(OPTS.tech_name)) @@ -70,7 +67,7 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index e1727794..9fdda7e7 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -1,24 +1,21 @@ #!/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. +# 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. # -""" -Check the .lib file for an SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS 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): globals.init_openram("config_{0}".format(OPTS.tech_name)) @@ -60,7 +57,7 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 0d33d1af..1fc5a66b 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -1,24 +1,21 @@ #!/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. +# 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. # -""" -Check the .lib file for an SRAM with pruning -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS 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): globals.init_openram("config_{0}".format(OPTS.tech_name)) @@ -71,7 +68,7 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 6f2bf0b7..0ababf32 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Check the .lib file for an SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -70,7 +66,7 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 362495d7..5f7fdc60 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Check the LEF file for an SRMA -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -54,4 +50,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index 0bbe45b7..da6a2682 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Check the .v file for an SRAM -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS import debug @@ -51,4 +47,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py new file mode 100755 index 00000000..f0cccba3 --- /dev/null +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +""" +Run regression tests/pex test on an extracted pinv to ensure pex functionality +with HSPICE. +""" +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + + +class hspice_pex_pinv_test(openram_test): + + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + import pinv + + # load the hspice + OPTS.spice_name="hspice" + OPTS.analytical_delay = False + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + + # generate the pinv + prev_purge_value = OPTS.purge_temp + OPTS.purge_temp = False # force set purge to false to save the sp file + debug.info(2, "Checking 1x size inverter") + tx = pinv.pinv(name="pinv", size=1) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tx.gds_write(tempgds) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tx.sp_write(tempsp) + + # make sure that the library simulation is successful\ + sp_delay = self.simulate_delay(test_module = tempsp, + top_level_name = tx.name) + if sp_delay is "Failed": + self.fail('Library Spice module did not behave as expected') + + # now generate its pex file + pex_file = self.run_pex(tx) + OPTS.purge_temp = prev_purge_value # restore the old purge value + # generate simulation for pex, make sure the simulation is successful + pex_delay = self.simulate_delay(test_module = pex_file, + top_level_name = tx.name) + # make sure the extracted spice simulated + if pex_delay is "Failed": + self.fail('Pex file did not behave as expected') + + # if pex data is bigger than original spice file then result is ok + # However this may not always be true depending on the netlist provided + # comment out for now + #debug.info(2,"pex_delay: {0}".format(pex_delay)) + #debug.info(2,"sp_delay: {0}".format(sp_delay)) + + #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + #.format(pex_delay,sp_delay) + + globals.end_openram() + + def simulate_delay(self, test_module, top_level_name): + from characterizer import charutils + from charutils import parse_spice_list + # setup simulation + sim_file = OPTS.openram_temp + "stim.sp" + log_file_name = "timing" + test_sim = self.write_simulation(sim_file, test_module, top_level_name) + test_sim.run_sim() + delay = parse_spice_list(log_file_name, "pinv_delay") + return delay + + def write_simulation(self, sim_file, cir_file, top_module_name): + """ write pex spice simulation for a pinv test""" + import tech + from characterizer import measurements, stimuli + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + sim_file = open(sim_file, "w") + simulation = stimuli(sim_file,corner) + + # library files + simulation.write_include(cir_file) + + # supply voltages + simulation.gen_constant(sig_name ="vdd", + v_val = tech.spice["nom_supply_voltage"]) + simulation.gen_constant(sig_name = "gnd", + v_val = "0v") + + run_time = tech.spice["feasible_period"] * 4 + # input voltage + clk_period = tech.spice["feasible_period"] + simulation.gen_pwl(sig_name ="input", + clk_times = [clk_period,clk_period], + data_values = [1,0], + period = clk_period, + slew = 0.001*tech.spice["feasible_period"], + setup = 0) + + # instantiation of simulated pinv + simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], + model_name = top_module_name) + + # delay measurement + delay_measure = measurements.delay_measure(measure_name = "pinv_delay", + trig_name = "input", + targ_name = "output", + trig_dir_str = "FALL", + targ_dir_str = "RISE", + has_port = False) + trig_td = trag_td = 0.01 * run_time + rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + delay_measure.write_measure(simulation, rest_info) + + simulation.write_control(end_time = run_time) + sim_file.close() + return simulation + + +# 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() diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py new file mode 100755 index 00000000..2eb95948 --- /dev/null +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +""" +Run regression tests/pex test on an extracted pinv to ensure pex functionality +with Ngspice. +""" +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + + +class ngspice_pex_pinv_test(openram_test): + def runTest(self): + globals.init_openram("config_{0}".format(OPTS.tech_name)) + import pinv + + # load the ngspice + OPTS.spice_name="ngspice" + OPTS.analytical_delay = False + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + + # generate the pinv module + prev_purge_value = OPTS.purge_temp + OPTS.purge_temp = False # force set purge to false to save the sp file + debug.info(2, "Checking 1x size inverter") + tx = pinv.pinv(name="pinv", size=1) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tx.gds_write(tempgds) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tx.sp_write(tempsp) + + # make sure that the library simulation is successful + sp_delay = self.simulate_delay(test_module = tempsp, + top_level_name = tx.name) + if sp_delay is "Failed": + self.fail('Library Spice module did not behave as expected') + + # now generate its pex file + pex_file = self.run_pex(tx) + OPTS.purge_temp = prev_purge_value # restore the old purge value + # generate simulation for pex, make sure the simulation is successful + pex_delay = self.simulate_delay(test_module = pex_file, + top_level_name = tx.name) + # make sure the extracted spice simulated + if pex_delay is "Failed": + self.fail('Pex file did not behave as expected') + + # if pex data is bigger than original spice file then result is ok + # However this may not always be true depending on the netlist provided + # comment out for now + #debug.info(2,"pex_delay: {0}".format(pex_delay)) + #debug.info(2,"sp_delay: {0}".format(sp_delay)) + + #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + #.format(pex_delay,sp_delay) + + globals.end_openram() + + def simulate_delay(self, test_module, top_level_name): + from characterizer import charutils + from charutils import parse_spice_list + # setup simulation + sim_file = OPTS.openram_temp + "stim.sp" + log_file_name = "timing" + test_sim = self.write_simulation(sim_file, test_module, top_level_name) + test_sim.run_sim() + delay = parse_spice_list(log_file_name, "pinv_delay") + return delay + + def write_simulation(self, sim_file, cir_file, top_module_name): + """ write pex spice simulation for a pinv test""" + import tech + from characterizer import measurements, stimuli + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + sim_file = open(sim_file, "w") + simulation = stimuli(sim_file,corner) + + # library files + simulation.write_include(cir_file) + + # supply voltages + simulation.gen_constant(sig_name ="vdd", + v_val = tech.spice["nom_supply_voltage"]) + # The scn4m_subm and ngspice combination will have a gnd source error: + # "Fatal error: instance vgnd is a shorted VSRC" + # However, remove gnd power for all techa pass for this test + # simulation.gen_constant(sig_name = "gnd", + # v_val = "0v") + + + run_time = tech.spice["feasible_period"] * 4 + # input voltage + clk_period = tech.spice["feasible_period"] + simulation.gen_pwl(sig_name ="input", + clk_times = [clk_period,clk_period], + data_values = [1,0], + period = clk_period, + slew = 0.001*tech.spice["feasible_period"], + setup = 0) + + # instantiation of simulated pinv + simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], + model_name = top_module_name) + + # delay measurement + delay_measure = measurements.delay_measure(measure_name = "pinv_delay", + trig_name = "input", + targ_name = "output", + trig_dir_str = "FALL", + targ_dir_str = "RISE", + has_port = False) + trig_td = trag_td = 0.01 * run_time + rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + delay_measure.write_measure(simulation, rest_info) + + simulation.write_control(end_time = run_time) + sim_file.close() + return simulation + +# 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() diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py index 5d26d26e..78409249 100755 --- a/compiler/tests/26_pex_test.py +++ b/compiler/tests/26_pex_test.py @@ -1,19 +1,15 @@ #!/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. +# 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. # -""" -Run a regression test on an extracted SRAM to ensure functionality. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -319,4 +315,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/30_openram_back_end_test.py b/compiler/tests/30_openram_back_end_test.py index d5cbe0af..c579bde6 100755 --- a/compiler/tests/30_openram_back_end_test.py +++ b/compiler/tests/30_openram_back_end_test.py @@ -1,28 +1,22 @@ #!/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. +# 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. # -""" -This tests the top-level executable. It checks that it generates the -appropriate files: .lef, .lib, .sp, .gds, .v. It DOES NOT, however, -check that these files are right. -""" - import unittest -from testutils import header,openram_test +from testutils import * import sys,os,re,shutil -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug import getpass -class openram_test(openram_test): +class openram_back_end_test(openram_test): def runTest(self): OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) @@ -100,4 +94,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/30_openram_front_end_test.py b/compiler/tests/30_openram_front_end_test.py index 006d1bf3..db75fe0a 100755 --- a/compiler/tests/30_openram_front_end_test.py +++ b/compiler/tests/30_openram_front_end_test.py @@ -1,21 +1,23 @@ #!/usr/bin/env python3 -""" -This tests the top-level executable. It checks that it generates the -appropriate files: .lef, .lib, .sp, .gds, .v. It DOES NOT, however, -check that these files are right. -""" - +# 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 header,openram_test +from testutils import * import sys,os,re,shutil -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug 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): OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) @@ -99,4 +101,4 @@ if __name__ == "__main__": (OPTS, args) = globals.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main() + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/config_freepdk45.py b/compiler/tests/config_freepdk45.py index 5a5b2054..3103217f 100644 --- a/compiler/tests/config_freepdk45.py +++ b/compiler/tests/config_freepdk45.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 diff --git a/compiler/tests/config_freepdk45_back_end.py b/compiler/tests/config_freepdk45_back_end.py index 5fc87ead..68417a3b 100644 --- a/compiler/tests/config_freepdk45_back_end.py +++ b/compiler/tests/config_freepdk45_back_end.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 @@ -16,5 +16,5 @@ temperatures = [25] inline_lvsdrc = True route_supplies = True check_lvsdrc = True - +analytical_delay = False diff --git a/compiler/tests/config_freepdk45_front_end.py b/compiler/tests/config_freepdk45_front_end.py index 69d58442..1886d808 100644 --- a/compiler/tests/config_freepdk45_front_end.py +++ b/compiler/tests/config_freepdk45_front_end.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 @@ -13,6 +13,6 @@ process_corners = ["TT"] supply_voltages = [1.0] temperatures = [25] - +analytical_delay = False diff --git a/compiler/tests/config_scn3me_subm.py b/compiler/tests/config_scn3me_subm.py new file mode 100644 index 00000000..7b5b5e15 --- /dev/null +++ b/compiler/tests/config_scn3me_subm.py @@ -0,0 +1,22 @@ +# 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. +# +word_size = 1 +num_words = 16 + +tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] + +route_supplies = True +check_lvsdrc = True + +drc_name = "magic" +lvs_name = "netgen" +pex_name = "magic" + diff --git a/compiler/tests/config_scn3me_subm_back_end.py b/compiler/tests/config_scn3me_subm_back_end.py new file mode 100644 index 00000000..f9c23417 --- /dev/null +++ b/compiler/tests/config_scn3me_subm_back_end.py @@ -0,0 +1,23 @@ +# 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. +# +word_size = 1 +num_words = 16 + +tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] + +route_supplies = True +check_lvsdrc = True +inline_lvsdrc = True +analytical_delay = False + +drc_name = "magic" +lvs_name = "netgen" +pex_name = "magic" diff --git a/compiler/tests/config_scn3me_subm_front_end.py b/compiler/tests/config_scn3me_subm_front_end.py new file mode 100644 index 00000000..40504a18 --- /dev/null +++ b/compiler/tests/config_scn3me_subm_front_end.py @@ -0,0 +1,21 @@ +# 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. +# +word_size = 1 +num_words = 16 + +tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] + +analytical_delay = False + +drc_name = "magic" +lvs_name = "netgen" +pex_name = "magic" + diff --git a/compiler/tests/config_scn4m_subm.py b/compiler/tests/config_scn4m_subm.py index 61e5cfe9..abb31435 100644 --- a/compiler/tests/config_scn4m_subm.py +++ b/compiler/tests/config_scn4m_subm.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 diff --git a/compiler/tests/config_scn4m_subm_back_end.py b/compiler/tests/config_scn4m_subm_back_end.py index d966abfa..35e4cd91 100644 --- a/compiler/tests/config_scn4m_subm_back_end.py +++ b/compiler/tests/config_scn4m_subm_back_end.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 @@ -16,6 +16,7 @@ temperatures = [25] route_supplies = True check_lvsdrc = True inline_lvsdrc = True +analytical_delay = False drc_name = "magic" lvs_name = "netgen" diff --git a/compiler/tests/config_scn4m_subm_front_end.py b/compiler/tests/config_scn4m_subm_front_end.py index d0c8de85..142191a0 100644 --- a/compiler/tests/config_scn4m_subm_front_end.py +++ b/compiler/tests/config_scn4m_subm_front_end.py @@ -1,9 +1,9 @@ # 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. +# 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. # word_size = 1 num_words = 16 diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.lef b/compiler/tests/golden/sram_2_16_1_freepdk45.lef index 5a80802d..15ad3a88 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.lef +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.lef @@ -3,7 +3,7 @@ NAMESCASESENSITIVE ON ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS - DATABASE MICRONS 1000 ; + dataBASE MICRONS 1000 ; END UNITS SITE MacroSite CLASS Core ; @@ -14,48 +14,48 @@ MACRO sram_2_16_1_freepdk45 SIZE 12145.0 BY 43967.5 ; SYMMETRY X Y R90 ; SITE MacroSite ; - PIN DATA[0] + PIN data[0] DIRECTION INOUT ; PORT LAYER metal2 ; RECT 10260.0 67.5 10330.0 207.5 ; END - END DATA[0] - PIN DATA[1] + END data[0] + PIN data[1] DIRECTION INOUT ; PORT LAYER metal2 ; RECT 10965.0 67.5 11035.0 207.5 ; END - END DATA[1] - PIN ADDR[0] + END data[1] + PIN addr[0] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 67.5 8370.0 837.5 8440.0 ; END - END ADDR[0] - PIN ADDR[1] + END addr[0] + PIN addr[1] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 67.5 7665.0 837.5 7735.0 ; END - END ADDR[1] - PIN ADDR[2] + END addr[1] + PIN addr[2] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 67.5 6960.0 837.5 7030.0 ; END - END ADDR[2] - PIN ADDR[3] + END addr[2] + PIN addr[3] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 67.5 6255.0 837.5 6325.0 ; END - END ADDR[3] + END addr[3] PIN CSb DIRECTION INPUT ; PORT diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.sp b/compiler/tests/golden/sram_2_16_1_freepdk45.sp index 90500f05..c499390e 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.sp +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.sp @@ -136,10 +136,10 @@ Xpmos1 vdd A net1 vdd nor_2_pmos121 Xpmos2 net1 B Z vdd nor_2_pmos222 .ENDS nor2 -.SUBCKT msf_control DATA[0] DATA[1] DATA[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd -XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop -XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop -XXdff2 DATA[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop +.SUBCKT msf_control data[0] data[1] data[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd +XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop +XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop +XXdff2 data[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop .ENDS msf_control .SUBCKT replica_cell_6t bl br wl vdd gnd @@ -524,16 +524,16 @@ XINVERTER_[14] Z[14] decode_out[14] vdd gnd INVERTER XINVERTER_[15] Z[15] decode_out[15] vdd gnd INVERTER .ENDS hierarchical_decoder -.SUBCKT msf_address ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd -XXdff0 ADDR[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop -XXdff1 ADDR[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop -XXdff2 ADDR[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop -XXdff3 ADDR[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop +.SUBCKT msf_address addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd +XXdff0 addr[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop +XXdff1 addr[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop +XXdff2 addr[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop +XXdff3 addr[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop .ENDS msf_address -.SUBCKT msf_data_in DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd -XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop -XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop +.SUBCKT msf_data_in data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd +XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop +XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop .ENDS msf_data_in .SUBCKT msf_data_out data_out[0] data_out[1] tri_in[0] tri_in_bar[0] tri_in[1] tri_in_bar[1] sclk vdd gnd @@ -551,9 +551,9 @@ M_6 in_inv in gnd gnd NMOS_VTG W=90.000000n L=50.000000n .ENDS -.SUBCKT tri_gate_array tri_in[0] tri_in[1] DATA[0] DATA[1] en en_bar vdd gnd -XXtri_gate0 tri_in[0] DATA[0] en en_bar vdd gnd tri_gate -XXtri_gate1 tri_in[1] DATA[1] en en_bar vdd gnd tri_gate +.SUBCKT tri_gate_array tri_in[0] tri_in[1] data[0] data[1] en en_bar vdd gnd +XXtri_gate0 tri_in[0] data[0] en en_bar vdd gnd tri_gate +XXtri_gate1 tri_in[1] data[1] en en_bar vdd gnd tri_gate .ENDS tri_gate_array .SUBCKT wordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd @@ -643,19 +643,19 @@ Xpmos1 vdd A net1 vdd nor_2_pmos185 Xpmos2 net1 B Z vdd nor_2_pmos286 .ENDS NOR2 -.SUBCKT test_bank1 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd +.SUBCKT test_bank1 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd Xbitcell_array bl[0] br[0] bl[1] br[1] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd bitcell_array Xprecharge_array bl[0] br[0] bl[1] br[1] clk_bar vdd precharge_array Xsense_amp_array bl[0] br[0] bl[1] br[1] data_out[0] data_out[1] s_en vdd gnd sense_amp_array Xwrite_driver_array data_in[0] data_in[1] bl[0] br[0] bl[1] br[1] w_en vdd gnd write_driver_array -Xdata_in_flop_array DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in -Xtrigate_data_array data_out[0] data_out[1] DATA[0] DATA[1] tri_en tri_en_bar vdd gnd tri_gate_array +Xdata_in_flop_array data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in +Xtrigate_data_array data_out[0] data_out[1] data[0] data[1] tri_en tri_en_bar vdd gnd tri_gate_array Xaddress_decoder A[0] A[1] A[2] A[3] decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] vdd gnd hierarchical_decoder Xwordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd wordline_driver -Xaddress_flop_array ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address +Xaddress_flop_array addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address .ENDS test_bank1 -.SUBCKT testsram DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd gnd -Xbank0 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1 +.SUBCKT testsram data[0] data[1] addr[0] addr[1] addr[2] addr[3] CSb WEb OEb clk vdd gnd +Xbank0 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1 Xcontrol CSb WEb OEb s_en w_en tri_en tri_en_bar clk_bar clk vdd gnd control_logic .ENDS testsram diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.v b/compiler/tests/golden/sram_2_16_1_freepdk45.v index 025350bc..5edd2fee 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.v +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.v @@ -4,7 +4,7 @@ module sram_2_16_1_freepdk45( // Port 0: RW - clk0,csb0,web0,ADDR0,DIN0,DOUT0 + clk0,csb0,web0,addr0,din0,dout0 ); parameter DATA_WIDTH = 2 ; @@ -16,28 +16,28 @@ module sram_2_16_1_freepdk45( input clk0; // clock input csb0; // active low chip select input web0; // active low write control - input [ADDR_WIDTH-1:0] ADDR0; - input [DATA_WIDTH-1:0] DIN0; - output [DATA_WIDTH-1:0] DOUT0; + input [ADDR_WIDTH-1:0] addr0; + input [DATA_WIDTH-1:0] din0; + output [DATA_WIDTH-1:0] dout0; reg csb0_reg; reg web0_reg; - reg [ADDR_WIDTH-1:0] ADDR0_reg; - reg [DATA_WIDTH-1:0] DIN0_reg; - reg [DATA_WIDTH-1:0] DOUT0; + reg [ADDR_WIDTH-1:0] addr0_reg; + reg [DATA_WIDTH-1:0] din0_reg; + reg [DATA_WIDTH-1:0] dout0; // All inputs are registers always @(posedge clk0) begin csb0_reg = csb0; web0_reg = web0; - ADDR0_reg = ADDR0; - DIN0_reg = DIN0; - DOUT0 = 2'bx; + addr0_reg = addr0; + din0_reg = din0; + dout0 = 2'bx; if ( !csb0_reg && web0_reg ) - $display($time," Reading %m ADDR0=%b DOUT0=%b",ADDR0_reg,mem[ADDR0_reg]); + $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]); if ( !csb0_reg && !web0_reg ) - $display($time," Writing %m ADDR0=%b DIN0=%b",ADDR0_reg,DIN0_reg); + $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg); end reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; @@ -47,7 +47,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; always @ (negedge clk0) begin : MEM_WRITE0 if ( !csb0_reg && !web0_reg ) - mem[ADDR0_reg] = DIN0_reg; + mem[addr0_reg] = din0_reg; end // Memory Read Block Port 0 @@ -55,7 +55,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; always @ (negedge clk0) begin : MEM_READ0 if (!csb0_reg && web0_reg) - DOUT0 <= #(DELAY) mem[ADDR0_reg]; + dout0 <= #(DELAY) mem[addr0_reg]; end endmodule diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib index 88b54eca..a1c5a04b 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){ area : 1124.88; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000167; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 0.2091; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 0.2091; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){ direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("0.033101244168888884"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("0.033101244168888884"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib index e78fe8d3..865daada 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){ area : 1124.88; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000167; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 0.2091; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 0.2091; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){ direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("0.033101244168888884"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("0.033101244168888884"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib index 0939b4bb..72d01a0f 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){ area : 977.4951374999999; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.0011164579999999999; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 0.2091; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 0.2091; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){ direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("0.03599689694444445"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("0.029906643888888886"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib index a06ff5b5..33587063 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){ area : 977.4951374999999; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000179; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 0.2091; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 0.2091; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){ direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("0.0747594982142222"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("0.0747594982142222"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib index d7d7de7e..5817211b 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){ area : 977.4951374999999; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.0011164579999999999; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 0.2091; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 0.2091; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){ direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("0.03334771594444444"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("0.028457026222222223"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef b/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef index 9d784677..08ebcdb2 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef @@ -3,7 +3,7 @@ NAMESCASESENSITIVE ON ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS - DATABASE MICRONS 1000 ; + dataBASE MICRONS 1000 ; END UNITS SITE MacroSite CLASS Core ; @@ -14,48 +14,48 @@ MACRO sram_2_16_1_scn3me_subm SIZE 148050.0 BY 461850.0 ; SYMMETRY X Y R90 ; SITE MacroSite ; - PIN DATA[0] + PIN data[0] DIRECTION INOUT ; PORT LAYER metal2 ; RECT 120900.0 0.0 121800.0 1800.0 ; END - END DATA[0] - PIN DATA[1] + END data[0] + PIN data[1] DIRECTION INOUT ; PORT LAYER metal2 ; RECT 131100.0 0.0 132000.0 1800.0 ; END - END DATA[1] - PIN ADDR[0] + END data[1] + PIN addr[0] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 0.0 87600.0 10800.0 89100.0 ; END - END ADDR[0] - PIN ADDR[1] + END addr[0] + PIN addr[1] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 0.0 77400.0 10800.0 78900.0 ; END - END ADDR[1] - PIN ADDR[2] + END addr[1] + PIN addr[2] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 0.0 67200.0 10800.0 68700.0 ; END - END ADDR[2] - PIN ADDR[3] + END addr[2] + PIN addr[3] DIRECTION INPUT ; PORT LAYER metal3 ; RECT 0.0 57000.0 10800.0 58500.0 ; END - END ADDR[3] + END addr[3] PIN CSb DIRECTION INPUT ; PORT diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp b/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp index 258b4464..1b8d4e07 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp @@ -136,10 +136,10 @@ Xpmos1 vdd A net1 vdd nor_2_pmos125 Xpmos2 net1 B Z vdd nor_2_pmos226 .ENDS nor2 -.SUBCKT msf_control DATA[0] DATA[1] DATA[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd -XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop -XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop -XXdff2 DATA[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop +.SUBCKT msf_control data[0] data[1] data[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd +XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop +XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop +XXdff2 data[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop .ENDS msf_control *********************** "cell_6t" ****************************** @@ -541,16 +541,16 @@ XINVERTER_[14] Z[14] decode_out[14] vdd gnd INVERTER XINVERTER_[15] Z[15] decode_out[15] vdd gnd INVERTER .ENDS hierarchical_decoder -.SUBCKT msf_address ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd -XXdff0 ADDR[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop -XXdff1 ADDR[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop -XXdff2 ADDR[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop -XXdff3 ADDR[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop +.SUBCKT msf_address addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd +XXdff0 addr[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop +XXdff1 addr[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop +XXdff2 addr[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop +XXdff3 addr[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop .ENDS msf_address -.SUBCKT msf_data_in DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd -XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop -XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop +.SUBCKT msf_data_in data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd +XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop +XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop .ENDS msf_data_in .SUBCKT msf_data_out data_out[0] data_out[1] tri_in[0] tri_in_bar[0] tri_in[1] tri_in_bar[1] sclk vdd gnd @@ -571,9 +571,9 @@ M_6 in_inv in gnd gnd n W='1.2*1u' L=0.6u .ENDS -.SUBCKT tri_gate_array tri_in[0] tri_in[1] DATA[0] DATA[1] en en_bar vdd gnd -XXtri_gate0 tri_in[0] DATA[0] en en_bar vdd gnd tri_gate -XXtri_gate1 tri_in[1] DATA[1] en en_bar vdd gnd tri_gate +.SUBCKT tri_gate_array tri_in[0] tri_in[1] data[0] data[1] en en_bar vdd gnd +XXtri_gate0 tri_in[0] data[0] en en_bar vdd gnd tri_gate +XXtri_gate1 tri_in[1] data[1] en en_bar vdd gnd tri_gate .ENDS tri_gate_array .SUBCKT wordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd @@ -663,19 +663,19 @@ Xpmos1 vdd A net1 vdd nor_2_pmos197 Xpmos2 net1 B Z vdd nor_2_pmos298 .ENDS NOR2 -.SUBCKT test_bank1 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd +.SUBCKT test_bank1 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd Xbitcell_array bl[0] br[0] bl[1] br[1] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd bitcell_array Xprecharge_array bl[0] br[0] bl[1] br[1] clk_bar vdd precharge_array Xsense_amp_array bl[0] br[0] bl[1] br[1] data_out[0] data_out[1] s_en vdd gnd sense_amp_array Xwrite_driver_array data_in[0] data_in[1] bl[0] br[0] bl[1] br[1] w_en vdd gnd write_driver_array -Xdata_in_flop_array DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in -Xtrigate_data_array data_out[0] data_out[1] DATA[0] DATA[1] tri_en tri_en_bar vdd gnd tri_gate_array +Xdata_in_flop_array data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in +Xtrigate_data_array data_out[0] data_out[1] data[0] data[1] tri_en tri_en_bar vdd gnd tri_gate_array Xaddress_decoder A[0] A[1] A[2] A[3] decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] vdd gnd hierarchical_decoder Xwordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd wordline_driver -Xaddress_flop_array ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address +Xaddress_flop_array addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address .ENDS test_bank1 -.SUBCKT testsram DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd gnd -Xbank0 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1 +.SUBCKT testsram data[0] data[1] addr[0] addr[1] addr[2] addr[3] CSb WEb OEb clk vdd gnd +Xbank0 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1 Xcontrol CSb WEb OEb s_en w_en tri_en tri_en_bar clk_bar clk vdd gnd control_logic .ENDS testsram diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v index 7017b8a7..cec47c19 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v @@ -4,7 +4,7 @@ module sram_2_16_1_scn4m_subm( // Port 0: RW - clk0,csb0,web0,ADDR0,DIN0,DOUT0 + clk0,csb0,web0,addr0,din0,dout0 ); parameter DATA_WIDTH = 2 ; @@ -16,28 +16,28 @@ module sram_2_16_1_scn4m_subm( input clk0; // clock input csb0; // active low chip select input web0; // active low write control - input [ADDR_WIDTH-1:0] ADDR0; - input [DATA_WIDTH-1:0] DIN0; - output [DATA_WIDTH-1:0] DOUT0; + input [ADDR_WIDTH-1:0] addr0; + input [DATA_WIDTH-1:0] din0; + output [DATA_WIDTH-1:0] dout0; reg csb0_reg; reg web0_reg; - reg [ADDR_WIDTH-1:0] ADDR0_reg; - reg [DATA_WIDTH-1:0] DIN0_reg; - reg [DATA_WIDTH-1:0] DOUT0; + reg [ADDR_WIDTH-1:0] addr0_reg; + reg [DATA_WIDTH-1:0] din0_reg; + reg [DATA_WIDTH-1:0] dout0; // All inputs are registers always @(posedge clk0) begin csb0_reg = csb0; web0_reg = web0; - ADDR0_reg = ADDR0; - DIN0_reg = DIN0; - DOUT0 = 2'bx; + addr0_reg = addr0; + din0_reg = din0; + dout0 = 2'bx; if ( !csb0_reg && web0_reg ) - $display($time," Reading %m ADDR0=%b DOUT0=%b",ADDR0_reg,mem[ADDR0_reg]); + $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]); if ( !csb0_reg && !web0_reg ) - $display($time," Writing %m ADDR0=%b DIN0=%b",ADDR0_reg,DIN0_reg); + $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg); end reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; @@ -47,7 +47,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; always @ (negedge clk0) begin : MEM_WRITE0 if ( !csb0_reg && !web0_reg ) - mem[ADDR0_reg] = DIN0_reg; + mem[addr0_reg] = din0_reg; end // Memory Read Block Port 0 @@ -55,7 +55,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; always @ (negedge clk0) begin : MEM_READ0 if (!csb0_reg && web0_reg) - DOUT0 <= #(DELAY) mem[ADDR0_reg]; + dout0 <= #(DELAY) mem[addr0_reg]; end endmodule diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib index 5cbecd94..c370f993 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){ area : 73068.14000000001; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000167; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 9.8242; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 78.5936; min_capacitance : 2.45605; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 9.8242; max_transition : 0.4; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 9.8242; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 9.8242; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){ direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("4.99880645"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("4.99880645"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib index 3324f119..f52de676 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){ area : 73068.14000000001; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000167; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 9.8242; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 78.5936; min_capacitance : 2.45605; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 9.8242; max_transition : 0.4; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 9.8242; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 9.8242; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){ direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("4.99880645"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("4.99880645"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib index f8a337d3..7447a1e2 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){ area : 60774.3; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.0009813788999999999; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 9.8242; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 78.5936; min_capacitance : 2.45605; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 9.8242; max_transition : 0.4; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 9.8242; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 9.8242; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){ direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("9.972790277777777"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("8.899322499999998"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib index 72a106ac..4248b986 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){ area : 60774.3; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.000179; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 9.8242; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 78.5936; min_capacitance : 2.45605; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 9.8242; max_transition : 0.4; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 9.8242; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 9.8242; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){ direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("11.3049604371"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("11.3049604371"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib index 124f80ff..7b649d0d 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib @@ -1,10 +1,10 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; - voltage_unit : "1v" ; + voltage_unit : "1V" ; current_unit : "1mA" ; resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; + capacitive_load_unit(1, pF) ; leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(OC){ @@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ default_operating_conditions : OC; - type (DATA){ + type (data){ base_type : array; data_type : bit; bit_width : 2; @@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ bit_to : 1; } - type (ADDR){ + type (addr){ base_type : array; data_type : bit; bit_width : 4; @@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){ area : 60774.3; leakage_power () { - when : "CSb0"; + when : "csb0"; value : 0.0009813788999999999; } cell_leakage_power : 0; - bus(DIN0){ - bus_type : DATA; + bus(din0){ + bus_type : data; direction : input; capacitance : 9.8242; memory_write(){ - address : ADDR0; + address : addr0; clocked_on : clk0; } - pin(DIN0[1:0]){ + pin(din0[1:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){ } } } - bus(DOUT0){ - bus_type : DATA; + bus(dout0){ + bus_type : data; direction : output; max_capacitance : 78.5936; min_capacitance : 2.45605; memory_read(){ - address : ADDR0; + address : addr0; } - pin(DOUT0[1:0]){ + pin(dout0[1:0]){ timing(){ timing_sense : non_unate; related_pin : "clk0"; @@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){ } } - bus(ADDR0){ - bus_type : ADDR; + bus(addr0){ + bus_type : addr; direction : input; capacitance : 9.8242; max_transition : 0.4; - pin(ADDR0[3:0]){ + pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(CSb0){ + pin(csb0){ direction : input; capacitance : 9.8242; timing(){ @@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(WEb0){ + pin(web0){ direction : input; capacitance : 9.8242; timing(){ @@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){ direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk0 & !WEb0"; + when : "!csb0 & clk0 & !web0"; rise_power(scalar){ values("9.602821763527778"); } @@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "!CSb0 & !clk0 & WEb0"; + when : "!csb0 & !clk0 & web0"; rise_power(scalar){ values("8.647938152416664"); } @@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){ } } internal_power(){ - when : "CSb0"; + when : "csb0"; rise_power(scalar){ values("0"); } diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py index c6591cf4..e60b010d 100755 --- a/compiler/tests/regress.py +++ b/compiler/tests/regress.py @@ -1,22 +1,22 @@ #!/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. +# 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 re import unittest import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) import globals (OPTS, args) = globals.parse_args() del sys.argv[1:] -from testutils import header,openram_test +from testutils import * header(__file__, OPTS.tech_name) # get a list of all files in the tests directory diff --git a/compiler/tests/sram_1rw_1r_tb.v b/compiler/tests/sram_1rw_1r_tb.v index 9c212e0a..3a2194e1 100644 --- a/compiler/tests/sram_1rw_1r_tb.v +++ b/compiler/tests/sram_1rw_1r_tb.v @@ -19,14 +19,14 @@ module sram_1rw_1r_tb; reg csb1; wire [1:0] dout1; - sram_1rw_1r_2_16_scn4m_subm U0 (.DIN0(din0), - .DOUT0(dout0), - .ADDR0(addr0), + sram_1rw_1r_2_16_scn4m_subm U0 (.din0(din0), + .dout0(dout0), + .addr0(addr0), .csb0(csb0), .web0(web0), .clk0(clk), - .DOUT1(dout1), - .ADDR1(addr1), + .dout1(dout1), + .addr1(addr1), .csb1(csb1), .clk1(clk) ); diff --git a/compiler/tests/sram_1rw_tb.v b/compiler/tests/sram_1rw_tb.v index 31f120e8..f4f6cb33 100644 --- a/compiler/tests/sram_1rw_tb.v +++ b/compiler/tests/sram_1rw_tb.v @@ -13,9 +13,9 @@ module sram_1rw_tb; reg web0; wire [1:0] dout0; - sram_2_16_scn4m_subm U0 (.DIN0(din0), - .DOUT0(dout0), - .ADDR0(addr0), + sram_2_16_scn4m_subm U0 (.din0(din0), + .dout0(dout0), + .addr0(addr0), .csb0(csb0), .web0(web0), .clk0(clk) diff --git a/compiler/tests/sram_1rw_wmask_tb.v b/compiler/tests/sram_1rw_wmask_tb.v new file mode 100644 index 00000000..51d03d6b --- /dev/null +++ b/compiler/tests/sram_1rw_wmask_tb.v @@ -0,0 +1,110 @@ +`define assert(signal, value) \ +if (!(signal === value)) begin \ + $display("ASSERTION FAILED in %m: signal != value"); \ + $finish;\ +end + +module sram_1rw_wmask_tb; + reg clk; + + reg [3:0] addr0; + reg [1:0] din0; + reg csb0; + reg web0; + reg [1:0] wmask0; + wire [1:0] dout0; + + sram_2b_16_1rw_freepdk45 U0 (.din0(din0), + .dout0(dout0), + .addr0(addr0), + .csb0(csb0), + .web0(web0), + .wmask0(wmask0), + .clk0(clk) + ); + + + initial + begin + //$monitor("%g addr0=%b din0=%b dout0=%b", + // $time, addr0, din0, dout0); + + + clk = 1; + csb0 = 1; + web0 = 1; + wmask0 = 2'b01; + addr0 = 0; + din0 = 0; + + // write + #10 din0=2'b10; + addr0=4'h1; + web0 = 0; + csb0 = 0; + wmask0 = 2'b10; + + // read + #10 din0=2'b11; + addr0=4'h1; + web0 = 1; + csb0 = 0; + + #10 `assert(dout0, 2'b1x) + + // write another + #10 din0=2'b01; + addr0=4'hC; + web0 = 0; + csb0 = 0; + wmask0 = 2'b01; + + // read undefined + #10 din0=2'b11; + addr0=4'h0; + web0 = 1; + csb0 = 0; + wmask0 = 2'b01; + + #10 `assert(dout0, 2'bxx) + + // read defined + din0=2'b11; + addr0=4'hC; + web0 = 1; + csb0 = 0; + wmask0 = 2'b01; + + #10 `assert(dout0, 2'bx1) + + // write another + din0=2'b01; + addr0=4'h1; + web0 = 0; + csb0 = 0; + + // read defined + #10 din0=2'b11; + addr0=4'h1; + web0 = 1; + csb0 = 0; + + + #10 `assert(dout0, 2'b11) + + // read undefined + din0=2'b11; + addr0=4'h0; + web0 = 1; + csb0 = 0; + + #10 `assert(dout0, 2'bxx) + + #10 $finish; + + end + + always + #5 clk = !clk; + +endmodule \ No newline at end of file diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index dfe34361..95675c38 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -1,21 +1,22 @@ # 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. +# 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,warnings +import pdb,traceback import sys,os,glob,copy import shutil -sys.path.append(os.path.join(sys.path[0],"..")) +sys.path.append(os.getenv("OPENRAM_HOME")) from globals import OPTS import debug class openram_test(unittest.TestCase): """ Base unit test that we have some shared classes in. """ - + def local_drc_check(self, w): self.reset() @@ -30,11 +31,11 @@ class openram_test(unittest.TestCase): if OPTS.purge_temp: self.cleanup() - + def local_check(self, a, final_verification=False): self.reset() - + tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name) @@ -51,7 +52,7 @@ class openram_test(unittest.TestCase): #shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) self.fail("DRC failed: {}".format(a.name)) - + result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification) if result != 0: #zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid()) @@ -59,9 +60,22 @@ class openram_test(unittest.TestCase): #shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) self.fail("LVS mismatch: {}".format(a.name)) + # For debug... + #import pdb; pdb.set_trace() if OPTS.purge_temp: self.cleanup() - + + def run_pex(self, a, output=None): + if output == None: + output = OPTS.openram_temp + a.name + ".pex.netlist" + tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name) + + import verify + result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False) + if result != 0: + self.fail("PEX ERROR: {}".format(a.name)) + return output def find_feasible_test_period(self, delay_obj, sram, load, slew): """Creates a delay simulation to determine a feasible period for the functional tests to run. @@ -69,24 +83,21 @@ class openram_test(unittest.TestCase): """ debug.info(1, "Finding feasible period for current test.") delay_obj.set_load_slew(load, slew) - delay_obj.set_probe(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1)) test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period. - delay_obj.create_signal_names() - delay_obj.create_measurement_names() - delay_obj.create_measurement_objects() - delay_obj.find_feasible_period_one_port(test_port) - return delay_obj.period - + delay_obj.analysis_init(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1)) + delay_obj.find_feasible_period_one_port(test_port) + return delay_obj.period + def cleanup(self): """ Reset the duplicate checker and cleanup files. """ files = glob.glob(OPTS.openram_temp + '*') for f in files: # Only remove the files if os.path.isfile(f): - os.remove(f) + os.remove(f) def reset(self): - """ + """ Reset everything after each test. """ # Reset the static duplicate name checker for unit tests. @@ -115,7 +126,7 @@ class openram_test(unittest.TestCase): data_string=pprint.pformat(data) debug.error("Results exceeded {:.1f}% tolerance compared to golden results:\n".format(error_tolerance*100)+data_string) return data_matches - + def isclose(self,key,value,actual_value,error_tolerance=1e-2): @@ -131,7 +142,7 @@ class openram_test(unittest.TestCase): return False def relative_diff(self, value1, value2): - """ Compute the relative difference of two values and normalize to the largest. + """ Compute the relative difference of two values and normalize to the largest. If largest value is 0, just return the difference.""" # Edge case to avoid divide by zero @@ -147,7 +158,7 @@ class openram_test(unittest.TestCase): # Edge case where greater is a zero if norm_value == 0: min_value = abs(min(value1, value2)) - + return abs(value1 - value2) / norm_value @@ -161,15 +172,15 @@ class openram_test(unittest.TestCase): """Compare two files. Arguments: - + filename1 -- First file name - + filename2 -- Second file name Return value: - + True if the files are the same, False otherwise. - + """ import re import debug @@ -202,7 +213,7 @@ class openram_test(unittest.TestCase): debug.info(3,"line1_floats: "+str(line1_floats)) debug.info(3,"line2_floats: "+str(line2_floats)) - + # 2. Remove the floats from the string for f in line1_floats: line1=line1.replace(f,"",1) @@ -214,10 +225,10 @@ class openram_test(unittest.TestCase): # 3. Convert to floats rather than strings line1_floats = [float(x) for x in line1_floats] line2_floats = [float(x) for x in line1_floats] - + # 4. Check if remaining string matches if line1 != line2: - #Uncomment if you want to see all the individual chars of the two lines + #Uncomment if you want to see all the individual chars of the two lines #print(str([i for i in line1])) #print(str([i for i in line2])) if mismatches==0: @@ -280,12 +291,13 @@ class openram_test(unittest.TestCase): debug.info(2,"MATCH {0} {1}".format(filename1,filename2)) return True + def header(filename, technology): # Skip the header for gitlab regression import getpass if getpass.getuser() == "gitlab-runner": return - + tst = "Running Test for:" print("\n") print(" ______________________________________________________________________________ ") @@ -296,3 +308,21 @@ def header(filename, technology): from globals import OPTS print("|=========" + OPTS.openram_temp.center(60) + "=========|") print("|==============================================================================|") + +def debugTestRunner(post_mortem=None): + """unittest runner doing post mortem debugging on failing tests""" + if post_mortem is None and not OPTS.purge_temp: + post_mortem = pdb.post_mortem + class DebugTestResult(unittest.TextTestResult): + def addError(self, test, err): + # called before tearDown() + traceback.print_exception(*err) + if post_mortem: + post_mortem(err[2]) + super(DebugTestResult, self).addError(test, err) + def addFailure(self, test, err): + traceback.print_exception(*err) + if post_mortem: + post_mortem(err[2]) + super(DebugTestResult, self).addFailure(test, err) + return unittest.TextTestRunner(resultclass=DebugTestResult) diff --git a/compiler/verify/__init__.py b/compiler/verify/__init__.py index 04fa9746..042fecff 100644 --- a/compiler/verify/__init__.py +++ b/compiler/verify/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This is a module that will import the correct DRC/LVS/PEX @@ -33,9 +33,6 @@ else: OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name) OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name) -if OPTS.check_lvsdrc and OPTS.tech_name == "freepdk45": - debug.check(OPTS.drc_exe[0]!="magic","Magic does not support FreePDK45 for DRC.") - if OPTS.drc_exe == None: from .none import run_drc,print_drc_stats elif "calibre"==OPTS.drc_exe[0]: diff --git a/compiler/verify/assura.py b/compiler/verify/assura.py index f7777fdb..d1d6146f 100644 --- a/compiler/verify/assura.py +++ b/compiler/verify/assura.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This is a DRC/LVS interface for Assura. It implements completely two diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 509e05fd..8abca448 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This is a DRC/LVS interface for calibre. It implements completely @@ -93,11 +93,11 @@ def write_calibre_lvs_script(cell_name, final_verification): 'cmnFDIUseLayerMap': 1, 'cmnTranscriptFile': './lvs.log', 'cmnTranscriptEchoToFile': 1, - 'lvsRecognizeGates': 'NONE', + 'lvsRecognizeGates': 'NONE', } # FIXME: Remove when vdd/gnd connected #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee - # FIXME: Remove when vdd/gnd connected + # FIXME: Remove when vdd/gnd connected #'lvsAbortOnSupplyError' : 0 if not final_verification: @@ -106,7 +106,7 @@ def write_calibre_lvs_script(cell_name, final_verification): lvs_runset['cmnVConnectNames']='vdd gnd' else: lvs_runset['lvsAbortOnSupplyError']=1 - + # write the runset file @@ -127,20 +127,23 @@ def write_calibre_lvs_script(cell_name, final_verification): f.write("\n") f.close() os.system("chmod u+x {}".format(run_file)) - + return lvs_runset def write_calibre_pex_script(cell_name, extract, output, final_verification): - + if output == None: output = name + ".pex.netlist" # check if lvs report has been done # if not run drc and lvs if not os.path.isfile(cell_name + ".lvs.report"): + gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" + sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" run_drc(cell_name, gds_name) run_lvs(cell_name, gds_name, sp_name) + from tech import drc pex_rules = drc["xrc_rules"] pex_runset = { 'pexRulesFile': pex_rules, @@ -175,18 +178,18 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): os.system("chmod u+x {}".format(run_file)) return pex_runset - + def run_drc(cell_name, gds_name, extract=False, final_verification=False): """Run DRC check on a given top-level name which is implemented in gds_name.""" - + global num_drc_runs num_drc_runs += 1 # Copy file to local dir if it isn't already if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): shutil.copy(gds_name, OPTS.openram_temp) - + drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) (outfile, errfile, resultsfile) = run_script(cell_name, "drc") @@ -209,12 +212,12 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): # always display this summary if errors > 0: - debug.error("{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name, + debug.error("{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name, geometries, rulechecks, errors)) else: - debug.info(1, "{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name, + debug.info(1, "{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name, geometries, rulechecks, errors)) @@ -225,10 +228,10 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): """Run LVS check on a given top-level name which is implemented in gds_name and sp_name. Final verification will ensure that there are no remaining virtual conections. """ - + global num_lvs_runs num_lvs_runs += 1 - + lvs_runset = write_calibre_lvs_script(cell_name, final_verification) # Copy file to local dir if it isn't already @@ -280,7 +283,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): # MRG - 9/26/17 - Change this to exclude warnings because of # multiple labels on different pins in column mux. ext_errors = len(exterrors) - ext_warnings = len(extwarnings) + ext_warnings = len(extwarnings) # also check the output file f = open(outfile, "r") @@ -297,16 +300,16 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): total_errors = summary_errors + out_errors + ext_errors if total_errors > 0: - debug.error("{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name, + debug.error("{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name, summary_errors, out_errors, ext_errors)) else: - debug.info(1, "{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name, + debug.info(1, "{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name, summary_errors, out_errors, ext_errors)) - + return total_errors @@ -317,10 +320,10 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False) global num_pex_runs num_pex_runs += 1 - write_calibre_pex_script() + write_calibre_pex_script(cell_name,True,output,final_verification) (outfile, errfile, resultsfile) = run_script(cell_name, "pex") - + # also check the output file f = open(outfile, "r") diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 2db87ae2..63aeaabe 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -1,16 +1,16 @@ # 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. +# 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. # """ -This is a DRC/LVS/PEX interface file for magic + netgen. +This is a DRC/LVS/PEX interface file for magic + netgen. We include the tech file for SCN4M_SUBM in the tech directory, -that is included in OpenRAM during DRC. -You can use this interactively by appending the magic system path in +that is included in OpenRAM during DRC. +You can use this interactively by appending the magic system path in your .magicrc file path sys /Users/mrg/openram/technology/scn3me_subm/tech @@ -33,7 +33,7 @@ num_drc_runs = 0 num_lvs_runs = 0 num_pex_runs = 0 - + def write_magic_script(cell_name, extract=False, final_verification=False): """ Write a magic script to perform DRC and optionally extraction. """ @@ -69,7 +69,7 @@ def write_magic_script(cell_name, extract=False, final_verification=False): if final_verification: f.write(pre+"extract unique all\n".format(cell_name)) f.write(pre+"extract\n".format(cell_name)) - #f.write(pre+"ext2spice hierarchy on\n") + #f.write(pre+"ext2spice hierarchy on\n") #f.write(pre+"ext2spice scale off\n") # lvs exists in 8.2.79, but be backword compatible for now #f.write(pre+"ext2spice lvs\n") @@ -82,18 +82,18 @@ def write_magic_script(cell_name, extract=False, final_verification=False): f.write(pre+"ext2spice blackbox on\n") f.write(pre+"ext2spice subcircuit top auto\n") f.write(pre+"ext2spice global off\n") - + # Can choose hspice, ngspice, or spice3, # but they all seem compatible enough. #f.write(pre+"ext2spice format ngspice\n") f.write(pre+"ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\n") f.write("EOF\n") - + f.close() os.system("chmod u+x {}".format(run_file)) - + def write_netgen_script(cell_name): """ Write a netgen script to perform LVS. """ @@ -119,7 +119,7 @@ def write_netgen_script(cell_name): f.close() os.system("chmod u+x {}".format(run_file)) - + def run_drc(cell_name, gds_name, extract=True, final_verification=False): """Run DRC check on a cell which is implemented in gds_name.""" @@ -129,7 +129,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): # Copy file to local dir if it isn't already if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): shutil.copy(gds_name, OPTS.openram_temp) - + # Copy .magicrc file into temp dir magic_file = OPTS.openram_tech + "mag_lib/.magicrc" if os.path.exists(magic_file): @@ -151,7 +151,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): f = open(outfile, "r") except FileNotFoundError: debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile),1) - + results = f.readlines() f.close() errors=1 @@ -162,7 +162,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): break else: debug.error("Unable to find the total error line in Magic output.",1) - + # always display this summary if errors > 0: @@ -189,19 +189,19 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): shutil.copy(gds_name, OPTS.openram_temp) if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): shutil.copy(sp_name, OPTS.openram_temp) - + write_netgen_script(cell_name) (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") - + total_errors = 0 - + # check the result for these lines in the summary: try: f = open(resultsfile, "r") except FileNotFoundError: debug.error("Unable to load LVS results from {}".format(resultsfile),1) - + results = f.readlines() f.close() # Look for the results after the final "Subcircuit summary:" @@ -217,14 +217,14 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): test = re.compile("Property errors were found.") propertyerrors = list(filter(test.search, results)) total_errors += len(propertyerrors) - + # Require pins to match? # Cell pin lists for pnand2_1.spice and pnand2_1 altered to match. # test = re.compile(".*altered to match.") # pinerrors = list(filter(test.search, results)) # if len(pinerrors)>0: # debug.warning("Pins altered to match in {}.".format(cell_name)) - + #if len(propertyerrors)>0: # debug.warning("Property errors found, but not checking them.") @@ -232,7 +232,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): test = re.compile("Netlists do not match.") incorrect = list(filter(test.search, final_results)) total_errors += len(incorrect) - + # Netlists match uniquely. test = re.compile("match uniquely.") correct = list(filter(test.search, final_results)) @@ -244,7 +244,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): # Just print out the whole file, it is short. for e in results: debug.info(1,e.strip("\n")) - debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile)) + debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile)) else: debug.info(1, "{0}\tLVS matches".format(cell_name)) @@ -257,9 +257,9 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): global num_pex_runs num_pex_runs += 1 - - debug.warning("PEX using magic not implemented.") - return 1 + #debug.warning("PEX using magic not implemented.") + #return 1 + os.chdir(OPTS.openram_temp) from tech import drc if output == None: @@ -271,25 +271,67 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): run_drc(name, gds_name) run_lvs(name, gds_name, sp_name) - """ - 2. magic can perform extraction with the following: - #!/bin/sh - rm -f $1.ext - rm -f $1.spice - magic -dnull -noconsole << EOF - tech load SCN3ME_SUBM.30 - #scalegrid 1 2 - gds rescale no - gds polygon subcell true - gds warning default - gds read $1 - extract - ext2spice scale off - ext2spice - quit -noprompt - EOF - """ - + # pex_fix did run the pex using a script while dev orignial method + # use batch mode. + # the dev old code using batch mode does not run and is split into functions + #pex_runset = write_batch_pex_rule(gds_name,name,sp_name,output) + pex_runset = write_script_pex_rule(gds_name,name,output) + + errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) + outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) + + # bash mode command from dev branch + #batch_cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, + # OPTS.openram_temp, + # errfile, + # outfile) + script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, + errfile, + outfile) + cmd = script_cmd + debug.info(2, cmd) + os.system(cmd) + + # rename technology models + pex_nelist = open(output, 'r') + s = pex_nelist.read() + pex_nelist.close() + s = s.replace('pfet','p') + s = s.replace('nfet','n') + f = open(output, 'w') + f.write(s) + f.close() + + # also check the output file + f = open(outfile, "r") + results = f.readlines() + f.close() + out_errors = find_error(results) + debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.") + + correct_port(name,output,sp_name) + return out_errors + +def write_batch_pex_rule(gds_name,name,sp_name,output): + """ + The dev branch old batch mode runset + 2. magic can perform extraction with the following: + #!/bin/sh + rm -f $1.ext + rm -f $1.spice + magic -dnull -noconsole << EOF + tech load SCN3ME_SUBM.30 + #scalegrid 1 2 + gds rescale no + gds polygon subcell true + gds warning default + gds read $1 + extract + ext2spice scale off + ext2spice + quit -noprompt + EOF + """ pex_rules = drc["xrc_rules"] pex_runset = { 'pexRulesFile': pex_rules, @@ -307,42 +349,89 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): } # write the runset file - f = open(OPTS.openram_temp + "pex_runset", "w") - for k in sorted(pex_runset.iterkeys()): + file = OPTS.openram_temp + "pex_runset" + f = open(file, "w") + for k in sorted(pex_runset.keys()): f.write("*{0}: {1}\n".format(k, pex_runset[k])) f.close() + return file - # run pex - cwd = os.getcwd() - os.chdir(OPTS.openram_temp) - errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) - outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) +def write_script_pex_rule(gds_name,cell_name,output): + global OPTS + run_file = OPTS.openram_temp + "run_pex.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write("{} -dnull -noconsole << eof\n".format(OPTS.drc_exe[1])) + f.write("gds polygon subcell true\n") + f.write("gds warning default\n") + f.write("gds read {}\n".format(gds_name)) + f.write("load {}\n".format(cell_name)) + f.write("select top cell\n") + f.write("expand\n") + f.write("port makeall\n") + extract = True + if not extract: + pre = "#" + else: + pre = "" + f.write(pre+"extract\n".format(cell_name)) + #f.write(pre+"ext2spice hierarchy on\n") + #f.write(pre+"ext2spice format ngspice\n") + #f.write(pre+"ext2spice renumber off\n") + #f.write(pre+"ext2spice scale off\n") + #f.write(pre+"ext2spice blackbox on\n") + f.write(pre+"ext2spice subcircuit top on\n") + #f.write(pre+"ext2spice global off\n") + f.write(pre+"ext2spice {}\n".format(cell_name)) + f.write("quit -noprompt\n") + f.write("eof\n") + f.write("mv {0}.spice {1}\n".format(cell_name,output)) - cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, - OPTS.openram_temp, - errfile, - outfile) - debug.info(2, cmd) - os.system(cmd) - os.chdir(cwd) - - # also check the output file - f = open(outfile, "r") - results = f.readlines() f.close() + os.system("chmod u+x {}".format(run_file)) + return run_file +def find_error(results): # Errors begin with "ERROR:" test = re.compile("ERROR:") stdouterrors = list(filter(test.search, results)) for e in stdouterrors: debug.error(e.strip("\n")) - out_errors = len(stdouterrors) - - debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.") - return out_errors +def correct_port(name, output_file_name, ref_file_name): + pex_file = open(output_file_name, "r") + contents = pex_file.read() + # locate the start of circuit definition line + match = re.search(".subckt " + str(name) + ".*", contents) + match_index_start = match.start() + pex_file.seek(match_index_start) + rest_text = pex_file.read() + # locate the end of circuit definition line + match = re.search(r'\n', rest_text) + match_index_end = match.start() + # store the unchanged part of pex file in memory + pex_file.seek(0) + part1 = pex_file.read(match_index_start) + pex_file.seek(match_index_start + match_index_end) + part2 = pex_file.read() + pex_file.close() + + # obtain the correct definition line from the original spice file + sp_file = open(ref_file_name, "r") + contents = sp_file.read() + circuit_title = re.search(".SUBCKT " + str(name) + ".*\n", contents) + circuit_title = circuit_title.group() + sp_file.close() + + # write the new pex file with info in the memory + output_file = open(output_file_name, "w") + output_file.write(part1) + output_file.write(circuit_title) + output_file.write(part2) + output_file.close() + def print_drc_stats(): debug.info(1,"DRC runs: {0}".format(num_drc_runs)) def print_lvs_stats(): diff --git a/compiler/verify/none.py b/compiler/verify/none.py index 68246463..9d7ac938 100644 --- a/compiler/verify/none.py +++ b/compiler/verify/none.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ This is a DRC/LVS/PEX interface file the case with no DRC/LVS tools. diff --git a/compiler/verify/run_script.py b/compiler/verify/run_script.py index 71f55074..3bc8d2d8 100644 --- a/compiler/verify/run_script.py +++ b/compiler/verify/run_script.py @@ -1,9 +1,9 @@ # 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. +# 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. # """ Some baseline functions to run scripts. diff --git a/compiler/view_profile.py b/compiler/view_profile.py index b292dce2..cad8e9ae 100755 --- a/compiler/view_profile.py +++ b/compiler/view_profile.py @@ -1,10 +1,10 @@ #!/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. +# 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 pstats p = pstats.Stats("profile.dat") diff --git a/technology/freepdk45/__init__.py b/technology/freepdk45/__init__.py index 0ad8d108..363df6f4 100644 --- a/technology/freepdk45/__init__.py +++ b/technology/freepdk45/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/python """ diff --git a/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds b/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds new file mode 100644 index 00000000..2ac1a287 Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds differ diff --git a/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds b/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds new file mode 100644 index 00000000..fa89439e Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds differ diff --git a/technology/freepdk45/gds_lib/dummy_cell_6t.gds b/technology/freepdk45/gds_lib/dummy_cell_6t.gds new file mode 100644 index 00000000..c6575122 Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_6t.gds differ diff --git a/technology/freepdk45/gds_lib/write_driver.gds b/technology/freepdk45/gds_lib/write_driver.gds index 742e39d4..86015e7a 100644 Binary files a/technology/freepdk45/gds_lib/write_driver.gds and b/technology/freepdk45/gds_lib/write_driver.gds differ diff --git a/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp b/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp new file mode 100644 index 00000000..c3c082ee --- /dev/null +++ b/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT dummy_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1 +MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM6 RA_to_R_left wl1 bl1_noconn gnd NMOS_VTG W=180.0n L=50n m=1 +MM5 Q wl0 bl0_noconn gnd NMOS_VTG W=135.00n L=50n m=1 +MM4 Q_bar wl0 br0_noconn gnd NMOS_VTG W=135.00n L=50n m=1 +MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1 +MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1 +MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1 +MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1 +.ENDS + diff --git a/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp b/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp new file mode 100644 index 00000000..72d7553f --- /dev/null +++ b/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT dummy_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1 +MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM6 RA_to_R_left wl1 bl1_noconn gnd NMOS_VTG W=180.0n L=50n m=1 +MM5 Q wl0 bl0_noconn gnd NMOS_VTG W=135.00n L=50n m=1 +MM4 Q_bar wl0 br0_noconn gnd NMOS_VTG W=135.00n L=50n m=1 +MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1 +MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1 +MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1 +MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1 +.ENDS + diff --git a/technology/freepdk45/sp_lib/dummy_cell_6t.sp b/technology/freepdk45/sp_lib/dummy_cell_6t.sp new file mode 100644 index 00000000..ab862ec5 --- /dev/null +++ b/technology/freepdk45/sp_lib/dummy_cell_6t.sp @@ -0,0 +1,15 @@ + +.SUBCKT dummy_cell_6t bl br wl vdd gnd +* Inverter 1 +MM0 Qbar Q gnd gnd NMOS_VTG W=205.00n L=50n +MM4 Qbar Q vdd vdd PMOS_VTG W=90n L=50n + +* Inverer 2 +MM1 Q Qbar gnd gnd NMOS_VTG W=205.00n L=50n +MM5 Q Qbar vdd vdd PMOS_VTG W=90n L=50n + +* Access transistors +MM3 bl_noconn wl Q gnd NMOS_VTG W=135.00n L=50n +MM2 br_noconn wl Qbar gnd NMOS_VTG W=135.00n L=50n +.ENDS cell_6t + diff --git a/technology/freepdk45/tech/__init__.py b/technology/freepdk45/tech/__init__.py index a516facc..662a09b6 100644 --- a/technology/freepdk45/tech/__init__.py +++ b/technology/freepdk45/tech/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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 tech specific modules. diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 12c314cf..77ddda76 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -1,9 +1,9 @@ # 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. +# 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 os from design_rules import * @@ -345,26 +345,22 @@ spice["msflop_leakage"] = 1 # Leakage power of flop in nW spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF spice["default_event_rate"] = 100 # Default event activity of every gate. MHz -spice["flop_transition_prob"] = .5 # Transition probability of inverter. -spice["inv_transition_prob"] = .5 # Transition probability of inverter. -spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand. -spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand. -spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor. +spice["flop_transition_prob"] = 0.5 # Transition probability of inverter. +spice["inv_transition_prob"] = 0.5 # Transition probability of inverter. +spice["nand2_transition_prob"] = 0.1875 # Transition probability of 2-input nand. +spice["nand3_transition_prob"] = 0.1094 # Transition probability of 3-input nand. +spice["nor2_transition_prob"] = 0.1875 # Transition probability of 2-input nor. #Parameters related to sense amp enable timing and delay chain/RBL sizing parameter['le_tau'] = 2.25 #In pico-seconds. parameter['cap_relative_per_ff'] = 7.5 #Units of Relative Capacitance/ Femto-Farad -parameter["static_delay_stages"] = 4 -parameter["static_fanout_per_stage"] = 3 -parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]] parameter["dff_clk_cin"] = 30.6 #relative capacitance parameter["6tcell_wl_cin"] = 3 #relative capacitance parameter["min_inv_para_delay"] = 2.4 #Tau delay units -parameter["sa_en_pmos_size"] = .72 #micro-meters -parameter["sa_en_nmos_size"] = .27 #micro-meters -parameter["sa_inv_pmos_size"] = .54 #micro-meters -parameter["sa_inv_nmos_size"] = .27 #micro-meters -parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array +parameter["sa_en_pmos_size"] = 0.72 #micro-meters +parameter["sa_en_nmos_size"] = 0.27 #micro-meters +parameter["sa_inv_pmos_size"] = 0.54 #micro-meters +parameter["sa_inv_nmos_size"] = 0.27 #micro-meters parameter['bitcell_drain_cap'] = 0.1 #In Femto-Farad, approximation of drain capacitance ################################################### diff --git a/technology/scn3me_subm/__init__.py b/technology/scn3me_subm/__init__.py new file mode 100644 index 00000000..87b26056 --- /dev/null +++ b/technology/scn3me_subm/__init__.py @@ -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. +# +#!/usr/bin/python +""" +This type of setup script should be placed in the setup_scripts directory in the trunk +""" + +import sys +import os + +TECHNOLOGY = "scn3me_subm" + + +########################## +# CDK paths + +# os.environ["CDK_DIR"] = CDK_DIR #PDK path +# os.environ["SYSTEM_CDS_LIB_DIR"] = "{0}/cdssetup".format(CDK_DIR) +# os.environ["CDS_SITE"] = CDK_DIR +os.environ["MGC_TMPDIR"] = "/tmp" + +########################### +# OpenRAM Paths + + +try: + DRCLVS_HOME = os.path.abspath(os.environ.get("DRCLVS_HOME")) +except: + OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH")) + DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech" +os.environ["DRCLVS_HOME"] = DRCLVS_HOME + +# try: +# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR")) +# except: +OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH")) +os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY) + diff --git a/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds b/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds new file mode 100644 index 00000000..f9a19873 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds differ diff --git a/technology/scn3me_subm/gds_lib/cell_1w_1r.gds b/technology/scn3me_subm/gds_lib/cell_1w_1r.gds new file mode 100644 index 00000000..41cff8af Binary files /dev/null and b/technology/scn3me_subm/gds_lib/cell_1w_1r.gds differ diff --git a/technology/scn3me_subm/gds_lib/cell_6t.gds b/technology/scn3me_subm/gds_lib/cell_6t.gds new file mode 100644 index 00000000..673962cc Binary files /dev/null and b/technology/scn3me_subm/gds_lib/cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/dff.gds b/technology/scn3me_subm/gds_lib/dff.gds new file mode 100644 index 00000000..6d089c49 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/dff.gds differ diff --git a/technology/scn3me_subm/gds_lib/ms_flop.gds b/technology/scn3me_subm/gds_lib/ms_flop.gds new file mode 100644 index 00000000..e1c071be Binary files /dev/null and b/technology/scn3me_subm/gds_lib/ms_flop.gds differ diff --git a/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds b/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds new file mode 100644 index 00000000..90002b77 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds differ diff --git a/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds b/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds new file mode 100644 index 00000000..2adb9582 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds differ diff --git a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds new file mode 100644 index 00000000..b26d63d4 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/sense_amp.gds b/technology/scn3me_subm/gds_lib/sense_amp.gds new file mode 100644 index 00000000..11081bd3 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/sense_amp.gds differ diff --git a/technology/scn3me_subm/gds_lib/tri_gate.gds b/technology/scn3me_subm/gds_lib/tri_gate.gds new file mode 100644 index 00000000..c48fe3a1 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/tri_gate.gds differ diff --git a/technology/scn3me_subm/gds_lib/write_driver.gds b/technology/scn3me_subm/gds_lib/write_driver.gds new file mode 100644 index 00000000..0bef7b79 Binary files /dev/null and b/technology/scn3me_subm/gds_lib/write_driver.gds differ diff --git a/technology/scn3me_subm/mag_lib/.magicrc b/technology/scn3me_subm/mag_lib/.magicrc new file mode 100644 index 00000000..f52d0592 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/.magicrc @@ -0,0 +1,5 @@ +path sys +$::env(OPENRAM_TECH)/scn3me_subm/tech +tech load SCN3ME_SUBM.30 -noprompt +scalegrid 1 4 +set GND gnd +set VDD vdd diff --git a/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag b/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag new file mode 100644 index 00000000..6a6fbc86 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag @@ -0,0 +1,156 @@ +magic +tech scmos +timestamp 1558933786 +<< nwell >> +rect 0 48 54 77 +<< pwell >> +rect 0 0 54 48 +<< ntransistor >> +rect 14 34 16 38 +rect 22 30 24 38 +rect 30 30 32 38 +rect 38 34 40 38 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 56 24 59 +rect 30 56 32 59 +<< ndiffusion >> +rect 13 34 14 38 +rect 16 34 17 38 +rect 21 34 22 38 +rect 17 30 22 34 +rect 24 36 30 38 +rect 24 32 25 36 +rect 29 32 30 36 +rect 24 30 30 32 +rect 32 34 33 38 +rect 37 34 38 38 +rect 40 34 41 38 +rect 32 30 37 34 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 22 30 23 +rect 24 18 25 22 +rect 29 18 30 22 +rect 24 17 30 18 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 56 22 59 +rect 24 56 25 59 +rect 29 56 30 59 +rect 32 56 33 59 +<< ndcontact >> +rect 9 34 13 38 +rect 17 34 21 38 +rect 25 32 29 36 +rect 33 34 37 38 +rect 41 34 45 38 +rect 9 17 13 21 +rect 25 18 29 22 +rect 41 17 45 21 +<< pdcontact >> +rect 17 56 21 60 +rect 25 56 29 60 +rect 33 56 37 60 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 37 70 41 74 +<< polysilicon >> +rect 22 59 24 62 +rect 30 59 32 62 +rect 22 45 24 56 +rect 30 53 32 56 +rect 13 41 16 43 +rect 14 38 16 41 +rect 22 38 24 41 +rect 30 38 32 49 +rect 38 41 41 43 +rect 38 38 40 41 +rect 14 32 16 34 +rect 38 32 40 34 +rect 14 23 16 24 +rect 22 23 24 30 +rect 30 23 32 30 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 28 49 32 53 +rect 9 41 13 45 +rect 22 41 26 45 +rect 41 41 45 45 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 70 25 74 +rect 29 70 37 74 +rect 41 70 54 74 +rect 0 63 54 67 +rect 9 45 13 63 +rect 16 56 17 60 +rect 37 56 38 60 +rect 16 53 20 56 +rect 16 49 28 53 +rect 16 38 19 49 +rect 35 45 38 56 +rect 26 41 38 45 +rect 41 45 45 63 +rect 35 38 38 41 +rect 6 34 9 38 +rect 16 34 17 38 +rect 25 36 29 38 +rect 37 34 38 38 +rect 45 34 48 38 +rect 25 22 29 32 +rect 25 13 29 18 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 70 29 74 +rect 25 56 29 60 +rect 2 34 6 38 +rect 48 34 52 38 +rect 16 24 20 28 +rect 34 24 38 28 +rect 9 17 13 21 +rect 41 17 45 21 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 38 6 74 +rect 2 0 6 34 +rect 9 21 13 74 +rect 25 60 29 70 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 74 +rect 41 0 45 17 +rect 48 38 52 74 +rect 48 0 52 34 +<< comment >> +rect 0 0 54 72 +<< labels >> +rlabel metal1 27 4 27 4 4 wl1 +rlabel psubstratepcontact 27 11 27 11 4 gnd +rlabel metal2 4 7 4 7 4 bl0 +rlabel metal2 50 7 50 7 4 br0 +rlabel metal1 19 65 19 65 4 wl0 +rlabel metal2 11 7 11 7 4 bl1 +rlabel metal2 43 7 43 7 4 br1 +rlabel metal1 18 72 18 72 1 vdd +<< properties >> +string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/cell_1w_1r.mag b/technology/scn3me_subm/mag_lib/cell_1w_1r.mag new file mode 100644 index 00000000..6a6fbc86 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/cell_1w_1r.mag @@ -0,0 +1,156 @@ +magic +tech scmos +timestamp 1558933786 +<< nwell >> +rect 0 48 54 77 +<< pwell >> +rect 0 0 54 48 +<< ntransistor >> +rect 14 34 16 38 +rect 22 30 24 38 +rect 30 30 32 38 +rect 38 34 40 38 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 56 24 59 +rect 30 56 32 59 +<< ndiffusion >> +rect 13 34 14 38 +rect 16 34 17 38 +rect 21 34 22 38 +rect 17 30 22 34 +rect 24 36 30 38 +rect 24 32 25 36 +rect 29 32 30 36 +rect 24 30 30 32 +rect 32 34 33 38 +rect 37 34 38 38 +rect 40 34 41 38 +rect 32 30 37 34 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 22 30 23 +rect 24 18 25 22 +rect 29 18 30 22 +rect 24 17 30 18 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 56 22 59 +rect 24 56 25 59 +rect 29 56 30 59 +rect 32 56 33 59 +<< ndcontact >> +rect 9 34 13 38 +rect 17 34 21 38 +rect 25 32 29 36 +rect 33 34 37 38 +rect 41 34 45 38 +rect 9 17 13 21 +rect 25 18 29 22 +rect 41 17 45 21 +<< pdcontact >> +rect 17 56 21 60 +rect 25 56 29 60 +rect 33 56 37 60 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 37 70 41 74 +<< polysilicon >> +rect 22 59 24 62 +rect 30 59 32 62 +rect 22 45 24 56 +rect 30 53 32 56 +rect 13 41 16 43 +rect 14 38 16 41 +rect 22 38 24 41 +rect 30 38 32 49 +rect 38 41 41 43 +rect 38 38 40 41 +rect 14 32 16 34 +rect 38 32 40 34 +rect 14 23 16 24 +rect 22 23 24 30 +rect 30 23 32 30 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 28 49 32 53 +rect 9 41 13 45 +rect 22 41 26 45 +rect 41 41 45 45 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 70 25 74 +rect 29 70 37 74 +rect 41 70 54 74 +rect 0 63 54 67 +rect 9 45 13 63 +rect 16 56 17 60 +rect 37 56 38 60 +rect 16 53 20 56 +rect 16 49 28 53 +rect 16 38 19 49 +rect 35 45 38 56 +rect 26 41 38 45 +rect 41 45 45 63 +rect 35 38 38 41 +rect 6 34 9 38 +rect 16 34 17 38 +rect 25 36 29 38 +rect 37 34 38 38 +rect 45 34 48 38 +rect 25 22 29 32 +rect 25 13 29 18 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 70 29 74 +rect 25 56 29 60 +rect 2 34 6 38 +rect 48 34 52 38 +rect 16 24 20 28 +rect 34 24 38 28 +rect 9 17 13 21 +rect 41 17 45 21 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 38 6 74 +rect 2 0 6 34 +rect 9 21 13 74 +rect 25 60 29 70 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 74 +rect 41 0 45 17 +rect 48 38 52 74 +rect 48 0 52 34 +<< comment >> +rect 0 0 54 72 +<< labels >> +rlabel metal1 27 4 27 4 4 wl1 +rlabel psubstratepcontact 27 11 27 11 4 gnd +rlabel metal2 4 7 4 7 4 bl0 +rlabel metal2 50 7 50 7 4 br0 +rlabel metal1 19 65 19 65 4 wl0 +rlabel metal2 11 7 11 7 4 bl1 +rlabel metal2 43 7 43 7 4 br1 +rlabel metal1 18 72 18 72 1 vdd +<< properties >> +string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/cell_6t.mag b/technology/scn3me_subm/mag_lib/cell_6t.mag new file mode 100644 index 00000000..f2e9906a --- /dev/null +++ b/technology/scn3me_subm/mag_lib/cell_6t.mag @@ -0,0 +1,117 @@ +magic +tech scmos +timestamp 1536091415 +<< nwell >> +rect -8 29 42 51 +<< pwell >> +rect -8 -8 42 29 +<< ntransistor >> +rect 7 10 9 18 +rect 29 10 31 18 +rect 10 3 14 5 +rect 24 3 28 5 +<< ptransistor >> +rect 7 37 11 40 +rect 27 37 31 40 +<< ndiffusion >> +rect -2 16 7 18 +rect 2 12 7 16 +rect -2 10 7 12 +rect 9 14 10 18 +rect 9 10 14 14 +rect 28 14 29 18 +rect 24 10 29 14 +rect 31 16 36 18 +rect 31 12 32 16 +rect 31 10 36 12 +rect 10 5 14 10 +rect 24 5 28 10 +rect 10 2 14 3 +rect 24 2 28 3 +<< pdiffusion >> +rect 2 37 7 40 +rect 11 37 12 40 +rect 26 37 27 40 +rect 31 37 32 40 +<< ndcontact >> +rect -2 12 2 16 +rect 10 14 14 18 +rect 24 14 28 18 +rect 32 12 36 16 +rect 10 -2 14 2 +rect 24 -2 28 2 +<< pdcontact >> +rect -2 36 2 40 +rect 12 36 16 40 +rect 22 36 26 40 +rect 32 36 36 40 +<< psubstratepcontact >> +rect -2 22 2 26 +rect 32 22 36 26 +<< nsubstratencontact >> +rect 32 44 36 48 +<< polysilicon >> +rect 7 40 11 42 +rect 27 40 31 42 +rect 7 35 11 37 +rect 7 21 9 35 +rect 27 34 31 37 +rect 15 33 31 34 +rect 19 32 31 33 +rect 7 20 21 21 +rect 7 19 24 20 +rect 7 18 9 19 +rect 29 18 31 32 +rect 7 8 9 10 +rect 17 5 21 6 +rect 29 8 31 10 +rect -2 3 10 5 +rect 14 3 24 5 +rect 28 3 36 5 +<< polycontact >> +rect 15 29 19 33 +rect 21 20 25 24 +rect 17 6 21 10 +<< metal1 >> +rect -2 44 15 48 +rect 19 44 32 48 +rect -2 40 2 44 +rect 32 40 36 44 +rect 11 36 12 40 +rect 26 36 27 40 +rect -2 26 2 29 +rect -2 16 2 22 +rect 11 18 15 36 +rect 23 24 27 36 +rect 25 20 27 24 +rect 14 14 15 18 +rect 23 18 27 20 +rect 32 26 36 29 +rect 23 14 24 18 +rect 32 16 36 22 +rect -2 6 17 9 +rect 21 6 36 9 +rect -2 5 36 6 +<< m2contact >> +rect 15 44 19 48 +rect -2 29 2 33 +rect 32 29 36 33 +rect 6 -2 10 2 +rect 20 -2 24 2 +<< metal2 >> +rect -2 33 2 48 +rect -2 -2 2 29 +rect 6 2 10 48 +rect 24 -2 28 48 +rect 32 33 36 48 +rect 32 -2 36 29 +<< bb >> +rect 0 0 34 46 +<< labels >> +rlabel metal2 0 0 0 0 1 gnd +rlabel metal2 34 0 34 0 1 gnd +rlabel m2contact 17 46 17 46 5 vdd +rlabel metal2 8 43 8 43 1 bl +rlabel metal2 26 43 26 43 1 br +rlabel metal1 4 7 4 7 1 wl +<< end >> diff --git a/technology/scn3me_subm/mag_lib/convertall.sh b/technology/scn3me_subm/mag_lib/convertall.sh new file mode 100755 index 00000000..43de584f --- /dev/null +++ b/technology/scn3me_subm/mag_lib/convertall.sh @@ -0,0 +1,22 @@ +magic -dnull -noconsole << EOF +load dff +gds write dff.gds +load cell_6t +gds write cell_6t.gds +load replica_cell_6t +gds write replica_cell_6t.gds +load sense_amp +gds write sense_amp.gds +load tri_gate +gds write tri_gate.gds +load write_driver +gds write write_driver.gds +load replica_cell_1w_1r +gds write replica_cell_1w_1r +load replica_cell_1rw_1r +gds write replica_cell_1rw_1r +load cell_1rw_1r +gds write cell_1rw_1r +load cell_1w_1r +gds write cell_1w_1r +EOF diff --git a/technology/scn3me_subm/mag_lib/dff.mag b/technology/scn3me_subm/mag_lib/dff.mag new file mode 100644 index 00000000..46d22c84 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/dff.mag @@ -0,0 +1,279 @@ +magic +tech scmos +timestamp 1536089597 +<< nwell >> +rect 0 48 109 103 +<< pwell >> +rect 0 -3 109 48 +<< ntransistor >> +rect 11 6 13 26 +rect 19 6 21 16 +rect 24 6 26 16 +rect 33 6 35 16 +rect 38 6 40 16 +rect 47 6 49 16 +rect 63 6 65 16 +rect 68 6 70 16 +rect 78 6 80 16 +rect 83 6 85 16 +rect 91 6 93 26 +<< ptransistor >> +rect 11 54 13 94 +rect 19 74 21 94 +rect 25 74 27 94 +rect 33 74 35 94 +rect 39 74 41 94 +rect 47 74 49 94 +rect 63 74 65 94 +rect 68 74 70 94 +rect 78 84 80 94 +rect 83 84 85 94 +rect 91 54 93 94 +<< ndiffusion >> +rect 6 25 11 26 +rect 10 6 11 25 +rect 13 25 18 26 +rect 13 6 14 25 +rect 86 25 91 26 +rect 18 6 19 16 +rect 21 6 24 16 +rect 26 15 33 16 +rect 26 6 28 15 +rect 32 6 33 15 +rect 35 6 38 16 +rect 40 15 47 16 +rect 40 6 41 15 +rect 45 6 47 15 +rect 49 15 54 16 +rect 49 6 50 15 +rect 58 15 63 16 +rect 62 6 63 15 +rect 65 6 68 16 +rect 70 15 78 16 +rect 70 6 72 15 +rect 76 6 78 15 +rect 80 6 83 16 +rect 85 6 86 16 +rect 90 6 91 25 +rect 93 25 98 26 +rect 93 6 94 25 +<< pdiffusion >> +rect 6 93 11 94 +rect 10 54 11 93 +rect 13 55 14 94 +rect 18 74 19 94 +rect 21 74 25 94 +rect 27 93 33 94 +rect 27 74 28 93 +rect 32 74 33 93 +rect 35 74 39 94 +rect 41 93 47 94 +rect 41 74 42 93 +rect 46 74 47 93 +rect 49 93 54 94 +rect 49 74 50 93 +rect 58 93 63 94 +rect 62 74 63 93 +rect 65 74 68 94 +rect 70 93 78 94 +rect 70 74 72 93 +rect 76 84 78 93 +rect 80 84 83 94 +rect 85 93 91 94 +rect 85 84 86 93 +rect 76 74 77 84 +rect 13 54 18 55 +rect 90 54 91 93 +rect 93 93 98 94 +rect 93 54 94 93 +<< ndcontact >> +rect 6 6 10 25 +rect 14 6 18 25 +rect 28 6 32 15 +rect 41 6 45 15 +rect 50 6 54 15 +rect 58 6 62 15 +rect 72 6 76 15 +rect 86 6 90 25 +rect 94 6 98 25 +<< pdcontact >> +rect 6 54 10 93 +rect 14 55 18 94 +rect 28 74 32 93 +rect 42 74 46 93 +rect 50 74 54 93 +rect 58 74 62 93 +rect 72 74 76 93 +rect 86 54 90 93 +rect 94 54 98 93 +<< psubstratepcontact >> +rect 102 6 106 10 +<< nsubstratencontact >> +rect 102 89 106 93 +<< polysilicon >> +rect 11 94 13 96 +rect 19 94 21 96 +rect 25 94 27 96 +rect 33 94 35 96 +rect 39 94 41 96 +rect 47 94 49 96 +rect 63 94 65 96 +rect 68 94 70 96 +rect 78 94 80 96 +rect 83 94 85 96 +rect 91 94 93 96 +rect 11 37 13 54 +rect 19 46 21 74 +rect 11 26 13 33 +rect 19 16 21 42 +rect 25 38 27 74 +rect 33 54 35 74 +rect 33 29 35 50 +rect 24 27 35 29 +rect 39 71 41 74 +rect 24 16 26 27 +rect 39 23 41 67 +rect 47 61 49 74 +rect 63 73 65 74 +rect 54 71 65 73 +rect 34 19 35 23 +rect 33 16 35 19 +rect 38 19 39 23 +rect 38 16 40 19 +rect 47 16 49 57 +rect 53 19 55 67 +rect 68 63 70 74 +rect 78 67 80 84 +rect 76 65 80 67 +rect 63 61 70 63 +rect 61 24 63 33 +rect 68 31 70 61 +rect 83 53 85 84 +rect 79 51 85 53 +rect 78 31 80 47 +rect 91 45 93 54 +rect 89 41 93 45 +rect 68 29 75 31 +rect 61 22 70 24 +rect 53 17 65 19 +rect 63 16 65 17 +rect 68 16 70 22 +rect 73 19 75 29 +rect 78 27 79 31 +rect 73 17 80 19 +rect 78 16 80 17 +rect 83 16 85 31 +rect 91 26 93 41 +rect 11 4 13 6 +rect 19 4 21 6 +rect 24 4 26 6 +rect 33 4 35 6 +rect 38 4 40 6 +rect 47 4 49 6 +rect 63 4 65 6 +rect 68 4 70 6 +rect 78 4 80 6 +rect 83 4 85 6 +rect 91 4 93 6 +<< polycontact >> +rect 17 42 21 46 +rect 10 33 14 37 +rect 31 50 35 54 +rect 25 34 29 38 +rect 39 67 43 71 +rect 45 57 49 61 +rect 30 19 34 23 +rect 39 19 43 23 +rect 53 67 57 71 +rect 59 59 63 63 +rect 74 61 78 65 +rect 59 33 63 37 +rect 77 47 81 51 +rect 85 41 89 45 +rect 79 27 83 31 +<< metal1 >> +rect 0 97 109 103 +rect 14 94 18 97 +rect 6 93 10 94 +rect 28 93 32 94 +rect 22 74 28 77 +rect 42 93 46 97 +rect 50 93 54 94 +rect 58 93 62 97 +rect 71 93 77 94 +rect 71 74 72 93 +rect 76 74 77 93 +rect 86 93 90 97 +rect 50 71 53 74 +rect 43 68 53 71 +rect 26 57 45 60 +rect 52 60 59 63 +rect 52 54 55 60 +rect 71 56 74 65 +rect 10 50 31 52 +rect 35 51 55 54 +rect 62 53 74 56 +rect 94 93 98 94 +rect 102 93 106 97 +rect 6 49 34 50 +rect 21 43 38 46 +rect 18 34 25 37 +rect 62 37 65 53 +rect 94 51 98 54 +rect 81 48 94 51 +rect 74 41 85 44 +rect 29 34 59 37 +rect 6 25 10 26 +rect 14 25 18 26 +rect 31 23 34 34 +rect 63 34 65 37 +rect 94 31 98 47 +rect 83 28 98 31 +rect 94 25 98 28 +rect 43 19 53 22 +rect 50 16 53 19 +rect 22 15 32 16 +rect 22 13 28 15 +rect 41 15 46 16 +rect 45 6 46 15 +rect 50 15 54 16 +rect 58 15 62 16 +rect 70 15 77 16 +rect 70 13 72 15 +rect 71 6 72 13 +rect 76 6 77 15 +rect 14 3 18 6 +rect 41 3 46 6 +rect 58 3 62 6 +rect 86 3 90 6 +rect 102 3 106 6 +rect 0 -3 109 3 +<< m2contact >> +rect 22 70 26 74 +rect 70 70 74 74 +rect 22 57 26 61 +rect 6 50 10 54 +rect 38 43 42 47 +rect 14 33 18 37 +rect 94 47 98 51 +rect 70 40 74 44 +rect 6 26 10 30 +rect 22 16 26 20 +rect 70 16 74 20 +<< metal2 >> +rect 22 61 26 70 +rect 6 30 10 50 +rect 22 20 26 57 +rect 70 44 74 70 +rect 70 20 74 40 +<< bb >> +rect 0 0 109 100 +<< labels >> +rlabel m2contact 15 34 15 34 4 clk +rlabel m2contact 40 45 40 45 4 D +rlabel m2contact 96 49 96 49 4 Q +rlabel metal1 32 98 32 98 4 vdd +rlabel metal1 44 1 44 1 4 gnd +<< properties >> +string path 0.000 0.000 900.000 0.000 900.000 900.000 0.000 900.000 0.000 0.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/ms_flop.mag b/technology/scn3me_subm/mag_lib/ms_flop.mag new file mode 100644 index 00000000..713d264f --- /dev/null +++ b/technology/scn3me_subm/mag_lib/ms_flop.mag @@ -0,0 +1,294 @@ +magic +tech scmos +timestamp 1536089622 +<< nwell >> +rect -2 0 18 200 +<< pwell >> +rect 18 0 40 200 +<< ntransistor >> +rect 24 178 27 180 +rect 24 162 27 164 +rect 24 138 27 140 +rect 24 130 27 132 +rect 24 112 27 114 +rect 24 93 27 95 +rect 24 77 27 79 +rect 24 50 27 52 +rect 24 42 27 44 +rect 24 24 27 26 +<< ptransistor >> +rect 6 178 12 180 +rect 6 162 12 164 +rect 6 138 12 140 +rect 6 130 12 132 +rect 6 112 12 114 +rect 6 93 12 95 +rect 6 77 12 79 +rect 6 50 12 52 +rect 6 42 12 44 +rect 6 24 12 26 +<< ndiffusion >> +rect 24 180 27 181 +rect 24 177 27 178 +rect 24 164 27 165 +rect 24 161 27 162 +rect 28 157 32 161 +rect 24 140 27 141 +rect 24 137 27 138 +rect 24 132 27 133 +rect 24 129 27 130 +rect 24 114 27 115 +rect 24 111 27 112 +rect 24 95 27 96 +rect 24 92 27 93 +rect 24 79 27 80 +rect 24 76 27 77 +rect 28 72 32 76 +rect 24 52 27 53 +rect 24 49 27 50 +rect 24 44 27 45 +rect 24 41 27 42 +rect 24 26 27 27 +rect 24 23 27 24 +<< pdiffusion >> +rect 6 180 12 181 +rect 6 177 12 178 +rect 6 164 12 165 +rect 6 161 12 162 +rect 6 140 12 141 +rect 6 137 12 138 +rect 6 132 12 133 +rect 6 129 12 130 +rect 6 114 12 115 +rect 6 111 12 112 +rect 6 95 12 96 +rect 6 92 12 93 +rect 6 79 12 80 +rect 6 76 12 77 +rect 6 52 12 53 +rect 6 49 12 50 +rect 6 44 12 45 +rect 6 41 12 42 +rect 6 26 12 27 +rect 6 23 12 24 +rect 8 18 12 19 +<< ndcontact >> +rect 24 181 28 185 +rect 24 173 28 177 +rect 24 165 28 169 +rect 24 157 28 161 +rect 24 141 28 145 +rect 24 133 28 137 +rect 24 125 28 129 +rect 24 115 28 119 +rect 24 107 28 111 +rect 24 96 28 100 +rect 24 88 28 92 +rect 24 80 28 84 +rect 24 72 28 76 +rect 24 53 28 57 +rect 24 45 28 49 +rect 24 37 28 41 +rect 24 27 28 31 +rect 24 19 28 23 +<< pdcontact >> +rect 6 181 12 185 +rect 6 173 12 177 +rect 6 165 12 169 +rect 6 157 12 161 +rect 6 141 12 145 +rect 6 133 12 137 +rect 6 125 12 129 +rect 6 115 12 119 +rect 6 107 12 111 +rect 6 96 12 100 +rect 6 88 12 92 +rect 6 80 12 84 +rect 6 72 12 76 +rect 6 53 12 57 +rect 6 45 12 49 +rect 6 37 12 41 +rect 6 27 12 31 +rect 6 19 12 23 +<< psubstratepcontact >> +rect 32 157 36 161 +rect 32 72 36 76 +<< nsubstratencontact >> +rect 8 14 12 18 +<< polysilicon >> +rect 4 178 6 180 +rect 12 178 24 180 +rect 27 178 29 180 +rect 17 173 19 178 +rect 4 162 6 164 +rect 12 163 24 164 +rect 12 162 17 163 +rect 21 162 24 163 +rect 27 162 29 164 +rect 3 148 13 150 +rect 3 140 5 148 +rect 3 138 6 140 +rect 12 138 14 140 +rect 17 138 24 140 +rect 27 138 29 140 +rect 17 132 19 138 +rect 3 130 6 132 +rect 12 130 19 132 +rect 22 130 24 132 +rect 27 130 31 132 +rect 3 114 5 130 +rect 29 122 31 130 +rect 20 120 31 122 +rect 3 112 6 114 +rect 12 112 24 114 +rect 27 112 29 114 +rect 4 93 6 95 +rect 12 93 24 95 +rect 27 93 29 95 +rect 19 89 21 93 +rect 4 77 6 79 +rect 12 78 24 79 +rect 12 77 17 78 +rect 21 77 24 78 +rect 27 77 29 79 +rect 3 60 13 62 +rect 3 52 5 60 +rect 3 50 6 52 +rect 12 50 14 52 +rect 17 50 24 52 +rect 27 50 29 52 +rect 17 44 19 50 +rect 3 42 6 44 +rect 12 42 19 44 +rect 22 42 24 44 +rect 27 42 31 44 +rect 3 26 5 42 +rect 29 34 31 42 +rect 20 32 31 34 +rect 3 24 6 26 +rect 12 24 24 26 +rect 27 24 29 26 +rect 16 14 18 24 +<< polycontact >> +rect 16 169 20 173 +rect 17 159 21 163 +rect 13 148 17 152 +rect 16 118 20 122 +rect 15 108 19 112 +rect 17 85 21 89 +rect 17 74 21 78 +rect 13 60 17 64 +rect 16 30 20 34 +rect 15 10 19 14 +<< metal1 >> +rect 16 182 24 185 +rect -2 173 6 177 +rect 28 173 36 177 +rect -2 164 2 173 +rect 12 166 20 169 +rect 2 160 6 161 +rect -2 157 6 160 +rect 33 161 36 173 +rect -2 111 2 157 +rect 28 157 32 161 +rect 12 142 24 145 +rect 12 134 20 137 +rect 12 126 20 129 +rect 20 118 24 119 +rect 16 116 24 118 +rect -2 107 6 111 +rect 33 111 36 153 +rect -2 92 2 107 +rect 28 107 36 111 +rect 12 97 24 100 +rect 33 92 36 107 +rect -2 88 6 92 +rect -2 76 2 88 +rect 28 88 36 92 +rect 6 84 20 85 +rect 12 82 20 84 +rect -2 72 6 76 +rect 33 76 36 88 +rect -2 41 2 72 +rect 28 72 32 76 +rect 12 54 24 57 +rect 12 46 20 49 +rect 12 38 20 41 +rect -2 22 2 37 +rect 20 30 24 31 +rect 16 28 24 30 +rect 33 23 36 68 +rect -2 19 6 22 +rect 28 20 36 23 +rect 8 18 12 19 +rect -2 10 15 11 +rect 19 10 36 11 +rect -2 8 36 10 +<< m2contact >> +rect 12 181 16 185 +rect 20 166 24 170 +rect -2 160 2 164 +rect 17 155 21 159 +rect 32 153 36 157 +rect 6 145 10 149 +rect 17 148 21 152 +rect 20 133 24 137 +rect 20 125 24 129 +rect 12 115 16 119 +rect 15 104 19 108 +rect 6 100 10 104 +rect 20 81 24 85 +rect 17 70 21 74 +rect 32 68 36 72 +rect 6 57 10 61 +rect 17 60 21 64 +rect 20 45 24 49 +rect -2 37 2 41 +rect 20 37 24 41 +rect 12 27 16 31 +<< metal2 >> +rect 6 185 10 200 +rect 15 196 19 200 +rect 15 192 24 196 +rect 6 181 12 185 +rect 6 149 9 181 +rect 20 170 24 192 +rect 21 155 27 159 +rect 18 143 21 148 +rect 13 140 21 143 +rect 13 119 16 140 +rect 24 133 27 155 +rect 5 100 6 104 +rect 5 61 8 100 +rect 15 93 19 104 +rect 11 90 19 93 +rect 11 67 14 90 +rect 24 81 27 129 +rect 21 70 27 74 +rect 11 64 16 67 +rect 5 57 6 61 +rect 13 60 17 64 +rect 13 31 16 60 +rect 24 45 27 70 +rect 24 8 27 41 +rect 19 4 27 8 +rect 15 0 19 4 +<< m3contact >> +rect 15 4 19 8 +<< metal3 >> +rect 14 8 20 9 +rect 14 4 15 8 +rect 19 4 20 8 +rect 14 3 20 4 +<< bb >> +rect 0 0 34 200 +<< labels >> +rlabel metal1 0 8 0 8 2 clk +rlabel metal3 15 4 15 4 1 din +rlabel metal2 6 196 6 196 5 dout_bar +rlabel metal2 15 196 15 196 5 dout +rlabel m2contact 34 70 34 70 1 gnd +rlabel m2contact 34 154 34 154 1 gnd +rlabel m2contact 0 162 0 162 3 vdd +rlabel m2contact 0 38 0 38 3 vdd +<< end >> diff --git a/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag b/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag new file mode 100644 index 00000000..a7387b7e --- /dev/null +++ b/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag @@ -0,0 +1,157 @@ +magic +tech scmos +timestamp 1558933826 +<< nwell >> +rect 0 48 54 77 +<< pwell >> +rect 0 0 54 48 +<< ntransistor >> +rect 14 34 16 38 +rect 22 30 24 38 +rect 30 30 32 38 +rect 38 34 40 38 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 56 24 59 +rect 30 56 32 59 +<< ndiffusion >> +rect 13 34 14 38 +rect 16 34 17 38 +rect 21 34 22 38 +rect 17 30 22 34 +rect 24 36 30 38 +rect 24 32 25 36 +rect 29 32 30 36 +rect 24 30 30 32 +rect 32 34 33 38 +rect 37 34 38 38 +rect 40 34 41 38 +rect 32 30 37 34 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 22 30 23 +rect 24 18 25 22 +rect 29 18 30 22 +rect 24 17 30 18 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 56 22 59 +rect 24 56 25 59 +rect 29 56 30 59 +rect 32 56 33 59 +<< ndcontact >> +rect 9 34 13 38 +rect 17 34 21 38 +rect 25 32 29 36 +rect 33 34 37 38 +rect 41 34 45 38 +rect 9 17 13 21 +rect 25 18 29 22 +rect 41 17 45 21 +<< pdcontact >> +rect 17 56 21 60 +rect 25 56 29 60 +rect 33 56 37 60 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 37 70 41 74 +<< polysilicon >> +rect 22 59 24 62 +rect 30 59 32 62 +rect 22 45 24 56 +rect 30 53 32 56 +rect 13 41 16 43 +rect 14 38 16 41 +rect 22 38 24 41 +rect 30 38 32 49 +rect 38 41 41 43 +rect 38 38 40 41 +rect 14 32 16 34 +rect 38 32 40 34 +rect 14 23 16 24 +rect 22 23 24 30 +rect 30 23 32 30 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 28 49 32 53 +rect 9 41 13 45 +rect 22 41 26 45 +rect 41 41 45 45 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 70 25 74 +rect 29 70 37 74 +rect 41 70 54 74 +rect 0 63 54 67 +rect 9 45 13 63 +rect 16 56 17 60 +rect 29 56 33 60 +rect 37 56 38 60 +rect 16 53 20 56 +rect 16 49 28 53 +rect 16 38 19 49 +rect 35 45 38 56 +rect 26 41 38 45 +rect 41 45 45 63 +rect 35 38 38 41 +rect 6 34 9 38 +rect 16 34 17 38 +rect 25 36 29 38 +rect 37 34 38 38 +rect 45 34 48 38 +rect 25 22 29 32 +rect 25 13 29 18 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 70 29 74 +rect 25 56 29 60 +rect 2 34 6 38 +rect 48 34 52 38 +rect 16 24 20 28 +rect 34 24 38 28 +rect 9 17 13 21 +rect 41 17 45 21 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 38 6 74 +rect 2 0 6 34 +rect 9 21 13 74 +rect 25 60 29 70 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 74 +rect 41 0 45 17 +rect 48 38 52 74 +rect 48 0 52 34 +<< comment >> +rect 0 0 54 72 +<< labels >> +rlabel metal1 27 4 27 4 4 wl1 +rlabel psubstratepcontact 27 11 27 11 4 gnd +rlabel metal2 4 7 4 7 4 bl0 +rlabel metal2 50 7 50 7 4 br0 +rlabel metal1 19 65 19 65 4 wl0 +rlabel metal2 11 7 11 7 4 bl1 +rlabel metal2 43 7 43 7 4 br1 +rlabel metal1 18 72 18 72 1 vdd +<< properties >> +string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag b/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag new file mode 100644 index 00000000..a7387b7e --- /dev/null +++ b/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag @@ -0,0 +1,157 @@ +magic +tech scmos +timestamp 1558933826 +<< nwell >> +rect 0 48 54 77 +<< pwell >> +rect 0 0 54 48 +<< ntransistor >> +rect 14 34 16 38 +rect 22 30 24 38 +rect 30 30 32 38 +rect 38 34 40 38 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 56 24 59 +rect 30 56 32 59 +<< ndiffusion >> +rect 13 34 14 38 +rect 16 34 17 38 +rect 21 34 22 38 +rect 17 30 22 34 +rect 24 36 30 38 +rect 24 32 25 36 +rect 29 32 30 36 +rect 24 30 30 32 +rect 32 34 33 38 +rect 37 34 38 38 +rect 40 34 41 38 +rect 32 30 37 34 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 22 30 23 +rect 24 18 25 22 +rect 29 18 30 22 +rect 24 17 30 18 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 56 22 59 +rect 24 56 25 59 +rect 29 56 30 59 +rect 32 56 33 59 +<< ndcontact >> +rect 9 34 13 38 +rect 17 34 21 38 +rect 25 32 29 36 +rect 33 34 37 38 +rect 41 34 45 38 +rect 9 17 13 21 +rect 25 18 29 22 +rect 41 17 45 21 +<< pdcontact >> +rect 17 56 21 60 +rect 25 56 29 60 +rect 33 56 37 60 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 37 70 41 74 +<< polysilicon >> +rect 22 59 24 62 +rect 30 59 32 62 +rect 22 45 24 56 +rect 30 53 32 56 +rect 13 41 16 43 +rect 14 38 16 41 +rect 22 38 24 41 +rect 30 38 32 49 +rect 38 41 41 43 +rect 38 38 40 41 +rect 14 32 16 34 +rect 38 32 40 34 +rect 14 23 16 24 +rect 22 23 24 30 +rect 30 23 32 30 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 28 49 32 53 +rect 9 41 13 45 +rect 22 41 26 45 +rect 41 41 45 45 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 70 25 74 +rect 29 70 37 74 +rect 41 70 54 74 +rect 0 63 54 67 +rect 9 45 13 63 +rect 16 56 17 60 +rect 29 56 33 60 +rect 37 56 38 60 +rect 16 53 20 56 +rect 16 49 28 53 +rect 16 38 19 49 +rect 35 45 38 56 +rect 26 41 38 45 +rect 41 45 45 63 +rect 35 38 38 41 +rect 6 34 9 38 +rect 16 34 17 38 +rect 25 36 29 38 +rect 37 34 38 38 +rect 45 34 48 38 +rect 25 22 29 32 +rect 25 13 29 18 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 70 29 74 +rect 25 56 29 60 +rect 2 34 6 38 +rect 48 34 52 38 +rect 16 24 20 28 +rect 34 24 38 28 +rect 9 17 13 21 +rect 41 17 45 21 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 38 6 74 +rect 2 0 6 34 +rect 9 21 13 74 +rect 25 60 29 70 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 74 +rect 41 0 45 17 +rect 48 38 52 74 +rect 48 0 52 34 +<< comment >> +rect 0 0 54 72 +<< labels >> +rlabel metal1 27 4 27 4 4 wl1 +rlabel psubstratepcontact 27 11 27 11 4 gnd +rlabel metal2 4 7 4 7 4 bl0 +rlabel metal2 50 7 50 7 4 br0 +rlabel metal1 19 65 19 65 4 wl0 +rlabel metal2 11 7 11 7 4 bl1 +rlabel metal2 43 7 43 7 4 br1 +rlabel metal1 18 72 18 72 1 vdd +<< properties >> +string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/replica_cell_6t.mag b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag new file mode 100644 index 00000000..d0dc472f --- /dev/null +++ b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag @@ -0,0 +1,118 @@ +magic +tech scmos +timestamp 1536091380 +<< nwell >> +rect -8 29 42 51 +<< pwell >> +rect -8 -8 42 29 +<< ntransistor >> +rect 7 10 9 18 +rect 29 10 31 18 +rect 10 3 14 5 +rect 24 3 28 5 +<< ptransistor >> +rect 7 37 11 40 +rect 27 37 31 40 +<< ndiffusion >> +rect -2 16 7 18 +rect 2 12 7 16 +rect -2 10 7 12 +rect 9 14 10 18 +rect 9 10 14 14 +rect 28 14 29 18 +rect 24 10 29 14 +rect 31 16 36 18 +rect 31 12 32 16 +rect 31 10 36 12 +rect 10 5 14 10 +rect 24 5 28 10 +rect 10 2 14 3 +rect 24 2 28 3 +<< pdiffusion >> +rect 2 37 7 40 +rect 11 37 12 40 +rect 26 37 27 40 +rect 31 37 32 40 +<< ndcontact >> +rect -2 12 2 16 +rect 10 14 14 18 +rect 24 14 28 18 +rect 32 12 36 16 +rect 10 -2 14 2 +rect 24 -2 28 2 +<< pdcontact >> +rect -2 36 2 40 +rect 12 36 16 40 +rect 22 36 26 40 +rect 32 36 36 40 +<< psubstratepcontact >> +rect -2 22 2 26 +rect 32 22 36 26 +<< nsubstratencontact >> +rect 32 44 36 48 +<< polysilicon >> +rect 7 40 11 42 +rect 27 40 31 42 +rect 7 35 11 37 +rect 7 21 9 35 +rect 27 34 31 37 +rect 15 33 31 34 +rect 19 32 31 33 +rect 7 20 21 21 +rect 7 19 24 20 +rect 7 18 9 19 +rect 29 18 31 32 +rect 7 8 9 10 +rect 17 5 21 6 +rect 29 8 31 10 +rect -2 3 10 5 +rect 14 3 24 5 +rect 28 3 36 5 +<< polycontact >> +rect 15 29 19 33 +rect 21 20 25 24 +rect 17 6 21 10 +<< metal1 >> +rect -2 44 15 48 +rect 19 44 32 48 +rect -2 40 2 44 +rect 32 40 36 44 +rect 11 36 12 40 +rect 26 36 27 40 +rect -2 26 2 29 +rect 11 22 15 36 +rect 23 24 27 36 +rect -2 18 15 22 +rect 25 20 27 24 +rect -2 16 2 18 +rect 14 14 15 18 +rect 23 18 27 20 +rect 32 26 36 29 +rect 23 14 24 18 +rect 32 16 36 22 +rect -2 6 17 9 +rect 21 6 36 9 +rect -2 5 36 6 +<< m2contact >> +rect 15 44 19 48 +rect -2 29 2 33 +rect 32 29 36 33 +rect 6 -2 10 2 +rect 20 -2 24 2 +<< metal2 >> +rect -2 33 2 48 +rect -2 -2 2 29 +rect 6 2 10 48 +rect 24 -2 28 48 +rect 32 33 36 48 +rect 32 -2 36 29 +<< bb >> +rect 0 0 34 46 +<< labels >> +rlabel metal2 0 0 0 0 1 gnd +rlabel metal2 34 0 34 0 1 gnd +rlabel m2contact 17 46 17 46 5 vdd +rlabel metal2 8 43 8 43 1 bl +rlabel metal2 26 43 26 43 1 br +rlabel metal1 4 7 4 7 1 wl +<< end >> diff --git a/technology/scn3me_subm/mag_lib/sense_amp.mag b/technology/scn3me_subm/mag_lib/sense_amp.mag new file mode 100644 index 00000000..e5fa4373 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/sense_amp.mag @@ -0,0 +1,136 @@ +magic +tech scmos +timestamp 1536089670 +<< nwell >> +rect 0 0 40 102 +<< pwell >> +rect 0 102 40 163 +<< ntransistor >> +rect 21 130 23 139 +rect 12 108 14 117 +rect 20 108 22 117 +<< ptransistor >> +rect 12 78 14 96 +rect 20 78 22 96 +rect 11 20 13 44 +rect 27 20 29 44 +<< ndiffusion >> +rect 20 130 21 139 +rect 23 130 24 139 +rect 11 108 12 117 +rect 14 108 15 117 +rect 19 108 20 117 +rect 22 108 23 117 +<< pdiffusion >> +rect 7 94 12 96 +rect 11 80 12 94 +rect 7 78 12 80 +rect 14 94 20 96 +rect 14 80 15 94 +rect 19 80 20 94 +rect 14 78 20 80 +rect 22 94 27 96 +rect 22 80 23 94 +rect 22 78 27 80 +rect 10 20 11 44 +rect 13 20 14 44 +rect 26 20 27 44 +rect 29 20 30 44 +<< ndcontact >> +rect 16 130 20 139 +rect 24 130 28 139 +rect 7 108 11 117 +rect 15 108 19 117 +rect 23 108 27 117 +<< pdcontact >> +rect 7 80 11 94 +rect 15 80 19 94 +rect 23 80 27 94 +rect 6 20 10 44 +rect 14 20 18 44 +rect 22 20 26 44 +rect 30 20 34 44 +<< psubstratepcontact >> +rect 32 137 36 141 +<< nsubstratencontact >> +rect 27 70 31 74 +<< polysilicon >> +rect 21 139 23 149 +rect 21 129 23 130 +rect 3 127 23 129 +rect 3 47 5 127 +rect 12 122 34 124 +rect 12 117 14 122 +rect 20 117 22 119 +rect 12 96 14 108 +rect 20 96 22 108 +rect 32 105 34 122 +rect 30 101 34 105 +rect 12 76 14 78 +rect 20 69 22 78 +rect 13 67 22 69 +rect 9 55 11 65 +rect 32 55 34 101 +rect 33 51 34 55 +rect 3 45 13 47 +rect 11 44 13 45 +rect 27 44 29 46 +rect 11 19 13 20 +rect 27 19 29 20 +rect 11 17 29 19 +<< polycontact >> +rect 20 149 24 153 +rect 26 101 30 105 +rect 9 65 13 69 +rect 9 51 13 55 +rect 29 51 33 55 +<< metal1 >> +rect -2 149 20 153 +rect 24 149 36 153 +rect 28 133 32 137 +rect 16 117 19 130 +rect 7 94 11 108 +rect 23 105 27 108 +rect 23 101 26 105 +rect 7 69 11 80 +rect 15 94 19 96 +rect 15 78 19 80 +rect 23 94 27 101 +rect 23 78 27 80 +rect 15 75 18 78 +rect 15 74 31 75 +rect 15 72 27 74 +rect 7 65 9 69 +rect 6 44 9 54 +rect 33 51 34 55 +rect 31 44 34 51 +rect 3 20 6 23 +rect 3 15 7 20 +<< m2contact >> +rect 32 133 36 137 +rect 27 66 31 70 +rect 13 44 17 48 +rect 22 44 26 48 +rect 3 11 7 15 +<< metal2 >> +rect 10 48 14 163 +rect 20 48 24 163 +rect 32 129 36 133 +rect 27 62 31 66 +rect 10 44 13 48 +rect 20 44 22 48 +rect 3 0 7 11 +rect 10 0 14 44 +rect 20 0 24 44 +<< bb >> +rect 0 0 34 163 +<< labels >> +flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en +rlabel metal2 34 131 34 131 1 gnd +rlabel metal2 29 64 29 64 1 vdd +rlabel metal2 12 161 12 161 5 bl +rlabel metal2 22 161 22 161 5 br +rlabel metal2 5 3 5 3 1 dout +<< properties >> +string path 270.000 468.000 270.000 486.000 288.000 486.000 288.000 468.000 270.000 468.000 +<< end >> diff --git a/technology/scn3me_subm/mag_lib/setup.tcl b/technology/scn3me_subm/mag_lib/setup.tcl new file mode 100644 index 00000000..01639fe2 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/setup.tcl @@ -0,0 +1,17 @@ +# Setup file for netgen +ignore class c +equate class {-circuit1 nfet} {-circuit2 n} +equate class {-circuit1 pfet} {-circuit2 p} +# This circuit has symmetries and needs to be flattened to resolve them +# or the banks won't pass +flatten class {-circuit1 bitcell_array_0} +flatten class {-circuit1 bitcell_array_1} +#flatten class {-circuit1 precharge_array_0} +#flatten class {-circuit1 precharge_array_1} +#flatten class {-circuit1 precharge_array_2} +#flatten class {-circuit1 precharge_array_3} +property {-circuit1 nfet} remove as ad ps pd +property {-circuit1 pfet} remove as ad ps pd +property {-circuit2 n} remove as ad ps pd +property {-circuit2 p} remove as ad ps pd +permute transistors diff --git a/technology/scn3me_subm/mag_lib/tri_gate.mag b/technology/scn3me_subm/mag_lib/tri_gate.mag new file mode 100644 index 00000000..bda635c7 --- /dev/null +++ b/technology/scn3me_subm/mag_lib/tri_gate.mag @@ -0,0 +1,98 @@ +magic +tech scmos +timestamp 1536089695 +<< nwell >> +rect -2 45 38 73 +<< pwell >> +rect -2 0 38 45 +<< ntransistor >> +rect 9 27 11 31 +rect 17 27 19 31 +rect 25 27 27 31 +<< ptransistor >> +rect 9 53 11 61 +rect 17 53 19 61 +rect 25 53 27 61 +<< ndiffusion >> +rect 8 27 9 31 +rect 11 27 12 31 +rect 16 27 17 31 +rect 19 27 20 31 +rect 24 27 25 31 +rect 27 27 28 31 +<< pdiffusion >> +rect 8 53 9 61 +rect 11 53 12 61 +rect 16 53 17 61 +rect 19 53 20 61 +rect 24 53 25 61 +rect 27 53 28 61 +<< ndcontact >> +rect 4 27 8 31 +rect 12 27 16 31 +rect 20 27 24 31 +rect 28 27 32 31 +<< pdcontact >> +rect 4 53 8 61 +rect 12 53 16 61 +rect 20 53 24 61 +rect 28 53 32 61 +<< psubstratepcontact >> +rect 12 19 16 23 +<< nsubstratencontact >> +rect 12 65 16 69 +<< polysilicon >> +rect 25 63 35 65 +rect 9 61 11 63 +rect 17 61 19 63 +rect 25 61 27 63 +rect 9 50 11 53 +rect 9 31 11 46 +rect 17 42 19 53 +rect 25 51 27 53 +rect 17 31 19 38 +rect 25 31 27 33 +rect 9 25 11 27 +rect 17 25 19 27 +rect 25 16 27 27 +rect 33 8 35 63 +rect 32 6 35 8 +<< polycontact >> +rect 9 46 13 50 +rect 16 38 20 42 +rect 25 12 29 16 +rect 28 4 32 8 +<< metal1 >> +rect 16 65 23 69 +rect 12 61 16 65 +rect 3 53 4 61 +rect 3 42 6 53 +rect 13 46 15 50 +rect 3 38 16 42 +rect 3 31 6 38 +rect 29 31 32 53 +rect 3 27 4 31 +rect 12 23 16 27 +rect 16 19 24 23 +rect 0 12 25 16 +rect 29 12 36 16 +rect 0 4 28 8 +rect 32 4 36 8 +<< m2contact >> +rect 23 65 27 69 +rect 15 46 19 50 +rect 25 34 29 38 +rect 24 19 28 23 +<< metal2 >> +rect 15 34 25 38 +rect 15 0 19 34 +<< bb >> +rect 0 0 34 73 +<< labels >> +rlabel metal1 0 12 0 12 3 en +rlabel metal1 0 4 0 4 2 en_bar +rlabel metal2 16 1 16 1 1 out +rlabel m2contact 26 21 26 21 1 gnd +rlabel m2contact 25 67 25 67 1 vdd +rlabel m2contact 17 48 17 48 1 in +<< end >> diff --git a/technology/scn3me_subm/mag_lib/write_driver.mag b/technology/scn3me_subm/mag_lib/write_driver.mag new file mode 100644 index 00000000..ab2014aa --- /dev/null +++ b/technology/scn3me_subm/mag_lib/write_driver.mag @@ -0,0 +1,224 @@ +magic +tech scmos +timestamp 1536089714 +<< nwell >> +rect -3 101 37 138 +rect -3 0 37 51 +<< pwell >> +rect -3 138 37 202 +rect -3 51 37 101 +<< ntransistor >> +rect 9 177 11 189 +rect 17 177 19 189 +rect 15 162 27 164 +rect 9 144 11 148 +rect 17 144 19 148 +rect 10 82 12 89 +rect 18 82 20 89 +rect 8 57 10 64 +rect 16 57 18 64 +rect 24 60 26 64 +<< ptransistor >> +rect 9 125 11 132 +rect 17 125 19 132 +rect 10 107 12 114 +rect 18 107 20 114 +rect 8 38 10 45 +rect 16 38 18 45 +rect 24 38 26 45 +<< ndiffusion >> +rect 8 177 9 189 +rect 11 177 12 189 +rect 16 177 17 189 +rect 19 177 20 189 +rect 15 164 27 165 +rect 15 161 27 162 +rect 12 157 15 160 +rect 12 156 16 157 +rect 8 144 9 148 +rect 11 144 12 148 +rect 16 144 17 148 +rect 19 144 20 148 +rect 9 82 10 89 +rect 12 82 13 89 +rect 17 82 18 89 +rect 20 82 21 89 +rect 25 82 26 86 +rect 7 57 8 64 +rect 10 57 11 64 +rect 15 57 16 64 +rect 18 57 19 64 +rect 23 60 24 64 +rect 26 60 27 64 +<< pdiffusion >> +rect 8 125 9 132 +rect 11 125 12 132 +rect 16 125 17 132 +rect 19 125 20 132 +rect 12 122 16 125 +rect 9 107 10 114 +rect 12 107 13 114 +rect 17 107 18 114 +rect 20 107 21 114 +rect 7 38 8 45 +rect 10 38 11 45 +rect 15 38 16 45 +rect 18 38 19 45 +rect 23 38 24 45 +rect 26 38 27 45 +rect 3 35 7 38 +<< ndcontact >> +rect 4 177 8 189 +rect 12 177 16 189 +rect 20 177 24 189 +rect 15 165 27 169 +rect 15 157 27 161 +rect 4 144 8 148 +rect 12 144 16 148 +rect 20 144 24 148 +rect 5 82 9 89 +rect 13 82 17 89 +rect 21 82 25 89 +rect 3 57 7 64 +rect 11 57 15 64 +rect 19 57 23 64 +rect 27 60 31 64 +<< pdcontact >> +rect 4 125 8 132 +rect 12 125 16 132 +rect 20 125 24 132 +rect 5 107 9 114 +rect 13 107 17 114 +rect 21 107 25 114 +rect 3 38 7 45 +rect 11 38 15 45 +rect 19 38 23 45 +rect 27 38 31 45 +<< psubstratepcontact >> +rect 12 152 16 156 +rect 26 82 30 86 +<< nsubstratencontact >> +rect 12 118 16 122 +rect 3 31 7 35 +<< polysilicon >> +rect 9 194 30 196 +rect 9 189 11 194 +rect 17 189 19 191 +rect 28 185 30 194 +rect 9 175 11 177 +rect 17 172 19 177 +rect 6 170 19 172 +rect 6 167 8 170 +rect 13 162 15 164 +rect 27 162 33 164 +rect 9 148 11 150 +rect 17 148 19 150 +rect 9 132 11 144 +rect 17 132 19 144 +rect 9 124 11 125 +rect 2 122 11 124 +rect 17 124 19 125 +rect 17 122 28 124 +rect 2 75 4 122 +rect 10 114 12 116 +rect 18 114 20 116 +rect 10 89 12 107 +rect 18 106 20 107 +rect 16 104 20 106 +rect 16 92 18 104 +rect 26 100 28 122 +rect 27 96 28 100 +rect 16 90 20 92 +rect 18 89 20 90 +rect 10 81 12 82 +rect 10 79 13 81 +rect 2 71 3 75 +rect 11 71 13 79 +rect 18 79 20 82 +rect 18 77 23 79 +rect 31 71 33 162 +rect 11 69 33 71 +rect 11 67 13 69 +rect 8 65 13 67 +rect 8 64 10 65 +rect 16 64 18 66 +rect 24 64 26 66 +rect 8 45 10 57 +rect 16 52 18 57 +rect 24 52 26 60 +rect 16 50 26 52 +rect 16 45 18 50 +rect 24 45 26 50 +rect 8 28 10 38 +rect 16 14 18 38 +rect 24 36 26 38 +<< polycontact >> +rect 28 181 32 185 +rect 4 163 8 167 +rect 23 96 27 100 +rect 3 71 7 75 +rect 23 75 27 79 +rect 7 24 11 28 +rect 15 10 19 14 +<< metal1 >> +rect 5 192 10 196 +rect 5 189 8 192 +rect 32 181 33 185 +rect 13 169 16 177 +rect 13 165 15 169 +rect 4 148 8 163 +rect 12 157 15 161 +rect 12 156 16 157 +rect 12 148 16 152 +rect 4 132 8 144 +rect 20 142 24 144 +rect 30 142 33 181 +rect 20 138 33 142 +rect 20 132 24 138 +rect 12 122 16 125 +rect 13 114 17 118 +rect 5 104 9 107 +rect 21 104 25 107 +rect 5 101 25 104 +rect 5 89 9 101 +rect 21 100 25 101 +rect 21 96 23 100 +rect 25 82 26 90 +rect 4 64 7 71 +rect 27 64 31 79 +rect 3 51 7 57 +rect 3 48 15 51 +rect 11 45 15 48 +rect 27 45 31 60 +rect 3 35 7 38 +rect 19 35 23 38 +rect 7 31 19 35 +rect 0 24 7 28 +rect 11 24 36 28 +<< m2contact >> +rect 10 192 14 196 +rect 20 189 24 193 +rect 23 153 27 157 +rect 16 118 20 122 +rect 26 86 30 90 +rect 19 64 23 68 +rect 19 31 23 35 +rect 15 6 19 10 +<< metal2 >> +rect 10 196 14 202 +rect 20 193 24 202 +rect 20 177 24 189 +rect 15 0 19 6 +<< bb >> +rect 0 0 34 202 +<< labels >> +rlabel metal2 15 1 15 1 1 din +rlabel metal1 2 25 2 25 3 en +rlabel metal2 12 200 12 200 5 bl +rlabel metal2 22 200 22 200 5 br +rlabel m2contact 21 66 21 66 1 gnd +rlabel m2contact 28 88 28 88 1 gnd +rlabel m2contact 21 33 21 33 1 vdd +rlabel m2contact 18 120 18 120 1 vdd +rlabel m2contact 25 155 25 155 1 gnd +<< end >> diff --git a/technology/scn3me_subm/models/ff/nmos.sp b/technology/scn3me_subm/models/ff/nmos.sp new file mode 100644 index 00000000..9711c533 --- /dev/null +++ b/technology/scn3me_subm/models/ff/nmos.sp @@ -0,0 +1,10 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 ++ NSUB=6E16 U0=461 K1=0.5705 TOX=13.9n VERSION=3.3.0) + diff --git a/technology/scn3me_subm/models/ff/pmos.sp b/technology/scn3me_subm/models/ff/pmos.sp new file mode 100644 index 00000000..e08967e4 --- /dev/null +++ b/technology/scn3me_subm/models/ff/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n VERSION=3.3.0) diff --git a/technology/scn3me_subm/models/nom/nmos.sp b/technology/scn3me_subm/models/nom/nmos.sp new file mode 100644 index 00000000..59f88cfd --- /dev/null +++ b/technology/scn3me_subm/models/nom/nmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 ++ NSUB=6E16 U0=458 K1=0.5705 TOX=13.9n VERSION=3.3.0) diff --git a/technology/scn3me_subm/models/nom/pmos.sp b/technology/scn3me_subm/models/nom/pmos.sp new file mode 100644 index 00000000..69f3aacd --- /dev/null +++ b/technology/scn3me_subm/models/nom/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n VERSION=3.3.0) diff --git a/technology/scn3me_subm/models/ss/nmos.sp b/technology/scn3me_subm/models/ss/nmos.sp new file mode 100644 index 00000000..4e8a531f --- /dev/null +++ b/technology/scn3me_subm/models/ss/nmos.sp @@ -0,0 +1,10 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 ++ NSUB=6E16 U0=460 K1=0.5705 TOX=13.9n VERSION=3.3.0) + diff --git a/technology/scn3me_subm/models/ss/pmos.sp b/technology/scn3me_subm/models/ss/pmos.sp new file mode 100644 index 00000000..e08967e4 --- /dev/null +++ b/technology/scn3me_subm/models/ss/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n VERSION=3.3.0) diff --git a/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp new file mode 100644 index 00000000..f58867a7 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u +MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u +MM3 Q Q_bar vdd vdd p w=0.9u l=0.6u +MM2 Q_bar Q vdd vdd p w=0.9u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/cell_1w_1r.sp new file mode 100644 index 00000000..fe981d6d --- /dev/null +++ b/technology/scn3me_subm/sp_lib/cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u +MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u +MM3 Q Q_bar vdd vdd p w=0.9u l=0.6u +MM2 Q_bar Q vdd vdd p w=0.9u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/cell_6t.sp b/technology/scn3me_subm/sp_lib/cell_6t.sp new file mode 100644 index 00000000..76c40f31 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/cell_6t.sp @@ -0,0 +1,10 @@ + +*********************** "cell_6t" ****************************** +.SUBCKT cell_6t bl br wl vdd gnd +M_1 Q Qb vdd vdd p W='0.9u' L=1.2u +M_2 Qb Q vdd vdd p W='0.9u' L=1.2u +M_3 br wl Qb gnd n W='1.2u' L=0.6u +M_4 bl wl Q gnd n W='1.2u' L=0.6u +M_5 Qb Q gnd gnd n W='2.4u' L=0.6u +M_6 Q Qb gnd gnd n W='2.4u' L=0.6u +.ENDS $ cell_6t diff --git a/technology/scn3me_subm/sp_lib/dff.sp b/technology/scn3me_subm/sp_lib/dff.sp new file mode 100644 index 00000000..d3fa7635 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/dff.sp @@ -0,0 +1,27 @@ +*********************** "dff" ****************************** +* Positive edge-triggered FF +.SUBCKT dff D Q clk vdd gnd +M0 vdd clk a_2_6# vdd p w=12u l=0.6u +M1 a_17_74# D vdd vdd p w=6u l=0.6u +M2 a_22_6# clk a_17_74# vdd p w=6u l=0.6u +M3 a_31_74# a_2_6# a_22_6# vdd p w=6u l=0.6u +M4 vdd a_34_4# a_31_74# vdd p w=6u l=0.6u +M5 a_34_4# a_22_6# vdd vdd p w=6u l=0.6u +M6 a_61_74# a_34_4# vdd vdd p w=6u l=0.6u +M7 a_66_6# a_2_6# a_61_74# vdd p w=6u l=0.6u +M8 a_76_84# clk a_66_6# vdd p w=3u l=0.6u +M9 vdd Q a_76_84# vdd p w=3u l=0.6u +M10 gnd clk a_2_6# gnd n w=6u l=0.6u +M11 Q a_66_6# vdd vdd p w=12u l=0.6u +M12 a_17_6# D gnd gnd n w=3u l=0.6u +M13 a_22_6# a_2_6# a_17_6# gnd n w=3u l=0.6u +M14 a_31_6# clk a_22_6# gnd n w=3u l=0.6u +M15 gnd a_34_4# a_31_6# gnd n w=3u l=0.6u +M16 a_34_4# a_22_6# gnd gnd n w=3u l=0.6u +M17 a_61_6# a_34_4# gnd gnd n w=3u l=0.6u +M18 a_66_6# clk a_61_6# gnd n w=3u l=0.6u +M19 a_76_6# a_2_6# a_66_6# gnd n w=3u l=0.6u +M20 gnd Q a_76_6# gnd n w=3u l=0.6u +M21 Q a_66_6# gnd gnd n w=6u l=0.6u + +.ENDS dff diff --git a/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp new file mode 100644 index 00000000..1c4c1bc3 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u +MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u +MM3 Q Q_bar vdd vdd p w=1.2u l=0.6u +MM2 Q_bar Q vdd vdd p w=1.2u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp new file mode 100644 index 00000000..aed7466b --- /dev/null +++ b/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u +MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u +MM3 Q Q_bar vdd vdd p w=1.2u l=0.6u +MM2 Q_bar Q vdd vdd p w=1.2u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp new file mode 100644 index 00000000..e90dd033 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q vdd gnd gnd n w=2.4u l=0.6u +MM0 vdd Q gnd gnd n w=2.4u l=0.6u +MM3 Q vdd vdd vdd p w=1.2u l=0.6u +MM2 vdd Q vdd vdd p w=1.2u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp new file mode 100644 index 00000000..bd2e5eb5 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT replica_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 vdd wl0 br0 gnd n w=0.8u l=0.6u +MM1 Q vdd gnd gnd n w=2.4u l=0.6u +MM0 vdd Q gnd gnd n w=2.4u l=0.6u +MM3 Q vdd vdd vdd p w=0.6u l=0.6u +MM2 vdd Q vdd vdd p w=0.6u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/ms_flop.sp b/technology/scn3me_subm/sp_lib/ms_flop.sp new file mode 100644 index 00000000..abf664e7 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/ms_flop.sp @@ -0,0 +1,29 @@ +*master-slave flip-flop with both output and inverted ouput + +.subckt dlatch din dout dout_bar clk clk_bar vdd gnd +*clk inverter +mPff1 clk_bar clk vdd vdd p W=1.8u L=0.6u m=1 +mNff1 clk_bar clk gnd gnd n W=0.9u L=0.6u m=1 + +*transmission gate 1 +mtmP1 din clk int1 vdd p W=1.8u L=0.6u m=1 +mtmN1 din clk_bar int1 gnd n W=0.9u L=0.6u m=1 + +*foward inverter +mPff3 dout_bar int1 vdd vdd p W=1.8u L=0.6u m=1 +mNff3 dout_bar int1 gnd gnd n W=0.9u L=0.6u m=1 + +*backward inverter +mPff4 dout dout_bar vdd vdd p W=1.8u L=0.6u m=1 +mNf4 dout dout_bar gnd gnd n W=0.9u L=0.6u m=1 + +*transmission gate 2 +mtmP2 int1 clk_bar dout vdd p W=1.8u L=0.6u m=1 +mtmN2 int1 clk dout gnd n W=0.9u L=0.6u m=1 +.ends dlatch + +.subckt ms_flop din dout dout_bar clk vdd gnd +xmaster din mout mout_bar clk clk_bar vdd gnd dlatch +xslave mout_bar dout_bar dout clk_bar clk_nn vdd gnd dlatch +.ends flop + diff --git a/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp new file mode 100644 index 00000000..a8654c83 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q vdd gnd gnd n w=2.4u l=0.6u +MM0 vdd Q gnd gnd n w=2.4u l=0.6u +MM3 Q vdd vdd vdd p w=0.9u l=0.6u +MM2 vdd Q vdd vdd p w=0.9u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp new file mode 100644 index 00000000..5b9c9b18 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT replica_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u +MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u +MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u +MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u +MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u +MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u +MM1 Q vdd gnd gnd n w=2.4u l=0.6u +MM0 vdd Q gnd gnd n w=2.4u l=0.6u +MM3 Q vdd vdd vdd p w=0.9u l=0.6u +MM2 vdd Q vdd vdd p w=0.9u l=0.6u +.ENDS + diff --git a/technology/scn3me_subm/sp_lib/replica_cell_6t.sp b/technology/scn3me_subm/sp_lib/replica_cell_6t.sp new file mode 100644 index 00000000..1fa75a55 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/replica_cell_6t.sp @@ -0,0 +1,10 @@ + +*********************** "cell_6t" ****************************** +.SUBCKT replica_cell_6t bl br wl vdd gnd +M_1 gnd net_2 vdd vdd p W='0.9u' L=1.2u +M_2 net_2 gnd vdd vdd p W='0.9u' L=1.2u +M_3 br wl net_2 gnd n W='1.2u' L=0.6u +M_4 bl wl gnd gnd n W='1.2u' L=0.6u +M_5 net_2 gnd gnd gnd n W='2.4u' L=0.6u +M_6 gnd net_2 gnd gnd n W='2.4u' L=0.6u +.ENDS $ replica_cell_6t diff --git a/technology/scn3me_subm/sp_lib/sense_amp.sp b/technology/scn3me_subm/sp_lib/sense_amp.sp new file mode 100644 index 00000000..1399228d --- /dev/null +++ b/technology/scn3me_subm/sp_lib/sense_amp.sp @@ -0,0 +1,12 @@ +*********************** "sense_amp" ****************************** + +.SUBCKT sense_amp bl br dout en vdd gnd +M_1 dout net_1 vdd vdd p W='5.4*1u' L=0.6u +M_2 dout net_1 net_2 gnd n W='2.7*1u' L=0.6u +M_3 net_1 dout vdd vdd p W='5.4*1u' L=0.6u +M_4 net_1 dout net_2 gnd n W='2.7*1u' L=0.6u +M_5 bl en dout vdd p W='7.2*1u' L=0.6u +M_6 br en net_1 vdd p W='7.2*1u' L=0.6u +M_7 net_2 en gnd gnd n W='2.7*1u' L=0.6u +.ENDS sense_amp + diff --git a/technology/scn3me_subm/sp_lib/tri_gate.sp b/technology/scn3me_subm/sp_lib/tri_gate.sp new file mode 100644 index 00000000..0d298172 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/tri_gate.sp @@ -0,0 +1,13 @@ +*********************** tri_gate ****************************** + +.SUBCKT tri_gate in out en en_bar vdd gnd + +M_1 net_2 in_inv gnd gnd n W='1.2*1u' L=0.6u +M_2 net_3 in_inv vdd vdd p W='2.4*1u' L=0.6u +M_3 out en_bar net_3 vdd p W='2.4*1u' L=0.6u +M_4 out en net_2 gnd n W='1.2*1u' L=0.6u +M_5 in_inv in vdd vdd p W='2.4*1u' L=0.6u +M_6 in_inv in gnd gnd n W='1.2*1u' L=0.6u + + +.ENDS diff --git a/technology/scn3me_subm/sp_lib/write_driver.sp b/technology/scn3me_subm/sp_lib/write_driver.sp new file mode 100644 index 00000000..88f80361 --- /dev/null +++ b/technology/scn3me_subm/sp_lib/write_driver.sp @@ -0,0 +1,38 @@ +*********************** Write_Driver ****************************** +.SUBCKT write_driver din bl br en vdd gnd + +**** Inverter to conver Data_in to data_in_bar ****** +* din_bar = inv(din) +M_1 din_bar din gnd gnd n W=1.2u L=0.6u +M_2 din_bar din vdd vdd p W=2.1u L=0.6u + +**** 2input nand gate follwed by inverter to drive BL ****** +* din_bar_gated = nand(en, din) +M_3 din_bar_gated en net_7 gnd n W=2.1u L=0.6u +M_4 net_7 din gnd gnd n W=2.1u L=0.6u +M_5 din_bar_gated en vdd vdd p W=2.1u L=0.6u +M_6 din_bar_gated din vdd vdd p W=2.1u L=0.6u +* din_bar_gated_bar = inv(din_bar_gated) +M_7 din_bar_gated_bar din_bar_gated vdd vdd p W=2.1u L=0.6u +M_8 din_bar_gated_bar din_bar_gated gnd gnd n W=1.2u L=0.6u + +**** 2input nand gate follwed by inverter to drive BR****** +* din_gated = nand(en, din_bar) +M_9 din_gated en vdd vdd p W=2.1u L=0.6u +M_10 din_gated en net_8 gnd n W=2.1u L=0.6u +M_11 net_8 din_bar gnd gnd n W=2.1u L=0.6u +M_12 din_gated din_bar vdd vdd p W=2.1u L=0.6u +* din_gated_bar = inv(din_gated) +M_13 din_gated_bar din_gated vdd vdd p W=2.1u L=0.6u +M_14 din_gated_bar din_gated gnd gnd n W=1.2u L=0.6u + +************************************************ +* pull down with en enable +M_15 bl din_gated_bar net_5 gnd n W=3.6u L=0.6u +M_16 br din_bar_gated_bar net_5 gnd n W=3.6u L=0.6u +M_17 net_5 en gnd gnd n W=3.6u L=0.6u + + + +.ENDS $ write_driver + diff --git a/technology/scn3me_subm/sue_lib/cell_6t.sue b/technology/scn3me_subm/sue_lib/cell_6t.sue new file mode 100644 index 00000000..427b1d05 --- /dev/null +++ b/technology/scn3me_subm/sue_lib/cell_6t.sue @@ -0,0 +1,46 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_cell_6t {} { + make inout -name BL -origin {190 360} + make inout -name BR -origin {830 360} + make input -name WL -origin {240 120} + make global -orient RXY -name vdd -origin {520 160} + make global -name gnd -origin {510 600} + make pmos -orient RY -W 0.9u -L 1.2u -origin {630 230} + make pmos -orient RXY -W 0.9u -L 1.2u -origin {400 230} + make nmos -orient R90 -W 1.2 -L 0.6u -origin {740 360} + make nmos -orient R90X -W 1.2 -L 0.6u -origin {270 360} + make nmos -W 2.4u -L 0.6u -origin {630 490} + make nmos -orient RX -W 2.4u -L 0.6u -origin {400 490} + make_wire 630 550 630 530 + make_wire 400 530 400 550 + make_wire 400 190 400 170 + make_wire 630 170 630 190 + make_wire 400 360 400 270 + make_wire 310 360 400 360 + make_wire 630 360 630 450 + make_wire 630 360 700 360 + make_wire 270 300 270 120 + make_wire 270 120 740 120 + make_wire 740 120 740 300 + make_wire 230 360 190 360 + make_wire 780 360 830 360 + make_wire 510 550 400 550 + make_wire 510 550 630 550 + make_wire 510 550 510 600 + make_wire 520 170 400 170 + make_wire 520 170 630 170 + make_wire 520 160 520 170 + make_wire 240 120 270 120 + make_wire 460 290 630 290 + make_wire 460 290 460 490 + make_wire 460 290 460 230 + make_wire 630 290 630 360 + make_wire 630 290 630 270 + make_wire 570 420 400 420 + make_wire 570 420 570 490 + make_wire 570 420 570 230 + make_wire 400 420 400 360 + make_wire 400 420 400 450 +} + diff --git a/technology/scn3me_subm/sue_lib/ms_flop.sue b/technology/scn3me_subm/sue_lib/ms_flop.sue new file mode 100644 index 00000000..85cc8e03 --- /dev/null +++ b/technology/scn3me_subm/sue_lib/ms_flop.sue @@ -0,0 +1,84 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_ms_flop {} { + make pmos -orient R90X -W 1.8u -L 0.6u -origin {40 250} + make nmos -orient R270 -W 0.9u -L 0.6u -origin {40 380} + make inverter -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {-270 540} + make inverter -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {310 310} + make inverter -orient RX -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {430 730} + make pmos -orient R90X -W 1.8u -L 0.6u -origin {190 670} + make nmos -orient R270 -W 0.9u -L 0.6u -origin {190 780} + make input -name clk -origin {-380 540} + make input -name din -origin {-370 320} + make pmos -orient R90X -W 1.8u -L 0.6u -origin {720 250} + make nmos -orient R270 -W 0.9u -L 0.6u -origin {720 380} + make inverter -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {990 310} + make pmos -orient R90X -W 1.8u -L 0.6u -origin {870 670} + make nmos -orient R270 -W 0.9u -L 0.6u -origin {870 780} + make inverter -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {620 540} + make output -name dout -origin {1410 310} + make output -name dout_bar -origin {1430 930} + make inverter -orient RX -WP 1.8u -LP 0.6u -WN 0.9u -LN 0.6u -origin {1110 730} + make_wire -330 160 40 160 + make_wire 40 160 40 190 + make_wire -370 320 0 320 + make_wire 360 310 480 310 + make_wire 460 730 480 730 + make_wire 230 730 380 730 + make_wire 100 310 100 720 + make_wire 100 720 150 720 + make_wire 100 310 80 310 + make_wire 100 310 280 310 + make_wire 0 250 0 320 + make_wire 0 320 0 380 + make_wire 80 250 80 310 + make_wire 80 310 80 380 + make_wire 40 440 40 540 + make_wire -330 840 190 840 + make_wire 230 670 230 730 + make_wire 230 730 230 780 + make_wire 150 670 150 720 + make_wire 150 720 150 780 + make_wire 190 540 190 610 + make_wire -330 540 -330 840 + make_wire -220 540 40 540 + make_wire 40 540 190 540 + make_wire -380 540 -330 540 + make_wire -330 540 -300 540 + make_wire -330 540 -330 160 + make_wire 720 160 720 190 + make_wire 1140 730 1160 730 + make_wire 780 310 780 720 + make_wire 780 720 830 720 + make_wire 780 310 760 310 + make_wire 780 310 960 310 + make_wire 680 320 680 380 + make_wire 760 250 760 310 + make_wire 760 310 760 380 + make_wire 720 440 720 540 + make_wire 910 670 910 730 + make_wire 910 730 910 780 + make_wire 830 670 830 720 + make_wire 830 720 830 780 + make_wire 870 540 870 610 + make_wire 720 540 870 540 + make_wire 670 540 720 540 + make_wire 480 310 480 730 + make_wire 1160 310 1160 730 + make_wire 530 540 530 160 + make_wire 530 160 720 160 + make_wire 530 540 190 540 + make_wire 530 540 590 540 + make_wire 530 540 530 840 + make_wire 530 840 870 840 + make_wire 680 310 480 310 + make_wire 680 310 680 250 + make_wire 680 310 680 320 + make_wire 950 730 910 730 + make_wire 950 730 1060 730 + make_wire 1040 310 1160 310 + make_wire 1160 310 1410 310 + make_wire 950 930 1430 930 + make_wire 950 730 950 930 +} + diff --git a/technology/scn3me_subm/sue_lib/replica_cell_6t.sue b/technology/scn3me_subm/sue_lib/replica_cell_6t.sue new file mode 100644 index 00000000..56e72056 --- /dev/null +++ b/technology/scn3me_subm/sue_lib/replica_cell_6t.sue @@ -0,0 +1,49 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_replica_cell_6t {} { + make inout -name BL -origin {190 360} + make inout -name BR -origin {830 360} + make input -name WL -origin {240 120} + make global -orient RXY -name vdd -origin {520 160} + make global -name gnd -origin {510 600} + make pmos -orient RY -W 0.9u -L 1.2u -origin {630 230} + make pmos -orient RXY -W 0.9u -L 1.2u -origin {400 230} + make nmos -orient R90 -W 1.2 -L 0.6u -origin {740 360} + make nmos -orient R90X -W 1.2 -L 0.6u -origin {270 360} + make nmos -W 2.4u -L 0.6u -origin {630 490} + make nmos -orient RX -W 2.4u -L 0.6u -origin {400 490} + make_wire 630 550 630 530 + make_wire 400 530 400 550 + make_wire 400 190 400 170 + make_wire 630 170 630 190 + make_wire 400 360 400 270 + make_wire 630 360 630 450 + make_wire 630 360 700 360 + make_wire 270 300 270 120 + make_wire 270 120 740 120 + make_wire 740 120 740 300 + make_wire 230 360 190 360 + make_wire 780 360 830 360 + make_wire 510 550 400 550 + make_wire 510 550 630 550 + make_wire 510 550 510 600 + make_wire 520 170 400 170 + make_wire 520 170 630 170 + make_wire 520 160 520 170 + make_wire 240 120 270 120 + make_wire 460 290 630 290 + make_wire 460 290 460 490 + make_wire 460 290 460 230 + make_wire 630 290 630 360 + make_wire 630 290 630 270 + make_wire 570 420 400 420 + make_wire 570 420 570 490 + make_wire 570 420 570 230 + make_wire 400 420 400 360 + make_wire 400 420 400 450 + make_wire 320 360 320 550 + make_wire 320 550 400 550 + make_wire 320 360 310 360 + make_wire 320 360 400 360 +} + diff --git a/technology/scn3me_subm/sue_lib/sense_amp.sue b/technology/scn3me_subm/sue_lib/sense_amp.sue new file mode 100644 index 00000000..4d29e11a --- /dev/null +++ b/technology/scn3me_subm/sue_lib/sense_amp.sue @@ -0,0 +1,52 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_sense_amp {} { + make inout -name BL -origin {260 10} + make global -orient RXY -name vdd -origin {490 170} + make global -name gnd -origin {480 660} + make input -name sclk -origin {180 610} + make nmos -W 3.9u -L 0.6u -origin {600 500} + make nmos -orient RX -W 3.9u -L 0.6u -origin {370 500} + make pmos -orient RY -W 3u -L 0.6u -origin {600 240} + make pmos -orient RXY -W 3u -L 0.6u -origin {370 240} + make nmos -W 3.9u -L 0.6u -origin {480 610} + make inout -name BR -origin {710 20} + make pmos -W 3.9u -L 0.6u -origin {710 90} + make pmos -orient RX -W 3.9u -L 0.6u -origin {260 90} + make output -orient RXY -name dout -origin {110 370} + make_wire 600 560 600 540 + make_wire 370 540 370 560 + make_wire 370 200 370 180 + make_wire 600 180 600 200 + make_wire 490 180 370 180 + make_wire 490 180 600 180 + make_wire 490 170 490 180 + make_wire 430 300 600 300 + make_wire 430 300 430 500 + make_wire 430 300 430 240 + make_wire 600 300 600 280 + make_wire 540 430 370 430 + make_wire 540 430 540 500 + make_wire 540 430 540 240 + make_wire 370 430 370 460 + make_wire 480 560 600 560 + make_wire 480 560 370 560 + make_wire 480 560 480 570 + make_wire 480 650 480 660 + make_wire 420 610 180 610 + make_wire 650 90 320 90 + make_wire 600 360 710 360 + make_wire 710 360 710 130 + make_wire 600 360 600 300 + make_wire 600 360 600 460 + make_wire 370 370 260 370 + make_wire 260 370 260 130 + make_wire 370 370 370 430 + make_wire 370 370 370 280 + make_wire 260 10 260 50 + make_wire 710 20 710 50 + make_wire 320 90 180 90 + make_wire 180 90 180 610 + make_wire 110 370 260 370 +} + diff --git a/technology/scn3me_subm/sue_lib/tri_gate.sue b/technology/scn3me_subm/sue_lib/tri_gate.sue new file mode 100644 index 00000000..d296171f --- /dev/null +++ b/technology/scn3me_subm/sue_lib/tri_gate.sue @@ -0,0 +1,37 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_tri_gate {} { + make global -orient RXY -name vdd -origin {630 150} + make global -name gnd -origin {630 570} + make input -name tri_in -origin {320 340} + make output -name tri_out -origin {690 360} + make input -name en -origin {570 410} + make input -name en_bar -origin {570 310} + make nmos -W 1.2u -L 0.6u -origin {630 490} + make nmos -W 1.2u -L 0.6u -origin {630 410} + make pmos -orient RY -W 2.4u -L 0.6u -origin {630 310} + make pmos -orient RY -W 2.4u -L 0.6u -origin {630 230} + make pmos -orient RY -W 2.4u -L 0.6u -origin {380 290} + make nmos -W 1.2u -L 0.6u -origin {380 400} + make_wire 570 490 470 490 + make_wire 470 230 570 230 + make_wire 630 550 380 550 + make_wire 380 550 380 440 + make_wire 630 550 630 570 + make_wire 630 550 630 530 + make_wire 630 170 380 170 + make_wire 380 170 380 250 + make_wire 630 170 630 190 + make_wire 630 170 630 150 + make_wire 320 340 320 400 + make_wire 320 340 320 290 + make_wire 380 340 470 340 + make_wire 380 340 380 330 + make_wire 380 340 380 360 + make_wire 470 340 470 490 + make_wire 470 340 470 230 + make_wire 630 360 630 350 + make_wire 630 360 630 370 + make_wire 630 360 690 360 +} + diff --git a/technology/scn3me_subm/sue_lib/write_driver.sue b/technology/scn3me_subm/sue_lib/write_driver.sue new file mode 100644 index 00000000..de3909a7 --- /dev/null +++ b/technology/scn3me_subm/sue_lib/write_driver.sue @@ -0,0 +1,44 @@ +# SUE version MMI_SUE5.0.7 + +proc SCHEMATIC_write_driver {} { + make inout -name BL -origin {550 260} + make inout -name BR -origin {830 250} + make inverter -WP 2.1u -LP 0.6u -WN 1.2u -LN 0.6u -origin {280 520} + make nand2 -WP 2.1u -WN 2.1u -origin {90 360} + make inverter -WP 2.1u -LP 0.6u -WN 1.2u -LN 0.6u -origin {270 360} + make nmos -W 3.6u -L 0.6u -origin {830 410} + make nmos -W 3.6u -L 0.6u -origin {710 610} + make global -name gnd -origin {710 690} + make nand2 -WP 2.1u -WN 2.1u -origin {90 520} + make nmos -W 3.6u -L 0.6u -origin {550 410} + make input -name wen -origin {-290 340} + make input -name din -origin {-290 380} + make inverter -WP 2.1u -LP 0.6u -WN 1.2u -LN 0.6u -origin {-80 540} + make_wire 160 360 240 360 + make_wire 830 250 830 370 + make_wire 550 260 550 370 + make_wire 550 450 550 560 + make_wire 550 560 710 560 + make_wire 710 560 710 570 + make_wire 710 560 830 560 + make_wire 830 560 830 450 + make_wire 710 650 710 690 + make_wire 250 520 160 520 + make_wire 770 410 770 520 + make_wire 770 520 330 520 + make_wire 320 360 490 360 + make_wire 490 360 490 410 + make_wire -180 380 -290 380 + make_wire -180 380 70 380 + make_wire -180 540 -110 540 + make_wire -180 380 -180 540 + make_wire -30 540 70 540 + make_wire 20 340 20 500 + make_wire 20 500 70 500 + make_wire 20 340 70 340 + make_wire -240 340 -240 610 + make_wire -240 610 650 610 + make_wire -240 340 20 340 + make_wire -240 340 -290 340 +} + diff --git a/technology/scn3me_subm/tech/README b/technology/scn3me_subm/tech/README new file mode 100644 index 00000000..0d923fcb --- /dev/null +++ b/technology/scn3me_subm/tech/README @@ -0,0 +1,10 @@ +The file SCN3ME_SUBM.30.tech is from qflow 1.2 and has the following +license information: +--------------------------------------------------------------- +Tim Edwards +Open Circuit Design +v1.0 April 2013 +v1.1 May 2015 +v1.2 April 2017 +--------------------------------------------------------------- +GPL Copyright (c) 2017 diff --git a/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech new file mode 100644 index 00000000..bc447205 --- /dev/null +++ b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech @@ -0,0 +1,6942 @@ +tech + format 29 + scmos +end + +version + version 2001a + description "SCMOS: Submit as technology.lambda: SCN3ME_SUBM.30 [to process: AMIc5]" +end + +planes + well,w + implant,i + select,s + cap,c + active,a + metal1,m1 + metal2,m2 + metal3,m3 + oxide,ox + comment + xp + contact + via1,v1 + via2,v2 + fill +end + +types + well nwell,nw + well pwell,pw + implant n_field_implant,nfi + implant p_field_implant,pfi + select nselect,ns + select pselect,ps + cap electrode,poly2,el,p2 + metal1 electrodecontact,poly2contact,poly2c,p2c,elc + cap electrodecap,ecap,poly2cap,p2cap,pcap + contact genericpoly2contact,gc2 + active ntransistor,nfet + active ptransistor,pfet + active diffusion,diff + active transistor,fet + active ndiffusion,ndif,green + active pdiffusion,pdif,brown + active ndcontact,ndc + active pdcontact,pdc + active psubstratepdiff,pohmicdiff,pod,ppdiff,ppd,psd + active nsubstratendiff,nohmicdiff,nod,nndiff,nnd,nsd + active psubstratepcontact,pohmiccontact,poc,pwcontact,pwc,psc + active nsubstratencontact,nohmiccontact,noc,nwcontact,nwc,nsc + active polysilicon,red,poly,p + active polycontact,pcontact,polycut,pc + contact genericcontact,gcontact,gc + metal1 metal1,m1,blue + metal1 pseudo_rmetal1,prm1 + metal1 rmetal1,rm1 + metal1 fillm1,fm1 + metal1 m2contact,m2cut,m2c,via1,v1 + metal2 metal2,m2,purple + metal2 pseudo_rmetal2,prm2 + metal2 rmetal2,rm2 + metal2 fillm2,fm2 + via1 gv1 + metal2 m3contact,m3cut,m3c,via2,v2 + metal3 metal3,m3,cyan + metal3 pseudo_rmetal3,prm3 + metal3 rmetal3,rm3 + metal3 fillm3,fm3 + via2 gv2 + metal3 pad + oxide glass + cap high_resist,hr + cap poly2_high_resist,phr + active pseudo_rpoly,prp + active rpoly,rp + cap pseudo_rpoly2,prp2 + cap rpoly2,rp2 + active pseudo_rndiffusion,prnd + active rndiffusion,rndiff,rnd + active pseudo_rpdiffusion,prpd + active rpdiffusion,rpdiff,rpd + active pseudo_rnwell,prnwell,prnw + active rnwell,rnw + implant filln,fn + fill filla,fa + fill fillb,fb + active fillp,fp + active fillapm,fapm + xp xp + xp m1p + xp m2p + xp m3p + comment comment + comment bb +end + +contact + pc poly metal1 + ndc ndiff metal1 + pdc pdiff metal1 + nsc nsd metal1 + psc psd metal1 + m2c metal1 metal2 + m3c metal2 metal3 + stackable +end + +styles + styletype mos + nwell 12 + pwell 13 + nfi 53 + pfi 54 + nselect 43 + pselect 44 + diff 25 + tran 2 4 + ndiff 2 + pdiff 4 + nsd 3 + psd 5 + nfet 6 7 + pfet 8 9 + ndc 2 20 32 + pdc 4 20 32 + nsc 3 20 32 + psc 5 20 32 + poly 1 + pcontact 1 20 32 + gc 32 + metal1 20 + rm1 20 48 + prm1 48 + m1p 20 34 + fm1 20 34 + fp 1 34 + fa 32 + fb 45 34 + fn 45 34 + fapm 1 20 21 34 + gv1 55 + m2contact 20 21 55 + metal2 21 + rm2 21 48 + prm2 48 + m2p 21 34 + fm2 21 34 + gv2 56 + m3contact 21 22 56 + metal3 22 + rm3 22 48 + prm3 48 + m3p 22 34 + fm3 22 34 + pad 22 23 34 38 + glass 34 + xp 25 34 + ecap 10 14 + poly2 14 + p2c 14 20 32 + gc2 19 + hr 10 + phr 14 48 + rp 47 48 + prp 48 + rp2 14 48 + prp2 48 + rnd 2 48 + prnd 48 + rpd 4 53 + prpd 53 + rnw 12 53 + prnw 54 + comment 45 + bb 32 + error_p 42 + error_s 42 + error_ps 42 + magnet 54 + rotate 57 + fence 59 +end + +compose + compose nfet poly ndiff + compose pfet poly pdiff + paint diff nselect ndiff + paint diff pselect pdiff + compose tran poly diff + paint tran nselect nfet + paint tran pselect pfet + paint psd ns ndiff + paint nsd ps pdiff + paint ndiff ps psd + paint pdiff ns nsd + paint pad m1 pad + paint pad m2 pad + paint pad m2c pad + paint pfi nwell nfi + paint nfi pwell pfi + paint ndc nwell pdc + paint nfet nwell pfet + paint ndiff nwell pdiff + paint psd nwell nsd + paint psc nwell nsc + paint pdc pwell ndc + paint pfet pwell nfet + paint pdiff pwell ndiff + paint nsd pwell psd + paint nsc pwell psc + paint poly2 poly ecap + erase ecap poly poly2 + paint pad m3 pad + compose phr poly2 hr + paint hr poly2 phr + paint poly2 hr phr + erase phr hr poly2 +#CRE/CRM + compose rm1 prm1 m1 + compose rm2 prm2 m2 + compose rm3 prm3 m3 + compose rp prp poly + compose rp2 prp2 poly2 + compose rnd prnd ndiff + compose rpd prpd pdiff + paint nwell rnw space + paint nwell prnw space + paint poly fp fp + paint m1 fm1 fm1 + paint m2 fm2 fm2 + paint m3 fm3 fm3 +end + +connect + nwell,nsc/a,nsd nwell,nsc/a,nsd + pwell,psc/a,psd pwell,psc/a,psd + m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + m2,fm2,fapm,m2c/m2,m3c/m2,m3c/m2 m2,fm2,fapm,m2c/m2,m3c/m2,m3c/m2 + m3,fm3,fapm,m3c/m3 m3,fm3,fapm,m3c/m3 + ndiff,ndc/a,pdiff,pdc/a ndiff,ndc/a,pdiff,pdc/a + poly,fp,nfet,pfet,fet,fapm,pc/a poly,fp,nfet,pfet,fet,fapm,pc/a + poly2,ecap,p2c poly2,ecap,p2c + gc2 poly2,ecap,metal1 + gc poly,fp,ndiff,pdiff,nsd,psd,m1,fm1,fapm,m2c/m1 + gv1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2,fm2,fapm,m3c/m2 + gv2 m2,fm2,fapm,m2c/m2,m3c/m2,m3,fm3,fapm + pad m1,fm1,m2,fm2,m3,fm3 + rm1 prm1 + rm2 prm2 + rm3 prm3 + rnw prnw + rp prp + rp2 prp2 + rnd prnd + rpd prpd + phr hr +end + +cifoutput + +style lambda=0.30(p) + scalefactor 30 15 + options calma-permissive-labels + + layer CWN nwell,rnw + bloat-or pdiff,rpd,pdc/a,pfet * 180 + bloat-or nsd,nsc/a * 90 + bloat-or nfi * 120 + grow 90 + shrink 90 + labels nwell,rnw + calma 42 0 + + layer CWP pwell + bloat-or ndiff,rnd,ndc/a,nfet * 180 + bloat-or psd,psc/a * 90 + bloat-or pfi * 120 + grow 90 + shrink 90 + and-not CWN + labels pwell + calma 41 0 + + templayer TNS ns + + templayer TPS ps + +#we give priority to selects autogenerated around diffusions (vrs. ohmics) +#XDP = (pdiff*60) Or ps +#XDN = (ndiff*60) Or ns +#FSP = ((pdiff*60,psc*60) Or XDP And-Not XDN Or ps shrink-grow +#FSN = ((ndiff*60,nsc*60) Or XDN And-Not FDP Or ns shrink-grow +#CSN = FSN +#CSP = FSP + +#diffusion auto-nselect (will have priority) + templayer XDN + bloat-or ndiff,rnd,ndc/a * 60 psd,psc/a 0 + or TNS + +#diffusion auto-pselect (will have priority) + templayer XDP + bloat-or pdiff,rpd,pdc/a * 60 nsd,nsc/a 0 + or TPS + +#final pselect + templayer FSP + bloat-or pdiff,rpd,pfet,psd,pdc/a,psc/a,pfet * 60 ndiff,rnd,ndc/a,nsd,nsc/a,nfet 0 + or XDP +#give diff nselect priority + and-not XDN + or TPS + shrink 15 + grow 15 + grow 15 + shrink 15 + +#final nselect + templayer FSN + bloat-or ndiff,rnd,nfet,nsd,ndc/a,nsc/a,nfet * 60 pdiff,rpd,pdc/a,psd,psc/a,pfet 0 + or XDN +#never conflict with final pselect + and-not FSP +#drawn select always goes + or TNS + shrink 15 + grow 15 + grow 15 + shrink 15 + + layer CSN FSN + calma 45 0 + + layer CSP FSP + calma 44 0 + + layer CAA diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + labels diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + calma 43 0 + + layer CCA ndc/m1,nsc/m1 + squares 30 60 90 + calma 48 0 + + layer CCA pdc/m1,psc/m1 + squares 30 60 90 + calma 48 0 + + layer CPG poly,rp,nfet,pfet,fet,pc/a + labels poly,rp,nfet,pfet,fet,pc/a + calma 46 0 + + layer CCP pc/m1 + squares 30 60 90 + calma 47 0 + + layer CCE gc2 + squares 0 60 90 + calma 55 0 + + layer CCE p2c + squares 30 60 90 + calma 55 0 + + layer CCE gc2 + squares 0 60 90 + calma 55 0 + + layer CCC gc + squares 0 60 90 + calma 25 0 + + layer CV1 m2c/m1 + squares 30 60 90 + calma 50 0 + + layer CV1 gv1 + squares 0 60 90 + calma 50 0 + + layer CV2 m3c/m2 + squares 30 60 90 + calma 61 0 + + layer CV2 gv2 + squares 0 60 90 + calma 61 0 + + + templayer XPAD1 pad + shrink 180 + + templayer XPAD2 XPAD1 + shrink 180 + + layer CM3 pad + labels pad + calma 62 0 + + layer CV2 XPAD2 + squares 240 60 300 + calma 61 0 + + layer CM2 pad + labels pad + calma 51 0 + + layer CV1 XPAD2 + squares 60 60 300 + calma 50 0 + + layer CM1 pad + calma 49 0 + + layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + calma 49 0 + + layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2 + labels m2,rm2,m2c/m2,m3c/m2,m3c/m2 + calma 51 0 + + layer CMFP m1p + labels m1p + calma 81 0 + + layer CMSP m2p + labels m2p + calma 82 0 + + layer 100 fp + labels fp + calma 100 0 + + layer 101 fm1 + labels fm1 + calma 101 0 + + layer 102 fm2 + labels fm2 + calma 102 0 + + layer 103 fm3 + labels fm3 + calma 103 0 + + layer 109 fa + or fb + squares 0 210 120 + labels fa + calma 109 0 + + layer 119 fn + calma 119 0 + + layer 110 fapm + labels fapm + calma 110 0 + +# layer CPG fp + layer CPG fp,fapm + squares 0 210 120 + labels fp + calma 46 0 + +# layer CM1 fm1 + layer CM1 fm1,fapm + squares 0 210 120 + labels fm1 + calma 49 0 + +# layer CM2 fm2 + layer CM2 fm2,fapm + + squares 0 210 120 + labels fm2 + calma 51 0 + +# layer CM3 fm3 + layer CM3 fm3,fapm + + squares 0 210 120 + labels fm3 + calma 62 0 + + layer CM3 m3,rm3,m3c/m3 + labels m3,rm3,m3c/m3 + calma 62 0 + + layer CMTP m3p + labels m3p + calma 83 0 + + layer COG pad + shrink 600 + labels pad + calma 52 0 + + layer COG glass + labels glass + calma 52 0 + + layer CFI nfi,pfi + labels nfi,pfi + calma 27 0 + + layer CHR hr,phr + labels hr,phr + calma 34 0 + + layer CEL poly2,ecap,phr,p2c + labels poly2,ecap,phr,p2c + calma 56 0 + +#CRE/CRM + layer CRW rnw,prnw + labels rnw,prnw + calma 65 0 + layer CRG rp,prp + labels rp,prp + calma 67 0 + layer CRD rnd,rpd,prnd,prpd + labels rnd,rpd,prnd,prpd + calma 66 0 + layer CRE rnw,rp,rnd,rpd,rp2 + labels rnw,rp,rnd,rpd,rp2 + calma 64 0 + layer CRF rm1,prm1 + labels rm1,prm1 + calma 71 0 + layer CRS rm2,prm2 + labels rm2,prm2 + calma 72 0 + layer CRG2 rp2,prp2 + labels rp2,prp2 + calma 68 0 + layer CRT rm3,prm3 + labels rm3,prm3 + calma 73 0 +#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3 +#CRE/CRM calma 70 0 + + layer CX comment,bb + labels comment,bb + calma 63 0 + + layer XP pad,xp + labels pad,xp + calma 26 0 + +style fill-only + scalefactor 30 15 + + layer 100 fp + calma 100 0 + + layer 101 fm1 + calma 101 0 + + layer 102 fm2 + calma 102 0 + + layer 103 fm3 + calma 103 0 + + layer 109 fa + or fb + calma 109 0 + + layer 119 fn + calma 119 0 + +style fapm-boxes + +# this output style creates fill boxes automatically (to meet minimum +# density requirements for poly and metal layers) 5 microns outside of +# drawn layout IF: 1. you have a flattened version of your chip +# 2. over which you paint the special fill layer 'fa', preferably with +# a size that is a multiple of 7 + n * (7 + 4), 3. set 'cif +# ostype fapm-boxes' and cif out to a file (this actually creates the +# fill boxes on cif/strm layer '110' using the magic 'squares' +# command), 4. cif in the resulting file (which creates boxes on magic +# layer 'fapm') and place this cell onto your chip (and verify absence +# of drc errors or shorts), then 5. cif out under your regular cif out +# style, where the 'fapm' layer creates fill boxes on poly and all +# metal layers. + + scalefactor 30 15 + + templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c + or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2 + or fm3,m3,rm3,m3c/m3 + or glass,pad + grow 510 + and fa + + layer 110 fa + squares 0 210 120 + and-not CRIT + shrink 90 + grow 90 + or fapm + labels fapm + calma 110 0 + +style fapm-stripes + scalefactor 30 15 + +# this output style creates the above layer 110 as stripes for reduced size +# HOWEVER it requires each 'fa' box to first be an exact multiple as above +# and then *replacing* the left side (1-lambda wide) stripe of each 'fa' box +# to be a 1-lambda wide layer 'fb' box -- else you won't get strips! + + templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c + or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2 + or fm3,m3,rm3,m3c/m3 + or glass,pad + grow 510 + and fa + + templayer FB fa + or fb + squares 0 210 120 + and-not CRIT + + layer 110 fa + squares 0 210 120 + and-not CRIT + or FB + shrink 90 + grow 90 + or fapm + labels fapm + calma 110 0 + + +style lambda=0.30(cp) + scalefactor 30 15 + + layer CWN nwell,rnw + bloat-or pdiff,rpd,pdc/a,pfet * 180 + bloat-or nsd,nsc/a * 90 + bloat-or nfi * 120 + grow 90 + shrink 90 + labels nwell,rnw + calma 42 0 + + layer CWP pwell + bloat-or ndiff,rnd,ndc/a,nfet * 180 + bloat-or psd,psc/a * 90 + bloat-or pfi * 120 + grow 90 + shrink 90 + and-not CWN + labels pwell + calma 41 0 + + templayer TNS ns + + templayer TPS ps + +#we give priority to selects autogenerated around diffusions (vrs. ohmics) +#XDP = (pdiff*60) Or ps +#XDN = (ndiff*60) Or ns +#FSP = ((pdiff*60,psc*60) Or XDP And-Not XDN Or ps shrink-grow +#FSN = ((ndiff*60,nsc*60) Or XDN And-Not FDP Or ns shrink-grow +#CSN = FSN +#CSP = FSP + +#diffusion auto-nselect (will have priority) + templayer XDN + bloat-or ndiff,rnd,ndc/a * 60 psd,psc/a 0 + or TNS + +#diffusion auto-pselect (will have priority) + templayer XDP + bloat-or pdiff,rpd,pdc/a * 60 nsd,nsc/a 0 + or TPS + +#final pselect + templayer FSP + bloat-or pdiff,rpd,pfet,psd,pdc/a,psc/a,pfet * 60 ndiff,rnd,ndc/a,nsd,nsc/a,nfet 0 + or XDP +#give diff nselect priority + and-not XDN + or TPS + shrink 15 + grow 15 + grow 15 + shrink 15 + +#final nselect + templayer FSN + bloat-or ndiff,rnd,nfet,nsd,ndc/a,nsc/a,nfet * 60 pdiff,rpd,pdc/a,psd,psc/a,pfet 0 + or XDN +#never conflict with final pselect + and-not FSP +#drawn select always goes + or TNS + shrink 15 + grow 15 + grow 15 + shrink 15 + + layer CSN FSN + calma 45 0 + + layer CSP FSP + calma 44 0 + + layer CAA diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + labels diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + calma 43 0 + + layer CCC ndc/m1,nsc/m1 + squares 30 60 90 + calma 25 0 + + layer CCC pdc/m1,psc/m1 + squares 30 60 90 + calma 25 0 + + layer CPG poly,rp,nfet,pfet,fet,pc/a + labels poly,rp,nfet,pfet,fet,pc/a + calma 46 0 + + layer CCC pc/m1 + squares 30 60 90 + calma 25 0 + + layer CCC gc2 + squares 0 60 90 + calma 25 0 + + layer CCC p2c + squares 30 60 90 + calma 25 0 + + layer CCC gc2 + squares 0 60 90 + calma 25 0 + + layer CCC gc + squares 0 60 90 + calma 25 0 + + layer CV1 m2c/m1 + squares 30 60 90 + calma 50 0 + + layer CV1 gv1 + squares 0 60 90 + calma 50 0 + + layer CV2 m3c/m2 + squares 30 60 90 + calma 61 0 + + layer CV2 gv2 + squares 0 60 90 + calma 61 0 + + + templayer XPAD1 pad + shrink 180 + + templayer XPAD2 XPAD1 + shrink 180 + + layer CM3 pad + labels pad + calma 62 0 + + layer CV2 XPAD2 + squares 240 60 300 + calma 61 0 + + layer CM2 pad + labels pad + calma 51 0 + + layer CV1 XPAD2 + squares 60 60 300 + calma 50 0 + + layer CM1 pad + calma 49 0 + + layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + calma 49 0 + + layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2 + labels m2,rm2,m2c/m2,m3c/m2,m3c/m2 + calma 51 0 + + layer CMFP m1p + labels m1p + calma 81 0 + + layer CMSP m2p + labels m2p + calma 82 0 + + layer 100 fp + labels fp + calma 100 0 + + layer 101 fm1 + labels fm1 + calma 101 0 + + layer 102 fm2 + labels fm2 + calma 102 0 + + layer 103 fm3 + labels fm3 + calma 103 0 + + layer 109 fa + or fb + squares 0 210 120 + labels fa + calma 109 0 + + layer 119 fn + calma 119 0 + + layer 110 fapm + labels fapm + calma 110 0 + +# layer CPG fp + layer CPG fp,fapm + squares 0 210 120 + labels fp + calma 46 0 + +# layer CM1 fm1 + layer CM1 fm1,fapm + squares 0 210 120 + labels fm1 + calma 49 0 + +# layer CM2 fm2 + layer CM2 fm2,fapm + + squares 0 210 120 + labels fm2 + calma 51 0 + +# layer CM3 fm3 + layer CM3 fm3,fapm + + squares 0 210 120 + labels fm3 + calma 62 0 + + layer CM3 m3,rm3,m3c/m3 + labels m3,rm3,m3c/m3 + calma 62 0 + + layer CMTP m3p + labels m3p + calma 83 0 + + layer COG pad + shrink 600 + labels pad + calma 52 0 + + layer COG glass + labels glass + calma 52 0 + + layer CFI nfi,pfi + labels nfi,pfi + calma 27 0 + + layer CHR hr,phr + labels hr,phr + calma 34 0 + + layer CEL poly2,ecap,phr,p2c + labels poly2,ecap,phr,p2c + calma 56 0 + +#CRE/CRM + layer CRW rnw,prnw + labels rnw,prnw + calma 65 0 + layer CRG rp,prp + labels rp,prp + calma 67 0 + layer CRD rnd,rpd,prnd,prpd + labels rnd,rpd,prnd,prpd + calma 66 0 + layer CRE rnw,rp,rnd,rpd,rp2 + labels rnw,rp,rnd,rpd,rp2 + calma 64 0 + layer CRF rm1,prm1 + labels rm1,prm1 + calma 71 0 + layer CRS rm2,prm2 + labels rm2,prm2 + calma 72 0 + layer CRG2 rp2,prp2 + labels rp2,prp2 + calma 68 0 + layer CRT rm3,prm3 + labels rm3,prm3 + calma 73 0 +#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3 +#CRE/CRM calma 70 0 + + layer CX comment,bb + labels comment,bb + calma 63 0 + + layer XP pad,xp + labels pad,xp + calma 26 0 + + +style lambda=0.30(c) + scalefactor 30 15 + + layer CWN nwell,rnw + bloat-or pdiff,rpd,pdc/a,pfet * 180 + bloat-or nsd,nsc/a * 90 + bloat-or nfi * 120 + grow 90 + shrink 90 + labels nwell,rnw + calma 42 0 + + templayer TNS ns + + templayer TPS ps + +#we give priority to selects autogenerated around diffusions (vrs. ohmics) +#XDP = (pdiff*60) Or ps +#XDN = (ndiff*60) Or ns +#FSP = ((pdiff*60,psc*60) Or XDP And-Not XDN Or ps shrink-grow +#FSN = ((ndiff*60,nsc*60) Or XDN And-Not FDP Or ns shrink-grow +#CSN = FSN +#CSP = FSP + +#diffusion auto-nselect (will have priority) + templayer XDN + bloat-or ndiff,rnd,ndc/a * 60 psd,psc/a 0 + or TNS + +#diffusion auto-pselect (will have priority) + templayer XDP + bloat-or pdiff,rpd,pdc/a * 60 nsd,nsc/a 0 + or TPS + +#final pselect + templayer FSP + bloat-or pdiff,rpd,pfet,psd,pdc/a,psc/a,pfet * 60 ndiff,rnd,ndc/a,nsd,nsc/a,nfet 0 + or XDP +#give diff nselect priority + and-not XDN + or TPS + shrink 15 + grow 15 + grow 15 + shrink 15 + +#final nselect + templayer FSN + bloat-or ndiff,rnd,nfet,nsd,ndc/a,nsc/a,nfet * 60 pdiff,rpd,pdc/a,psd,psc/a,pfet 0 + or XDN +#never conflict with final pselect + and-not FSP +#drawn select always goes + or TNS + shrink 15 + grow 15 + grow 15 + shrink 15 + + layer CSN FSN + calma 45 0 + + layer CSP FSP + calma 44 0 + + layer CAA diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + labels diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + calma 43 0 + + layer CCC ndc/m1,nsc/m1 + squares 30 60 90 + calma 25 0 + + layer CCC pdc/m1,psc/m1 + squares 30 60 90 + calma 25 0 + + layer CPG poly,rp,nfet,pfet,fet,pc/a + labels poly,rp,nfet,pfet,fet,pc/a + calma 46 0 + + layer CCC pc/m1 + squares 30 60 90 + calma 25 0 + + layer CCC gc2 + squares 0 60 90 + calma 25 0 + + layer CCC p2c + squares 30 60 90 + calma 25 0 + + layer CCC gc2 + squares 0 60 90 + calma 25 0 + + layer CCC gc + squares 0 60 90 + calma 25 0 + + layer CV1 m2c/m1 + squares 30 60 90 + calma 50 0 + + layer CV1 gv1 + squares 0 60 90 + calma 50 0 + + layer CV2 m3c/m2 + squares 30 60 90 + calma 61 0 + + layer CV2 gv2 + squares 0 60 90 + calma 61 0 + + + templayer XPAD1 pad + shrink 180 + + templayer XPAD2 XPAD1 + shrink 180 + + layer CM3 pad + labels pad + calma 62 0 + + layer CV2 XPAD2 + squares 240 60 300 + calma 61 0 + + layer CM2 pad + labels pad + calma 51 0 + + layer CV1 XPAD2 + squares 60 60 300 + calma 50 0 + + layer CM1 pad + calma 49 0 + + layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + calma 49 0 + + layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2 + labels m2,rm2,m2c/m2,m3c/m2,m3c/m2 + calma 51 0 + + layer CMFP m1p + labels m1p + calma 81 0 + + layer CMSP m2p + labels m2p + calma 82 0 + + layer 100 fp + labels fp + calma 100 0 + + layer 101 fm1 + labels fm1 + calma 101 0 + + layer 102 fm2 + labels fm2 + calma 102 0 + + layer 103 fm3 + labels fm3 + calma 103 0 + + layer 109 fa + or fb + squares 0 210 120 + labels fa + calma 109 0 + + layer 119 fn + calma 119 0 + + layer 110 fapm + labels fapm + calma 110 0 + +# layer CPG fp + layer CPG fp,fapm + squares 0 210 120 + labels fp + calma 46 0 + +# layer CM1 fm1 + layer CM1 fm1,fapm + squares 0 210 120 + labels fm1 + calma 49 0 + +# layer CM2 fm2 + layer CM2 fm2,fapm + + squares 0 210 120 + labels fm2 + calma 51 0 + +# layer CM3 fm3 + layer CM3 fm3,fapm + + squares 0 210 120 + labels fm3 + calma 62 0 + + layer CM3 m3,rm3,m3c/m3 + labels m3,rm3,m3c/m3 + calma 62 0 + + layer CMTP m3p + labels m3p + calma 83 0 + + layer COG pad + shrink 600 + labels pad + calma 52 0 + + layer COG glass + labels glass + calma 52 0 + + layer CFI nfi,pfi + labels nfi,pfi + calma 27 0 + + layer CHR hr,phr + labels hr,phr + calma 34 0 + + layer CEL poly2,ecap,phr,p2c + labels poly2,ecap,phr,p2c + calma 56 0 + +#CRE/CRM + layer CRW rnw,prnw + labels rnw,prnw + calma 65 0 + layer CRG rp,prp + labels rp,prp + calma 67 0 + layer CRD rnd,rpd,prnd,prpd + labels rnd,rpd,prnd,prpd + calma 66 0 + layer CRE rnw,rp,rnd,rpd,rp2 + labels rnw,rp,rnd,rpd,rp2 + calma 64 0 + layer CRF rm1,prm1 + labels rm1,prm1 + calma 71 0 + layer CRS rm2,prm2 + labels rm2,prm2 + calma 72 0 + layer CRG2 rp2,prp2 + labels rp2,prp2 + calma 68 0 + layer CRT rm3,prm3 + labels rm3,prm3 + calma 73 0 +#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3 +#CRE/CRM calma 70 0 + + layer CX comment,bb + labels comment,bb + calma 63 0 + + layer XP pad,xp + labels pad,xp + calma 26 0 + + +style lambda=0.30() + scalefactor 30 15 + + layer CWN nwell,rnw + bloat-or pdiff,rpd,pdc/a,pfet * 180 + bloat-or nsd,nsc/a * 90 + bloat-or nfi * 120 + grow 90 + shrink 90 + labels nwell,rnw + calma 42 0 + + templayer TNS ns + + templayer TPS ps + +#we give priority to selects autogenerated around diffusions (vrs. ohmics) +#XDP = (pdiff*60) Or ps +#XDN = (ndiff*60) Or ns +#FSP = ((pdiff*60,psc*60) Or XDP And-Not XDN Or ps shrink-grow +#FSN = ((ndiff*60,nsc*60) Or XDN And-Not FDP Or ns shrink-grow +#CSN = FSN +#CSP = FSP + +#diffusion auto-nselect (will have priority) + templayer XDN + bloat-or ndiff,rnd,ndc/a * 60 psd,psc/a 0 + or TNS + +#diffusion auto-pselect (will have priority) + templayer XDP + bloat-or pdiff,rpd,pdc/a * 60 nsd,nsc/a 0 + or TPS + +#final pselect + templayer FSP + bloat-or pdiff,rpd,pfet,psd,pdc/a,psc/a,pfet * 60 ndiff,rnd,ndc/a,nsd,nsc/a,nfet 0 + or XDP +#give diff nselect priority + and-not XDN + or TPS + shrink 15 + grow 15 + grow 15 + shrink 15 + +#final nselect + templayer FSN + bloat-or ndiff,rnd,nfet,nsd,ndc/a,nsc/a,nfet * 60 pdiff,rpd,pdc/a,psd,psc/a,pfet 0 + or XDN +#never conflict with final pselect + and-not FSP +#drawn select always goes + or TNS + shrink 15 + grow 15 + grow 15 + shrink 15 + + layer CSN FSN + calma 45 0 + + layer CSP FSP + calma 44 0 + + layer CAA diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + labels diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet + calma 43 0 + + layer CCA ndc/m1,nsc/m1 + squares 30 60 90 + calma 48 0 + + layer CCA pdc/m1,psc/m1 + squares 30 60 90 + calma 48 0 + + layer CPG poly,rp,nfet,pfet,fet,pc/a + labels poly,rp,nfet,pfet,fet,pc/a + calma 46 0 + + layer CCP pc/m1 + squares 30 60 90 + calma 47 0 + + layer CCE gc2 + squares 0 60 90 + calma 55 0 + + layer CCE p2c + squares 30 60 90 + calma 55 0 + + layer CCE gc2 + squares 0 60 90 + calma 55 0 + + layer CCC gc + squares 0 60 90 + calma 25 0 + + layer CV1 m2c/m1 + squares 30 60 90 + calma 50 0 + + layer CV1 gv1 + squares 0 60 90 + calma 50 0 + + layer CV2 m3c/m2 + squares 30 60 90 + calma 61 0 + + layer CV2 gv2 + squares 0 60 90 + calma 61 0 + + + templayer XPAD1 pad + shrink 180 + + templayer XPAD2 XPAD1 + shrink 180 + + layer CM3 pad + labels pad + calma 62 0 + + layer CV2 XPAD2 + squares 240 60 300 + calma 61 0 + + layer CM2 pad + labels pad + calma 51 0 + + layer CV1 XPAD2 + squares 60 60 300 + calma 50 0 + + layer CM1 pad + calma 49 0 + + layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 + calma 49 0 + + layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2 + labels m2,rm2,m2c/m2,m3c/m2,m3c/m2 + calma 51 0 + + layer CMFP m1p + labels m1p + calma 81 0 + + layer CMSP m2p + labels m2p + calma 82 0 + + layer 100 fp + labels fp + calma 100 0 + + layer 101 fm1 + labels fm1 + calma 101 0 + + layer 102 fm2 + labels fm2 + calma 102 0 + + layer 103 fm3 + labels fm3 + calma 103 0 + + layer 109 fa + or fb + squares 0 210 120 + labels fa + calma 109 0 + + layer 119 fn + calma 119 0 + + layer 110 fapm + labels fapm + calma 110 0 + +# layer CPG fp + layer CPG fp,fapm + squares 0 210 120 + labels fp + calma 46 0 + +# layer CM1 fm1 + layer CM1 fm1,fapm + squares 0 210 120 + labels fm1 + calma 49 0 + +# layer CM2 fm2 + layer CM2 fm2,fapm + + squares 0 210 120 + labels fm2 + calma 51 0 + +# layer CM3 fm3 + layer CM3 fm3,fapm + + squares 0 210 120 + labels fm3 + calma 62 0 + + layer CM3 m3,rm3,m3c/m3 + labels m3,rm3,m3c/m3 + calma 62 0 + + layer CMTP m3p + labels m3p + calma 83 0 + + layer COG pad + shrink 600 + labels pad + calma 52 0 + + layer COG glass + labels glass + calma 52 0 + + layer CFI nfi,pfi + labels nfi,pfi + calma 27 0 + + layer CHR hr,phr + labels hr,phr + calma 34 0 + + layer CEL poly2,ecap,phr,p2c + labels poly2,ecap,phr,p2c + calma 56 0 + +#CRE/CRM + layer CRW rnw,prnw + labels rnw,prnw + calma 65 0 + layer CRG rp,prp + labels rp,prp + calma 67 0 + layer CRD rnd,rpd,prnd,prpd + labels rnd,rpd,prnd,prpd + calma 66 0 + layer CRE rnw,rp,rnd,rpd,rp2 + labels rnw,rp,rnd,rpd,rp2 + calma 64 0 + layer CRF rm1,prm1 + labels rm1,prm1 + calma 71 0 + layer CRS rm2,prm2 + labels rm2,prm2 + calma 72 0 + layer CRG2 rp2,prp2 + labels rp2,prp2 + calma 68 0 + layer CRT rm3,prm3 + labels rm3,prm3 + calma 73 0 +#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3 +#CRE/CRM calma 70 0 + + layer CX comment,bb + labels comment,bb + calma 63 0 + + layer XP pad,xp + labels pad,xp + calma 26 0 + +end + +cifinput + +style lambda=0.30(p) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + +layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + layer pwell CWP + and-not CTA + labels CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + calma CSN 45 * + + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer ndc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer ndc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer nsc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer nsc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer pdc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer pdc CAA + and CSP + and CCC + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer psc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer psc CAA + and CSP + and CCC + and-not CWNR + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer pc CCP + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCP 47 * + + layer pc CCC + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCC 25 * + + layer gc CCP + and-not CPG + and-not CPC + calma CCP 47 * + + layer gc CCP + and-not CM1 + calma CCP 47 * + + layer gc CCA + and-not COP + and-not CAA + and-not CBA + calma CCA 48 * + + layer gc CCA + and-not COP + and-not CM1 + calma CCA 48 * + + layer gc CCC + and-not COP + and-not CPG + and-not CPC + and-not CEL + and-not CAA + and-not CBA + calma CCC 25 * + + layer gc CCC + and-not COP + and-not CM1 + calma CCC 25 * + + layer gc2 CCE + and-not CPC + and-not CEL + calma CCE 55 * + + layer gc2 CCE + and-not CM1 + calma CCE 55 * + + layer gv1 CV1 + and-not COP + and-not CM1 + calma CV1 50 * + + layer gv1 CV1 + and-not COP + and-not CM2 + calma CV1 50 * + + layer gv2 CV2 + and-not COP + and-not CM2 + calma CV2 61 * + + layer gv2 CV2 + and-not COP + and-not CM3 + calma CV2 61 * + + layer m2c CV1 + and-not XP + grow 30 + and CM2 + and CM1 + grow 15 + shrink 15 + calma CV1 50 * + + layer m1 CM1 + and-not CRM + and-not CRF + and-not XP + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer m2 CM2 + and-not CRM + and-not CRS + and-not XP + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer m3c CV2 + and-not XP + grow 30 + and CM3 + and CM2 + grow 15 + shrink 15 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + and-not XP + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer pad XP + labels pad + calma XP 26 * + + layer glass COG + and-not COP + and-not XP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer elc CCE + grow 30 + and CM1 + and CEL + labels CM1 + calma CCE 55 * + + layer elc CCC + grow 30 + and CM1 + and CEL + labels CM1 + calma CCC 25 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(s) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + + ignore CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer nselect CSN + calma CSN 45 * + + layer pselect CSP + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer ndc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer ndc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer nsc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer nsc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer pdc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer pdc CAA + and CSP + and CCC + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer psc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer psc CAA + and CSP + and CCC + and-not CWNR + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer pc CCP + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCP 47 * + + layer pc CCC + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCC 25 * + + layer gc CCP + and-not CPG + and-not CPC + calma CCP 47 * + + layer gc CCP + and-not CM1 + calma CCP 47 * + + layer gc CCA + and-not COP + and-not CAA + and-not CBA + calma CCA 48 * + + layer gc CCA + and-not COP + and-not CM1 + calma CCA 48 * + + layer gc CCC + and-not COP + and-not CPG + and-not CPC + and-not CEL + and-not CAA + and-not CBA + calma CCC 25 * + + layer gc CCC + and-not COP + and-not CM1 + calma CCC 25 * + + layer gc2 CCE + and-not CPC + and-not CEL + calma CCE 55 * + + layer gc2 CCE + and-not CM1 + calma CCE 55 * + + layer gv1 CV1 + and-not COP + and-not CM1 + calma CV1 50 * + + layer gv1 CV1 + and-not COP + and-not CM2 + calma CV1 50 * + + layer gv2 CV2 + and-not COP + and-not CM2 + calma CV2 61 * + + layer gv2 CV2 + and-not COP + and-not CM3 + calma CV2 61 * + + layer m2c CV1 + and-not XP + grow 30 + and CM2 + and CM1 + grow 15 + shrink 15 + calma CV1 50 * + + layer m1 CM1 + and-not CRM + and-not CRF + and-not XP + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer m2 CM2 + and-not CRM + and-not CRS + and-not XP + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer m3c CV2 + and-not XP + grow 30 + and CM3 + and CM2 + grow 15 + shrink 15 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + and-not XP + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer pad XP + labels pad + calma XP 26 * + + layer glass COG + and-not COP + and-not XP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer elc CCE + grow 30 + and CM1 + and CEL + labels CM1 + calma CCE 55 * + + layer elc CCC + grow 30 + and CM1 + and CEL + labels CM1 + calma CCC 25 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(ps) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + layer pwell CWP + and-not CTA + labels CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer nselect CSN + calma CSN 45 * + + layer pselect CSP + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer ndc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer ndc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer nsc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer nsc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer pdc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer pdc CAA + and CSP + and CCC + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer psc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer psc CAA + and CSP + and CCC + and-not CWNR + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer pc CCP + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCP 47 * + + layer pc CCC + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCC 25 * + + layer gc CCP + and-not CPG + and-not CPC + calma CCP 47 * + + layer gc CCP + and-not CM1 + calma CCP 47 * + + layer gc CCA + and-not COP + and-not CAA + and-not CBA + calma CCA 48 * + + layer gc CCA + and-not COP + and-not CM1 + calma CCA 48 * + + layer gc CCC + and-not COP + and-not CPG + and-not CPC + and-not CEL + and-not CAA + and-not CBA + calma CCC 25 * + + layer gc CCC + and-not COP + and-not CM1 + calma CCC 25 * + + layer gc2 CCE + and-not CPC + and-not CEL + calma CCE 55 * + + layer gc2 CCE + and-not CM1 + calma CCE 55 * + + layer gv1 CV1 + and-not COP + and-not CM1 + calma CV1 50 * + + layer gv1 CV1 + and-not COP + and-not CM2 + calma CV1 50 * + + layer gv2 CV2 + and-not COP + and-not CM2 + calma CV2 61 * + + layer gv2 CV2 + and-not COP + and-not CM3 + calma CV2 61 * + + layer m2c CV1 + and-not XP + grow 30 + and CM2 + and CM1 + grow 15 + shrink 15 + calma CV1 50 * + + layer m1 CM1 + and-not CRM + and-not CRF + and-not XP + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer m2 CM2 + and-not CRM + and-not CRS + and-not XP + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer m3c CV2 + and-not XP + grow 30 + and CM3 + and CM2 + grow 15 + shrink 15 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + and-not XP + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer pad XP + labels pad + calma XP 26 * + + layer glass COG + and-not COP + and-not XP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer elc CCE + grow 30 + and CM1 + and CEL + labels CM1 + calma CCE 55 * + + layer elc CCC + grow 30 + and CM1 + and CEL + labels CM1 + calma CCC 25 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30() + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + + ignore CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + calma CSN 45 * + + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer ndc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer ndc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer nsc CAA + and CSN + and CCA + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer nsc CAA + and CSN + and CCC + and-not CWNR + and-not CTA + + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer pdc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer pdc CAA + and CSP + and CCC + and-not CTA + + and-not CPS + and CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer psc CAA + and CSP + and CCA + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCA 48 * + + layer psc CAA + and CSP + and CCC + and-not CWNR + and-not CTA + + and-not CPS + and-not CWN + and CM1 + grow 30 + grow 15 + shrink 15 + calma CCC 25 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer pc CCP + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCP 47 * + + layer pc CCC + and CPG + and-not CPC + and-not CEL + and-not CAA + grow 30 + and CM1 + grow 15 + shrink 15 + calma CCC 25 * + + layer gc CCP + and-not CPG + and-not CPC + calma CCP 47 * + + layer gc CCP + and-not CM1 + calma CCP 47 * + + layer gc CCA + and-not COP + and-not CAA + and-not CBA + calma CCA 48 * + + layer gc CCA + and-not COP + and-not CM1 + calma CCA 48 * + + layer gc CCC + and-not COP + and-not CPG + and-not CPC + and-not CEL + and-not CAA + and-not CBA + calma CCC 25 * + + layer gc CCC + and-not COP + and-not CM1 + calma CCC 25 * + + layer gc2 CCE + and-not CPC + and-not CEL + calma CCE 55 * + + layer gc2 CCE + and-not CM1 + calma CCE 55 * + + layer gv1 CV1 + and-not COP + and-not CM1 + calma CV1 50 * + + layer gv1 CV1 + and-not COP + and-not CM2 + calma CV1 50 * + + layer gv2 CV2 + and-not COP + and-not CM2 + calma CV2 61 * + + layer gv2 CV2 + and-not COP + and-not CM3 + calma CV2 61 * + + layer m2c CV1 + and-not XP + grow 30 + and CM2 + and CM1 + grow 15 + shrink 15 + calma CV1 50 * + + layer m1 CM1 + and-not CRM + and-not CRF + and-not XP + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer m2 CM2 + and-not CRM + and-not CRS + and-not XP + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer m3c CV2 + and-not XP + grow 30 + and CM3 + and CM2 + grow 15 + shrink 15 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + and-not XP + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer pad XP + labels pad + calma XP 26 * + + layer glass COG + and-not COP + and-not XP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer elc CCE + grow 30 + and CM1 + and CEL + labels CM1 + calma CCE 55 * + + layer elc CCC + grow 30 + and CM1 + and CEL + labels CM1 + calma CCC 25 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(c) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + + ignore CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + calma CSN 45 * + + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer gc2 CCA + and CEL + calma CCA 48 * + + layer gc2 CCP + and CEL + calma CCP 47 * + + layer gc2 CCC + and CEL + calma CCC 25 * + + layer gc2 CCE + and CEL + calma CCE 55 * + + layer gc2 CCA + and CPC + and-not CPG + calma CCA 48 * + + layer gc2 CCP + and CPC + and-not CPG + calma CCP 47 * + + layer gc2 CCC + and CPC + and-not CPG + calma CCC 25 * + + layer gc2 CCE + and CPC + and-not CPG + calma CCE 55 * + + layer gc CCA + and CPG + and-not CEL + calma CCA 48 * + + layer gc CCP + and CPG + and-not CEL + calma CCP 47 * + + layer gc CCC + and CPG + and-not CEL + calma CCC 25 * + + layer gc CCE + and CPG + and-not CEL + calma CCE 55 * + + layer gc CCA + and-not COP + and-not CPC + and-not CEL + calma CCA 48 * + + layer gc CCP + and-not COP + and-not CPC + and-not CEL + calma CCP 47 * + + layer gc CCC + and-not COP + and-not CPC + and-not CEL + calma CCC 25 * + + layer gc CCE + and-not COP + and-not CPC + and-not CEL + calma CCE 55 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer m1 CM1 + and-not CRM + and-not CRF + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer gv1 CV1 + calma CV1 50 * + + layer m2 CM2 + and-not CRM + and-not CRS + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer gv2 CV2 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer xp XP + calma XP 26 * + + layer glass COG + and-not COP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(cs) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + + ignore CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer nselect CSN + calma CSN 45 * + + layer pselect CSP + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer gc2 CCA + and CEL + calma CCA 48 * + + layer gc2 CCP + and CEL + calma CCP 47 * + + layer gc2 CCC + and CEL + calma CCC 25 * + + layer gc2 CCE + and CEL + calma CCE 55 * + + layer gc2 CCA + and CPC + and-not CPG + calma CCA 48 * + + layer gc2 CCP + and CPC + and-not CPG + calma CCP 47 * + + layer gc2 CCC + and CPC + and-not CPG + calma CCC 25 * + + layer gc2 CCE + and CPC + and-not CPG + calma CCE 55 * + + layer gc CCA + and CPG + and-not CEL + calma CCA 48 * + + layer gc CCP + and CPG + and-not CEL + calma CCP 47 * + + layer gc CCC + and CPG + and-not CEL + calma CCC 25 * + + layer gc CCE + and CPG + and-not CEL + calma CCE 55 * + + layer gc CCA + and-not COP + and-not CPC + and-not CEL + calma CCA 48 * + + layer gc CCP + and-not COP + and-not CPC + and-not CEL + calma CCP 47 * + + layer gc CCC + and-not COP + and-not CPC + and-not CEL + calma CCC 25 * + + layer gc CCE + and-not COP + and-not CPC + and-not CEL + calma CCE 55 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer m1 CM1 + and-not CRM + and-not CRF + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer gv1 CV1 + calma CV1 50 * + + layer m2 CM2 + and-not CRM + and-not CRS + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer gv2 CV2 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer xp XP + calma XP 26 * + + layer glass COG + and-not COP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(cps) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + layer pwell CWP + and-not CTA + labels CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer nselect CSN + calma CSN 45 * + + layer pselect CSP + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer gc2 CCA + and CEL + calma CCA 48 * + + layer gc2 CCP + and CEL + calma CCP 47 * + + layer gc2 CCC + and CEL + calma CCC 25 * + + layer gc2 CCE + and CEL + calma CCE 55 * + + layer gc2 CCA + and CPC + and-not CPG + calma CCA 48 * + + layer gc2 CCP + and CPC + and-not CPG + calma CCP 47 * + + layer gc2 CCC + and CPC + and-not CPG + calma CCC 25 * + + layer gc2 CCE + and CPC + and-not CPG + calma CCE 55 * + + layer gc CCA + and CPG + and-not CEL + calma CCA 48 * + + layer gc CCP + and CPG + and-not CEL + calma CCP 47 * + + layer gc CCC + and CPG + and-not CEL + calma CCC 25 * + + layer gc CCE + and CPG + and-not CEL + calma CCE 55 * + + layer gc CCA + and-not COP + and-not CPC + and-not CEL + calma CCA 48 * + + layer gc CCP + and-not COP + and-not CPC + and-not CEL + calma CCP 47 * + + layer gc CCC + and-not COP + and-not CPC + and-not CEL + calma CCC 25 * + + layer gc CCE + and-not COP + and-not CPC + and-not CEL + calma CCE 55 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer m1 CM1 + and-not CRM + and-not CRF + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer gv1 CV1 + calma CV1 50 * + + layer m2 CM2 + and-not CRM + and-not CRS + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer gv2 CV2 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer xp XP + calma XP 26 * + + layer glass COG + and-not COP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + + +style lambda=0.30(cp) + scalefactor 30 + + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + + layer nwell CWN + and-not CWNR + and-not CTA + labels CWN + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRE + and-not CSB + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer rnw CWN + and-not CWNR + and CRW + and-not CRD + and-not CAA + and-not CPG + calma CWN 42 * + + layer pseudo_rnwell CRW + and-not CRE + calma CRW 65 * + + layer pwell CWP + and-not CTA + labels CWP + calma CWP 41 * + + layer diff CAA + and-not CTA + and-not CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + layer tran CAA + and-not CTA + and CPG + and-not CWNR + and-not COP + and-not CSN + and-not CSP + labels CAA + calma CAA 43 * + + calma CSN 45 * + + calma CSP 44 * + + layer ndiff CAA + and CSN + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRE + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer rnd CAA + and CSN + and-not CWNR + and CRD + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rndiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and-not CWN + and-not CSP + and CSN + and-not CBA + calma CRD 66 * + + layer pdiff CAA + and CSP + and-not CWNR + and-not CTA + and-not CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRE + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer rpd CAA + and CSP + and-not CWNR + and CRD + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CAA 43 * + + layer pseudo_rpdiff CRD + and-not CRE + and-not CAA + and-not CSB + and-not CPG + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + calma CRD 66 * + + layer nfet CAA + and CSN + and-not CWNR + and-not CTA + and CPG + and-not CEL + and-not CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer pfet CAA + and CSP + and-not CWNR + and-not CTA + and CPG + and-not CEL + and CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer nsd CAA + and CSN + and-not CWNR + and-not CTA + and CWN + and-not CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer psd CAA + and CSP + and-not CWNR + and-not CTA + and-not CWN + and-not CSN + and-not CPS + and CSP + and-not CBA + labels CAA + calma CAA 43 * + + layer gc2 CCA + and CEL + calma CCA 48 * + + layer gc2 CCP + and CEL + calma CCP 47 * + + layer gc2 CCC + and CEL + calma CCC 25 * + + layer gc2 CCE + and CEL + calma CCE 55 * + + layer gc2 CCA + and CPC + and-not CPG + calma CCA 48 * + + layer gc2 CCP + and CPC + and-not CPG + calma CCP 47 * + + layer gc2 CCC + and CPC + and-not CPG + calma CCC 25 * + + layer gc2 CCE + and CPC + and-not CPG + calma CCE 55 * + + layer gc CCA + and CPG + and-not CEL + calma CCA 48 * + + layer gc CCP + and CPG + and-not CEL + calma CCP 47 * + + layer gc CCC + and CPG + and-not CEL + calma CCC 25 * + + layer gc CCE + and CPG + and-not CEL + calma CCE 55 * + + layer gc CCA + and-not COP + and-not CPC + and-not CEL + calma CCA 48 * + + layer gc CCP + and-not COP + and-not CPC + and-not CEL + calma CCP 47 * + + layer gc CCC + and-not COP + and-not CPC + and-not CEL + calma CCC 25 * + + layer gc CCE + and-not COP + and-not CPC + and-not CEL + calma CCE 55 * + + layer poly CPG + and-not CRE + labels CPG + calma CPG 46 * + + layer rp CPG + and CRE + and-not CSB + calma CPG 46 * + + layer rp CPG + and CRG + calma CPG 46 * + + layer pseudo_rpoly CRG + and-not CRE + calma CRG 67 * + + layer m1 CM1 + and-not CRM + and-not CRF + labels CM1 + calma CM1 49 * + + layer rm1 CRM + and CM1 + calma CRM 70 * + + layer rm1 CRF + and CM1 + calma CRF 71 * + + layer pseudo_rmetal1 CRF + and-not rm1 + calma CRF 71 * + + layer m1p CMFP + labels CMFP + calma CMFP 81 * + + layer gv1 CV1 + calma CV1 50 * + + layer m2 CM2 + and-not CRM + and-not CRS + labels CM2 + calma CM2 51 * + + layer rm2 CRM + and CM2 + calma CRM 70 * + + layer rm2 CRS + and CM2 + calma CRS 72 * + + layer pseudo_rmetal2 CRS + and-not rm2 + calma CRS 72 * + + layer m2p CMSP + labels CMSP + calma CMSP 82 * + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + + layer gv2 CV2 + calma CV2 61 * + + layer m3 CM3 + and-not CRM + and-not CRT + labels CM3 + calma CM3 62 * + + layer rm3 CRM + and CM3 + calma CRM 70 * + + layer rm3 CRT + and CM3 + calma CRT 73 * + + layer pseudo_rmetal3 CRT + and-not rm3 + calma CRT 73 * + + layer m3p CMTP + labels CMTP + calma CMTP 83 * + + layer xp XP + calma XP 26 * + + layer glass COG + and-not COP + labels COG + calma COG 52 * + + layer nfi CFI + and CWN + labels CFI + calma CFI 27 * + + layer pfi CFI + and-not CWN + labels CFI + calma CFI 27 * + + layer hr CHR + labels CHR + calma CHR 34 * + + layer phr CEL + and CHR + calma CEL 56 * + + layer ecap CEL + and CPG + labels CEL + calma CEL 56 * + + layer poly2 CEL + and-not CPG + labels CEL + calma CEL 56 * + + layer rp2 CEL + and CRG2 + calma CEL 56 * + + layer pseudo_rpoly2 CRG2 + and-not CRE + calma CRG2 68 * + + layer comment CX + labels CX + calma CX 63 * + + calma CTA 60 * + + calma CRW 65 * + calma CRG 67 * + calma CRD 66 * + calma CRE 64 * + calma CRF 71 * + calma CRS 72 * + calma CRT 73 * + calma CRM 70 * + +style fill-only + scalefactor 30 +# scalefactor 100 + + layer fp 100 + calma 100 100 * + + layer fm1 101 + calma 101 101 * + + layer fm2 102 + calma 102 102 * + + layer fm3 103 + calma 103 103 * + + layer fa 109 + or fb + calma 109 109 * + + layer fn 119 + calma 119 119 * + + layer fapm 110 + calma 110 110 * + +end + +mzrouter + style irouter +# layer hCost vCost jogCost hintCost + layer metal3 1 2 2 1 + layer metal2 2 1 2 1 + layer metal1 2 3 2 1 + layer poly 10 10 11 1 + contact m3contact metal3 metal2 5 + contact m2contact metal2 metal1 6 + contact pcontact metal1 poly 7 + notactive poly pcontact + +style garouter + layer m2 32 64 256 1 + layer m1 64 32 256 1 + contact m2contact metal1 metal2 1024 + +end + +drc + width nwell 12 \ + "N-well width < 12 (Mosis #1.1)" + + width rnw 12 \ + "rnwell (for resistor L/W extraction) width < 12 (Mosis #1.1)" + + width pwell 12 \ + "P-well width < 12 (Mosis #1.1)" + + width diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a 3 \ + "Diffusion width < 3 (Mosis #2.1)" + + width poly,fp,rp,pc/a,nfet,pfet,fet 2 \ + "Poly width < 2 (Mosis #3.1)" + + width nselect 2 \ + "N-Select width < 2 (Mosis #4.4)" + + width pselect 2 \ + "P-Select width < 2 (Mosis #4.4)" + + width pc/m1 4 \ + "Poly contact width < 4 (Mosis #5.1)" + + width gc 2 \ + "GC contact width < 2 (Mosis #6.1)" + + width ndc/m1 4 \ + "Diffusion contact width < 4 (Mosis #6.1)" + + width nsc/m1 4 \ + "Diffusion contact width < 4 (Mosis #6.1)" + + width pdc/m1 4 \ + "Diffusion contact width < 4 (Mosis #6.1)" + + width psc/m1 4 \ + "Diffusion contact width < 4 (Mosis #6.1)" + + width m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3 \ + "Metal1 width < 3 (Mosis #7.1)" + + width gv1 2 \ + "GV1 via width < 2 (Mosis #8.1)" + + width m2c/m1 4 \ + "Metal2 contact width < 4 (Mosis #8.1)" + + width m2,fm2,rm2,m2c/m2,m3c/m2 3 \ + "Metal2 width < 3 (Mosis #9.1)" + + width ecap 8 \ + "Ecap width < 8 (Mosis #11.1)" + + width poly2,ecap,phr 5 \ + "Poly2 width < 5 (Mosis #11.1)" + + width gc2 2 \ + "Generic contact2 width < 2 (Mosis #13.1)" + + width p2c 4 \ + "Poly2 contact width < 4 (Mosis #13.1)" + + width gv2 2 \ + "GV2 via width < 2 (Mosis #14.1)" + + width m3c/m2 4 \ + "Metal3 contact width < 4 (Mosis #14.1)" + + width m3,fm3,rm3,m3c/m3,pad 5 \ + "Metal3 width < 5 (Mosis #15.1)" + + width hr,phr 4 \ + "High-Resist width < 4 (Mosis #27.1)" + + width phr 5 \ + "High-Resist poly2R width < 5 (Mosis #27.7)" + + width nfi,pfi 4 \ + "N/P_field-implant width < 4 (Mosis #29.1)" + + spacing nwell nwell 6 touching_ok \ + "N-well(at-same-potential) spacing < 6 (Mosis #1.3)" + + spacing pwell pwell 6 touching_ok \ + "P-well(at-same-potential) spacing < 6 (Mosis #1.3)" + + spacing rnw nwell 18 touching_illegal \ + "rnw (for resistor L/W extraction) spacing to N-well < 18 (Mosis #2.3)" + + edge4way ~(pwell)/well pwell 1 ~(rnw)/active 0 0 \ + "P-well cannot touch rnw (for resistor L/W extraction) (Mosis #1.4)" active + + spacing diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a 3 touching_ok \ + "Diffusion spacing < 3 (Mosis #2.2)" + + spacing nwell ndiff,rnd,nfet,ndc/a 6 touching_illegal \ + "N-well spacing to N-Diffusion < 6 (Mosis #2.3)" + + spacing pwell pdiff,rpd,pfet,pdc/a 6 touching_illegal \ + "P-well spacing to P-Diffusion < 6 (Mosis #2.3)" + + spacing ndiff,rnd,nfet,ndc/a pdiff,rpd,pfet,pdc/a 12 touching_illegal \ + "N-Diffusion spacing to P-Diffusion < 12 (Mosis #2.3+2.3)" + + edge4way ~(nwell)/well nwell 6 ~(pdiff,rpd,pfet,pdc/a)/active nwell 6 \ + "N-well overlap of P-Diffusion < 6 (Mosis #2.4)" active + + edge4way ~(pwell)/well pwell 6 ~(ndiff,rnd,nfet,ndc/a)/active pwell 6 \ + "P-well overlap of N-Diffusion < 6 (Mosis #2.4)" active + + edge4way ~(nwell)/well nwell 3 ~(nsd,nsc/a)/active nwell 3 \ + "N-well overlap of N-Ohmic < 3 (Mosis #2.4)" active + + edge4way ~(pwell)/well pwell 3 ~(psd,psc/a)/active pwell 3 \ + "P-well overlap of P-Ohmic < 3 (Mosis #2.4)" active + + spacing ndiff,rnd,ndc/a nsd,nsc/a 9 touching_illegal \ + "N-Diffusion spacing to N-Ohmic < 9 (Mosis #2.3+2.4)" + + spacing pdiff,rpd,pdc/a psd,psc/a 9 touching_illegal \ + "P-Diffusion spacing to P-Ohmic < 9 (Mosis #2.3+2.4)" + + spacing nwell psd,psc/a 3 touching_illegal \ + "N-well spacing to P-Ohmic < 3 (Mosis #2.4)" + + spacing pwell nsd,nsc/a 3 touching_illegal \ + "P-well spacing to N-Ohmic < 3 (Mosis #2.4)" + + spacing psd,psc/a rnw,prnw 3 touching_illegal \ + "P-Ohmic spacing to rnw,prnw < 3 (Mosis #2.4)" + + spacing nsd,nsc/a psd,psc/a 6 touching_illegal \ + "N-Ohmic spacing to P-Ohmic < 6 (Mosis #2.4+2.4)" + + spacing ndiff,rnd,nfet,ndc/a,nfet psd,psc/a 4 touching_ok \ + "N-Diffusion spacing to P-Ohmic < 4 (Mosis #2.5)" + + spacing pdiff,rpd,pfet,pdc/a,pfet nsd,nsc/a 4 touching_ok \ + "P-Diffusion spacing to N-Ohmic < 4 (Mosis #2.5)" + + spacing poly,rp,pc/a,nfet,pfet,fet poly,rp,pc/a,nfet,pfet,fet 3 touching_ok \ + "Poly spacing < 3 (Mosis #3.2)" + + spacing poly,rp,pc/a,nfet,pfet,fet fp,fapm 3 touching_illegal \ + "Poly spacing to fill layer (fp) < 3 (Mosis #3.2)" + + spacing fp fp 4 touching_ok \ + "Poly fill layer (fp) spacing < 4 (Mosis #0)" + + edge4way nfet,pfet,fet space/active,poly,fp,rp,pc/a 2 poly,fp,rp,pc/a 0 0 \ + "Poly overhang of Transistor < 2 (Mosis #3.3)" active + + edge4way nfet,pfet,fet space/active,ndiff,rnd,ndc/a,pdiff,rpd,pdc/a 3 ndiff,rnd,ndc/a,pdiff,rpd,pdc/a,nfet,pfet,fet 0 0 \ + "N-Diffusion,P-Diffusion overhang of Transistor < 3 (Mosis #3.4)" active + + edge4way poly,fp,rp,pc/a ~(poly,fp,rp,pc/a,nfet,pfet,fet,prp)/active 1 space/a space/a 1 \ + "Poly spacing to Diffusion < 1 (Mosis #3.5)" + + edge4way nfet ~(nfet)/active 3 ~(pselect)/select ~(nfet)/active 3 \ + "N-Transistor space to P-Select < 3 (Mosis #4.1)" select + + edge4way pfet ~(pfet)/active 3 ~(nselect)/select ~(pfet)/active 3 \ + "P-Transistor space to N-Select < 3 (Mosis #4.1)" select + + edge4way nfet ~(nfet)/active 3 ~(psd,psc/a)/active ~(nfet)/active 2 \ + "N-Transistor space to P-Ohmic < 3 (Mosis #4.1)" active + + edge4way pfet ~(pfet)/active 3 ~(nsd,nsc/a)/active ~(pfet)/active 2 \ + "P-Transistor space to N-Ohmic < 3 (Mosis #4.1)" active + +#PEZ edge4way psd,psc/a space ~(nfet)/active space \ +#PEZ "P-Ohmic space to N-Transistor < (Mosis #4.1)" active + +#PEZ edge4way nsd,nsc/a space ~(pfet)/active space \ +#PEZ "N-Ohmic space to P-Transistor < (Mosis #4.1)" active + + edge4way ~(nselect,pselect)/select nselect,pselect 2 ~(diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a)/active nselect,pselect 2 \ + "N-Select,P-Select overlap of Diffusion < 2 (Mosis #4.2_)" active + + edge4way space nselect,pselect 2 ~(ndiff,rnd,nfet,ndc/a)/active nselect 2 \ + "N-Select space to N-Diffusion < 2 (Mosis #4.2a)" active + + edge4way nselect,pselect space 2 ~(ndiff,rnd,nfet,ndc/a)/active nselect 2 \ + "N-Select space to N-Diffusion < 2 (Mosis #4.2b)" active + + edge4way nselect,pselect space 2 ~(ndiff,rnd,nfet,ndc/a)/active space,nselect,pselect 2 \ + "N-Select space to N-Diffusion < 2 (Mosis #4.2c)" active + + edge4way space nselect,pselect 2 ~(pdiff,rpd,pfet,pdc/a)/active pselect 2 \ + "P-Select space to P-Diffusion < 2 (Mosis #4.2aa)" active + + edge4way nselect,pselect space 2 ~(pdiff,rpd,pfet,pdc/a)/active pselect 2 \ + "P-Select space to P-Diffusion < 2 (Mosis #4.2bb)" active + + edge4way nselect,pselect space 2 ~(pdiff,rpd,pfet,pdc/a)/active space,nselect,pselect 2 \ + "P-Select space to P-Diffusion < 2 (Mosis #4.2cc)" active + + edge4way diff space 2 nselect space 2 \ + "N-Select must overlap Diffusion by 2 (Mosis #4.2)" select + + edge4way diff space 2 pselect space 2 \ + "P-Select must overlap Diffusion by 2 (Mosis #4.2)" select + + edge4way ndiff,rnd,nfet,ndc/a space 2 ~(pselect)/select space 2 \ + "P-Select space to N-Diffusion < 2 (Mosis #4.2e)" select + + edge4way pdiff,rpd,pfet,pdc/a space 2 ~(nselect)/select space 2 \ + "N-Select space to P-Diffusion < 2 (Mosis #4.2e)" select + + edge4way ~(pdiff,rpd,pfet,pdc/a,psd,psc/a)/active pdiff,rpd,pfet,pdc/a,psd,psc/a 1 ~(nselect)/select 0 0 \ + "N-Select cannot touch P-Diffusion,P-Ohmic (Mosis #4.2f)" select + + edge4way ~(ndiff,rnd,nfet,ndc/a,nsd,nsc/a)/active ndiff,rnd,nfet,ndc/a,nsd,nsc/a 1 ~(pselect)/select 0 0 \ + "P-Select cannot touch N-Diffusion,N-Ohmic (Mosis #4.2f)" select + + width nsd,nsc/a,psd,psc/a 2 \ + "N-Ohmic,P-Ohmic width < 2 (Mosis #4.1)" + + spacing nselect nselect 2 touching_ok \ + "N-Select spacing < 2 (Mosis #4.4)" + + spacing pselect pselect 2 touching_ok \ + "P-Select spacing < 2 (Mosis #4.4)" + + edge4way ndiff,rnd,ndc/a psd,psc/a 2 ~(ndiff,rnd,ndc/a)/active 0 0 \ + "P-Ohmic(that touches N-Diffusion) width < 2 (Mosis #4.4)" + + edge4way pdiff,rpd,pdc/a nsd,nsc/a 2 ~(pdiff,rpd,pdc/a)/active 0 0 \ + "N-Ohmic(that touches P-Diffusion) width < 2 (Mosis #4.4)" + + edge4way gc ~(gc)/contact 1 poly,fp,rp,pc/a,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a ~(gc)/contact 1 \ + "Poly,Diffusion overlap of GC contact < 1 (Mosis #5.2)" active + + edge4way gc space 1 poly,fp,rp,pc/a,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a space 1 \ + "one of: Poly,Diffusion must overlap GC contact by 1 (Mosis #5.2a,6.2a)" active + + edge4way ~(poly,fp,rp,pc/a,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a)/active poly,fp,rp,pc/a,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a 1 ~(gc)/contact 0 0 \ + "Edge to one of: Poly,Diffusion cannot touch GC contact (Mosis #5.2a,6.2a)" contact + + spacing gc gc 3 touching_ok \ + "Generic contact spacing < 3 (Mosis #5.3)" + + edge4way ~(gc)/contact gc 1 ~(ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c)/metal1 0 0 \ + "GC contact cannot touch Metal1 contacts (Mosis #0)" metal1 + + spacing gv1 m2c/m2 2 touching_illegal \ + "GV1 via spacing to Metal2 contacts < 2 (Mosis #14.2)" + + spacing poly,fp,rp,pc/a pc/a 4 touching_ok \ + "Poly spacing to Poly contact < 4 (Mosis #5.5.b)" + + edge4way gc ~(gc)/contact 1 diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,poly,fp,rp,pc/a ~(gc)/contact 1 \ + "Diffusion,Poly overlap of GC contact < 1 (Mosis #6.2)" active + + spacing gc pc/a,ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \ + "Generic contact spacing to Poly contact,Diffusion contact < 2 (Mosis #5.3)" + + spacing nsc/m1 pdc/m1 1 touching_illegal \ + "nsc spacing to pdc < 1 (Mosis #6.3)" + + spacing psc/m1 ndc/m1 1 touching_illegal \ + "psc spacing to ndc < 1 (Mosis #6.3)" + + spacing nfet,pfet ndc/a,pdc/a,psc/a,nsc/a 1 touching_illegal \ + "N-Transistor,P-Transistor spacing to Diffusion contact < 1 (Mosis #6.4)" + + spacing nfet,pfet gc 2 touching_illegal \ + "N-Transistor,P-Transistor spacing to Generic contact < 2 (Mosis #6.4)" + + spacing diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a pc/a 1 touching_illegal \ + "Diffusion spacing to Poly contact < 1 (Mosis #6.5.b)" + + spacing diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,nfet,pfet ndc/a,pdc/a,psc/a,nsc/a 4 touching_ok \ + "Diffusion spacing to Diffusion contact < 4 (Mosis #6.5.b)" + + spacing pc/a ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \ + "pc/a spacing to ndc/a,pdc/a,psc/a,nsc/a < 2 (Mosis #6.7)" + + spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3 touching_ok \ + "Metal1 spacing < 3 (Mosis #7.2)" + + spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 fm1,fapm 3 touching_illegal \ + "Metal1 spacing to fill layer (fm1) < 3 (Mosis #7.2)" + + spacing fm1 fm1 4 touching_ok \ + "Metal1 fill layer (fm1) spacing < 4 (Mosis #0)" + + edge4way gc space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \ + "Metal1 must overlap GC contact by 1 (Mosis #7.3,7.4)" metal1 + + edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gc)/contact 0 0 \ + "Metal1(edge) cannot touch GC contact (Mosis #7.3+7.4)" contact + + spacing gv1 gv1 3 touching_ok \ + "GV1 via spacing < 3 (Mosis #8.2)" + + edge4way gv1 ~(gv1)/via1 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 ~(gv1)/via1 1 \ + "Metal1 overlap of GV1 via < 1 (Mosis #8.3)" metal1 + + edge4way gv1 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \ + "Metal1 must overlap GV1 via by 1 (Mosis #8.3)" metal1 + + edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gv1)/via1 0 0 \ + "Metal1(edge) cannot touch GV1 via (Mosis #8.3)" via1 + + spacing gc gv1 2 touching_illegal \ + "GC contact spacing to GV1 via < 2 (Mosis #8.4)" + + spacing gc m2c/m2 2 touching_illegal \ + " spacing to Metal2 contacts < 2 (Mosis #14.2)" + + spacing gc m2c/m2 2 touching_illegal \ + "GC contact spacing to Metal2 contacts < 2 (Mosis #8.4)" + + spacing m2,rm2,m2c/m2,m3c/m2 m2,rm2,m2c/m2,m3c/m2 3 touching_ok \ + "Metal2 spacing < 3 (Mosis #9.2)" + + spacing m2,rm2,m2c/m2,m3c/m2 fm2,fapm 3 touching_illegal \ + "Metal2 spacing to fill layer (fm2) < 3 (Mosis #9.2)" + + spacing fm2 fm2 4 touching_ok \ + "Metal2 fill layer (fm2) spacing < 4 (Mosis #0)" + + edge4way gv1 space 1 m2,fm2,rm2,m2c/m2,m3c/m2 space 1 \ + "Metal2 must overlap GV1 via by 1 (Mosis #9.3)" metal2 + + edge4way ~(m2,fm2,rm2,m2c/m2,m3c/m2)/metal2 m2,fm2,rm2,m2c/m2,m3c/m2 1 ~(gv1)/via1 0 0 \ + "Metal2(edge) cannot touch GV1 via (Mosis #9.3)" via1 + + width glass 10 \ + "COG width < 10 (Mosis #10.2)" + + edge4way ~(pad)/metal3 pad 20 ~(glass)/oxide pad 20 \ + "pad overlap of COG < 20 (Mosis #10.3)" oxide + + spacing ecap ecap 3 touching_ok \ + "Ecap spacing < 3 (Mosis #11.2)" + + edge4way ecap ~(ecap)/cap 5 poly,fp,rp,pc/a ~(ecap)/cap 5 \ + "Poly overlap of Ecap < 5 (Mosis #11.3)" active + + edge4way ~(ecap)/cap ecap 1 poly,fp,rp,pc/a 0 0 \ + "Ecap must touch Poly (Mosis #11.3x)" active + + edge4way poly2,phr space 5 ~(poly,fp,rp,pc/a)/active space 5 \ + "Poly2 spacing to Poly < 5 (Mosis #11.3c)" active + + spacing ecap pc/a 2 touching_illegal \ + "Ecap spacing to Poly contact < 2 (Mosis #11.5)" + + spacing ecap gc 3 touching_illegal \ + "Ecap spacing to Generic contact < 3 (Mosis #11.5)" + + spacing poly2,ecap,phr poly2,ecap,phr 3 touching_ok \ + "Poly2 spacing < 3 (Mosis #11.2)" + + spacing poly2,ecap,phr pc/a,ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \ + "Poly2 spacing to Poly contact,Diffusion contact < 2 (Mosis #11.5)" + + spacing poly2,ecap,phr gc,gc 3 touching_illegal \ + "Poly2 spacing to GC contact < 3 (Mosis #11.5)" + + spacing gc2 gc2 3 touching_ok \ + "Generic contact2 spacing < 3 (Mosis #13.2)" + + edge4way ~(ecap)/cap ecap 3 ~(gc2)/contact ecap 3 \ + "Ecap overlap of Generic contact2 < 3 (Mosis #13.3)" contact + + edge4way ~(ecap)/cap ecap 2 ~(p2c)/metal1 ecap 2 \ + "Ecap overlap of Poly2 contact < 2 (Mosis #13.3)" metal1 + + edge4way gc2 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \ + "Metal1 must overlap Generic contact2 by 1 (Mosis #13.4)" metal1 + + edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gc2)/contact 0 0 \ + "Metal1(edge) cannot touch Generic contact2 (Mosis #13.4)" contact + + edge4way ~(poly2,ecap,phr)/cap poly2,ecap,phr 1 ~(p2c)/metal1 poly2,ecap,phr 1 \ + "Poly2 overlap of Poly2 contact < 1 (Mosis #13.4)" metal1 + + spacing gv2 gv2 3 touching_ok \ + "GV2 via spacing < 3 (Mosis #14.2)" + + spacing gv2 m3c/m2 2 touching_illegal \ + "GV2 via spacing to Metal3 contact < 2 (Mosis #14.2)" + + edge4way gv2 space 1 m2,fm2,rm2,m2c/m2,m3c/m2 space 1 \ + "Metal2 must overlap GV2 via by 1 (Mosis #14.3)" metal2 + + edge4way ~(m2,fm2,rm2,m2c/m2,m3c/m2)/metal2 m2,fm2,rm2,m2c/m2,m3c/m2 1 ~(gv2)/via2 0 0 \ + "Metal2(edge) cannot touch GV2 via (Mosis #14.3)" via2 + + spacing gv1 gv2 2 touching_illegal \ + "GV1 via spacing to GV2 via < 2 (Mosis #14.4)" + + spacing gv1 m3c/m2 1 touching_illegal \ + "GV1 via spacing to Metal3 contact < 1 (Mosis #14.4)" + + spacing m3,rm3,m3c/m3,pad m3,rm3,m3c/m3,pad 3 touching_ok \ + "Metal3 spacing < 3 (Mosis #15.2)" + + spacing m3,rm3,m3c/m3,pad fm3,fapm 3 touching_illegal \ + "Metal3 spacing to fill layer (fm3) < 3 (Mosis #15.2)" + + spacing fm3 fm3 4 touching_ok \ + "Metal3 fill layer (fm3) spacing < 4 (Mosis #0)" + + edge4way m3c/m2 ~(m3c/m2)/metal2 1 m3,fm3,rm3,m3c/m3,pad ~(m3c/m2)/metal2 1 \ + "Metal3 overlap of Metal3 contact < 1 (Mosis #15.3)" metal3 + + edge4way gv2 space 2 m3,fm3,rm3,m3c/m3,pad space 2 \ + "Metal3 must overlap GV2 via by 2 (Mosis #15.3)" metal3 + + edge4way ~(m3,fm3,rm3,m3c/m3,pad)/metal3 m3,fm3,rm3,m3c/m3,pad 1 ~(gv2)/via2 0 0 \ + "Metal3(edge) cannot touch GV2 via (Mosis #15.3)" via2 + + spacing hr,phr hr,phr 4 touching_ok \ + "High-Resist spacing < 4 (Mosis #27.2)" + + spacing hr,phr,phr p2c 2 touching_illegal \ + "High-Resist spacing to Poly2 contact < 2 (Mosis #27.3)" + + spacing hr,phr,phr gc 2 touching_illegal \ + "High-Resist spacing to GC contact < 2 (Mosis #27.3)" + + edge4way hr,phr space 2 ~(ndiff,rnd,ndc/a,pdiff,rpd,pdc/a)/active 0 2 \ + "High-Resist space to Diffusion < 2 (Mosis #27.4)" active + + spacing hr,phr,phr poly2,ecap,phr 2 touching_ok \ + "High-Resist spacing to other Poly2 < 2 (Mosis #27.5)" + + edge4way hr,phr space 2 ~(poly2,ecap,phr)/contact hr,phr 2 \ + "High-Resist space to Poly2 < 2 (Mosis #27.5x)" contact + + spacing nwell phr 4 touching_illegal \ + "N-well spacing to Silicide-Block poly2R < 4 (Mosis #27.6)" + + spacing phr phr 7 touching_ok \ + "High-Resist poly2R spacing < 7 (Mosis #27.13)" + + edge4way phr space/active,hr 2 hr hr 2 \ + "High-Resist overlap of High-Resist poly2R < 2 (Mosis #27.15)" + + spacing nfi nfi 4 touching_ok \ + "N_field-implant spacing < 4 (Mosis #35.2)" + + spacing pfi pfi 4 touching_ok \ + "P_field-implant spacing < 4 (Mosis #35.2)" + + spacing nfi pfi 4 touching_illegal \ + "N_field-implant spacing to P_field-implant < 4 (Mosis #35.2)" + + spacing nwell,pdiff,rpd,pfet,pdc/a pfi 4 touching_illegal \ + "N-well,P-Diffusion spacing to P_field-implant < 4 (Mosis #2.1)" + + spacing pwell,ndiff,rnd,nfet,ndc/a nfi 4 touching_illegal \ + "P-well,N-Diffusion spacing to N_field-implant < 4 (Mosis #2.1)" + + edge4way ~(nwell)/well nwell 4 ~(nfi)/implant nwell 4 \ + "N-well overlap of N_field-implant < 4 (Mosis #21.2)" implant + + edge4way ~(pwell)/well pwell 4 ~(pfi)/implant pwell 4 \ + "P-well overlap of P_field-implant < 4 (Mosis #21.2)" implant + + spacing fa fapm 4 touching_illegal \ + "fill layer fa spacing to fill layer fapm < 4 (Mosis #0)" + + width fa 7 \ + "filla width < 7 (Mosis #0)" + + width fapm 7 \ + "fillapm width < 7 (Mosis #0)" + + width fp 7 \ + "fillp width < 7 (Mosis #0)" + + width fm1 7 \ + "fillm1 width < 7 (Mosis #0)" + + width fm2 7 \ + "fillm2 width < 7 (Mosis #0)" + + width fm3 7 \ + "fillm3 width < 7 (Mosis #0)" + + edge4way fa ~(fa)/fill 1 ~(fa)/fill (~(fa),fa)/fill 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fb ~(fb)/fill 1 ~(fb)/fill (~(fb),fb)/fill 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fapm ~(fapm)/active 1 ~(fapm)/active (~(fapm),fapm)/active 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fp ~(fp)/active 1 ~(fp)/active (~(fp),fp)/active 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fm1 ~(fm1)/metal1 1 ~(fm1)/metal1 (~(fm1),fm1)/metal1 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fm2 ~(fm2)/metal2 1 ~(fm2)/metal2 (~(fm2),fm2)/metal2 1 \ + "Contact not rectangular (Magic rule)" + + edge4way fm3 ~(fm3)/metal3 1 ~(fm3)/metal3 (~(fm3),fm3)/metal3 1 \ + "Contact not rectangular (Magic rule)" + + edge4way rp space/active 1 prp 0 0 \ + "prp overhang of rpoly (for resistor L/W extraction) < 1 (Mosis #0)" active + + edge4way rp2 space/cap 1 prp2 0 0 \ + "prp2 overhang of rpoly2 (for resistor L/W extraction) < 1 (Mosis #0)" cap + + edge4way rnw space/active 1 prnw 0 0 \ + "prnw overhang of rnwell (for resistor L/W extraction) < 1 (Mosis #0)" active + + edge4way rpd space/active 1 prpd 0 0 \ + "prpd overhang of rpdiff (for resistor L/W extraction) < 1 (Mosis #0)" active + + edge4way rnd space/active 1 prnd 0 0 \ + "prnd overhang of rndiff (for resistor L/W extraction) < 1 (Mosis #0)" active + + edge4way rm1 space/metal1 1 prm1 0 0 \ + "prm1 overhang of rmetal1 (for resistor L/W extraction) < 1 (Mosis #0)" metal1 + + edge4way rm2 space/metal2 1 prm2 0 0 \ + "prm2 overhang of rmetal2 (for resistor L/W extraction) < 1 (Mosis #0)" metal2 + + edge4way rm3 space/metal3 1 prm3 0 0 \ + "prm3 overhang of rmetal3 (for resistor L/W extraction) < 1 (Mosis #0)" metal3 + + edge4way ndc/a,nsc/a ~(ndc/a,nsc/a)/active 1 ~(ndc/a,nsc/a)/active (~(ndc/a,nsc/a),ndc/a,nsc/a)/active 1 \ + "Contact not rectangular (Magic rule)" + + edge4way pdc/a,psc/a ~(pdc/a,psc/a)/active 1 ~(pdc/a,psc/a)/active (~(pdc/a,psc/a),pdc/a,psc/a)/active 1 \ + "Contact not rectangular (Magic rule)" + + edge4way pc/a ~(pc/a)/active 1 ~(pc/a)/active (~(pc/a),pc/a)/active 1 \ + "Contact not rectangular (Magic rule)" + + edge4way gc2 ~(gc2)/contact 1 ~(gc2)/contact (~(gc2),gc2)/contact 1 \ + "Contact not rectangular (Magic rule)" + + edge4way p2c ~(p2c)/metal1 1 ~(p2c)/metal1 (~(p2c),p2c)/metal1 1 \ + "Contact not rectangular (Magic rule)" + + edge4way gc ~(gc)/contact 1 ~(gc)/contact (~(gc),gc)/contact 1 \ + "Contact not rectangular (Magic rule)" + + edge4way gv1 ~(gv1)/via1 1 ~(gv1)/via1 (~(gv1),gv1)/via1 1 \ + "Contact not rectangular (Magic rule)" + + edge4way m2c/m1 ~(m2c/m1)/metal1 1 ~(m2c/m1)/metal1 (~(m2c/m1),m2c/m1)/metal1 1 \ + "Contact not rectangular (Magic rule)" + + edge4way gv2 ~(gv2)/via2 1 ~(gv2)/via2 (~(gv2),gv2)/via2 1 \ + "Contact not rectangular (Magic rule)" + + edge4way m3c/m2 ~(m3c/m2)/metal2 1 ~(m3c/m2)/metal2 (~(m3c/m2),m3c/m2)/metal2 1 \ + "Contact not rectangular (Magic rule)" + + exact_overlap gc,ndc/a,pdc/a,psc/a,nsc/a,gc,pc/a,gc + + exact_overlap gc2,p2c + + edge4way pad ~(pad)/m3 1 ~(pad)/m3 (~(pad),pad)/m3 1 \ + "Contact not rectangular (Magic rule)" + + exact_overlap ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c + + exact_overlap m2c/m2 + + exact_overlap m3c/m3 + + exact_overlap gv1 + + exact_overlap gv2 + + + width m1p 4 \ + "Metal1 PIN width < 4 (do_pins)" + + spacing m1p m1p 4 touching_ok \ + "Metal1 PIN spacing < 4 (do_pins)" + + width m2p 4 \ + "Metal2 PIN width < 4 (do_pins)" + + spacing m2p m2p 4 touching_ok \ + "Metal2 PIN spacing < 4 (do_pins)" + + width m3p 6 \ + "Metal3 PIN width < 6 (do_pins)" + + spacing m3p m3p 4 touching_ok \ + "Metal3 PIN spacing < 4 (do_pins)" + +#CC cifstyle lambda=0.30(p) +#CC cifwidth CWN 360 \ +#CC "generated CIF layer CWN width will be < 12 (';cif see CWN')" +#CC cifspacing CWN CWN 180 touching_ok \ +#CC "generated CIF layer CWN spacing will be < 6 (';cif see CWN')" +#CC cifwidth CWP 360 \ +#CC "generated CIF layer CWP width will be < 12 (';cif see CWP')" +#CC cifspacing CWP CWP 180 touching_ok \ +#CC "generated CIF layer CWP spacing will be < 6 (';cif see CWP')" +#CC cifwidth CSN 60 \ +#CC "generated CIF layer CSN width will be < 2 (';cif see CSN')" +#CC cifspacing CSN CSN 60 touching_ok \ +#CC "generated CIF layer CSN spacing will be < 2 (';cif see CSN')" +#CC cifwidth CSP 60 \ +#CC "generated CIF layer CSP width will be < 2 (';cif see CSP')" +#CC cifspacing CSP CSP 60 touching_ok \ +#CC "generated CIF layer CSP spacing will be < 2 (';cif see CSP')" + + stepsize 400 + +end + +#--------------------------------------------------- +# LEF format definitions +#--------------------------------------------------- + +lef + +ignore PC +ignore CA + +routing m1 metal1 M1 m1 met1 +routing m2 metal2 M2 m2 met2 +routing m3 metal3 M3 m3 met3 + +contact m2c via1 via V1 v1 +contact m3c via2 V2 v2 + +end + +extract + style AMI0.5um(amic5)from:T11Z + cscale 1 + lambda 30 + step 100 + sidehalo 8 + planeorder well 0 + planeorder implant 1 + planeorder select 2 + planeorder cap 3 + planeorder active 4 + planeorder metal1 5 + planeorder metal2 6 + planeorder metal3 7 + planeorder oxide 8 + planeorder xp 9 + planeorder comment 10 + planeorder contact 11 + planeorder via1 12 + planeorder via2 13 + planeorder fill 14 + + substrate *psd,space/w,pwell well + + resist (ndiff,rnd,ndc,nsd,nsc)/active 82400 + resist (pdiff,rpd,pdc,psd,psc)/active 102700 + resist (nwell)/well 816000 + resist (rnw)/active 816000 0.5 + resist (pwell)/well 1 + resist (poly,fp,rp,pc,pc,nfet,pfet,fet)/active 22300 + resist (poly2,ecap,p2c)/cap 41300 + resist (phr)/cap 41300 0.5 + resist (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c,m2c)/metal1 90 + resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 90 + resist (m3,fm3,rm3,m3c,pad)/metal3 60 + + contact ndc 4 58700 + contact pdc 4 141000 + contact pc 4 15800 + contact p2c 4 26800 + contact m2c 4 760 + contact m3c 4 730 + + +#poly2 + overlap (poly,fp,rp,pc,pc)/active (poly2,ecap,phr,p2c)/cap 82.260 + +#nwell,cwell,pwell + areacap (nwell)/well 3.510 + +#rnw + areacap (rnw)/active 3.510 + +#ndiff +# MODEL HANDLES THIS: areacap (ndiff,ndc)/active 38.070 +# MODEL HANDLES THIS: overlap (ndiff,ndc)/active ~space/w 38.070 +# MODEL HANDLES THIS: perimc (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active 95.700 +# MODEL HANDLES THIS: sideoverlap (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active ~space/w 95.700 + + areacap (rnd)/active 38.070 + overlap (rnd)/active ~space/w 38.070 + perimc (rnd)/active ~(rnd)/active 95.700 + sideoverlap (rnd)/active ~(rnd)/active ~space/w 95.700 + +#pdiff +# MODEL HANDLES THIS: areacap (pdiff,pdc)/active 65.610 +# MODEL HANDLES THIS: overlap (pdiff,pdc)/active ~space/w 65.610 +# MODEL HANDLES THIS: perimc (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active 73.800 +# MODEL HANDLES THIS: sideoverlap (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active ~space/w 73.800 + + areacap (rpd)/active 65.610 + overlap (rpd)/active ~space/w 65.610 + perimc (rpd)/active ~(rpd)/active 73.800 + sideoverlap (rpd)/active ~(rpd)/active ~space/w 73.800 + +#rnw + +#poly +# MODEL HANDLES THIS: overlap (nfet)/active (ndiff,rnd,ndc)/active 225.450 +# MODEL HANDLES THIS: sideoverlap (nfet)/active ~(nfet)/active (ndiff,rnd,ndc)/active 65.700 +# MODEL HANDLES THIS: overlap (pfet)/active (pdiff,rpd,pdc)/active 219.060 +# MODEL HANDLES THIS: sideoverlap (pfet)/active ~(pfet)/active (pdiff,rpd,pdc)/active 69 + + areacap (poly,fp,rp,pc)/active 7.920 + overlap (poly,fp,rp,pc)/active ~space/w 7.920 + +#poly2 + +#rnw + +#metal1 + areacap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 2.790 + +#metal1-sub blocked by ~space/a,~space/c + overlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~space/w 2.790 ~space/a,~space/c + perimc (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 22.200 + sideoverlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~space/w 22.200 ~space/a,~space/c + +#rnw + overlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 rnw/active 2.790 ~space/c + sideoverlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 rnw/active 22.200 ~space/c + +#metal1-diff blocked by ~space/c + overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (ndiff,rnd,ndc)/active 3.150 ~space/c + sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (ndiff,rnd,ndc)/active 22.200 ~space/c + overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (pdiff,rpd,pdc)/active 3.150 ~space/c + sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (pdiff,rpd,pdc)/active 22.200 ~space/c + +#metal1-poly blocked by ~space/c + overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 4.680 ~space/c + sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 18 ~space/c + sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 18 ~space/c + +#metal1-poly2 not blocked + overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly2,ecap,phr)/cap 4.320 + +#metal2 + areacap (m2,fm2,rm2,m3c)/metal2 1.440 + +#metal2-sub blocked by + overlap (m2,fm2,rm2,m3c)/metal2 ~space/w 1.440 ~space/a,~space/m1,~space/c + perimc (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 17.400 + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 ~space/w 17.400 ~space/a,~space/m1,~space/c + overlap (m2,fm2,rm2,m3c)/metal2 rnw/active 1.440 ~space/m1,~space/c + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 rnw/active 17.400 ~space/m1,~space/c + +#metal2-*diff blocked by ~space/m1,~space/c + overlap (m2,fm2,rm2,m3c)/metal2 (ndiff,rnd,ndc)/active 1.440 ~space/m1,~space/c + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (ndiff,rnd,ndc)/active 17.400 ~space/m1,~space/c + overlap (m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 1.440 ~space/m1,~space/c + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 17.400 ~space/m1,~space/c + +#metal2-poly blocked by ~space/m1,~space/c + overlap (m2,fm2,rm2,m3c)/metal2 (poly,fp,rp,pc,nfet,pfet,fet)/active 1.350 ~space/m1,~space/c + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (poly,fp,rp,pc,nfet,pfet,fet)/active 11.400 ~space/m1,~space/c + sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m2,fm2,rm2,m2c,m3c)/metal2 11.400 ~space/m1,~space/c + +#metal2-poly2 blocked by ~space/m1 + +#M2->M1 + overlap (m2,fm2,rm2,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 2.700 + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 15 + sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (m2,fm2,rm2,m2c,m3c)/metal2 15 + +#metal3 + areacap (m3,fm3,rm3,pad)/metal3 0.900 + +#metal3-sub blocked by ~space/a,~space/m1,~space/m2,~space/c + overlap (m3,fm3,rm3,pad)/metal3 ~space/w 0.900 ~space/a,~space/m1,~space/m2,~space/c + perimc (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 11.400 + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 ~space/w 11.400 ~space/a,~space/m1,~space/m2,~space/c + +#rnw + overlap (m3,fm3,rm3,pad)/metal3 rnw/active 0.900 ~space/m1,~space/m2,~space/c + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 rnw/active 11.400 ~space/m1,~space/m2,~space/c + +#metal3-*diff blocked by ~space/m1,~space/m2,~space/c + overlap (m3,fm3,rm3,pad)/metal3 (ndiff,rnd,ndc)/active 0.990 ~space/m1,~space/m2,~space/c + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (ndiff,rnd,ndc)/active 11.400 ~space/m1,~space/m2,~space/c + overlap (m3,fm3,rm3,pad)/metal3 (pdiff,rpd,pdc)/active 0.990 ~space/m1,~space/m2,~space/c + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (pdiff,rpd,pdc)/active 11.400 ~space/m1,~space/m2,~space/c + +#metal3-poly blocked by ~space/m1,~space/m2,~space/c + overlap (m3,fm3,rm3,pad)/metal3 (poly,fp,rp,pc,nfet,pfet,fet)/active 0.810 ~space/m1,~space/m2,~space/c + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (poly,fp,rp,pc,nfet,pfet,fet)/active 8.400 ~space/m1,~space/m2,~space/c + sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m3,fm3,rm3,m3c,pad)/metal3 8.400 ~space/m1,~space/m2,~space/c + +#metal3-poly2 blocked by ~space/m1,~space/m2 + +#M3->M1 + overlap (m3,fm3,rm3,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 1.080 ~space/m2 + +#metal3-metal1 blocked by ~space/m2 + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 9.600 ~space/m2 + sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (m3,fm3,rm3,m3c,pad)/metal3 9.600 ~space/m2 + +#M3->M2 + overlap (m3,fm3,rm3,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 2.880 + sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 15.600 + sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m3,fm3,rm3,m3c,pad)/metal3 15.600 + +#metal4 + +#metal5 + +#metal6 + +#metal7 + +#metali + +#devices + + device mosfet pfet pfet pdiff,pdc nwell ERROR 69 219 + device mosfet nfet nfet ndiff,ndc pwell,space/w ERROR 66 225 + + fetresis pfet linear 21001 + fetresis pfet saturation 21001 + fetresis nfet linear 6020 + fetresis nfet saturation 6020 + + device resistor nwellResistor rnwell *nsd + device resistor polyResistor rpoly *poly + device resistor poly2Resistor rpoly2 *poly2 + device resistor ndiffResistor rndiff *ndiff + device resistor pdiffResistor rpdiff *pdiff + + device resistor metal1Resistor rmetal1 *metal1 + device resistor metal2Resistor rmetal2 *metal2 + device resistor metal3Resistor rmetal3 *metal3 + + device resistor presResistor phr *poly2 + + +end + +wiring + contact pdcontact 4 metal1 0 pdiff 0 + contact ndcontact 4 metal1 0 ndiff 0 + contact pcontact 4 metal1 0 poly 0 + contact m2contact 4 metal1 0 metal2 0 + contact m3contact 5 metal2 0 metal3 1 + +end + +router + layer2 metal2 3 m2,fm2,rm2,m2c/m2,m3c/m2,m3c/m2 4 poly,fp,rp,ndiff,rnd,nsd,pdiff,rpd,psd,m1,fm1,rm1 1 + layer1 metal1 3 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3 + contacts m2contact 4 + gridspacing 8 + +end + +plowing + fixed nfet,pfet,glass,pad + covered nfet,pfet + drag nfet,pfet + +end + +plot +style colorversatec + ndiff,rnd,ndc/a yellow \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA + ndiff,rnd,ndc/a cyan \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 + nsd,nsc/a yellow \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 + nsd,nsc/a cyan \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 + pdiff,rpd,pdc/a yellow \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA + pdiff,rpd,pdc/a cyan \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 \ + 0000 5555 0000 5555 + pdiff,rpd,pdc/a magenta \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 + psd,psc/a yellow \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 \ + 1515 2A2A 5151 A2A2 + psd,psc/a cyan \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 \ + 0000 1515 0000 5151 + psd,psc/a magenta \ + 2A2A 0000 A2A2 0000 \ + 2A2A 0000 A2A2 0000 \ + 2A2A 0000 A2A2 0000 \ + 2A2A 0000 A2A2 0000 + poly,fp,rp,pc/a magenta \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA \ + 5555 AAAA 5555 AAAA + nfet yellow \ + 0505 8282 1414 0A0A \ + 5050 2828 4141 A0A0 \ + 0505 8282 1414 0A0A \ + 5050 2828 4141 A0A0 + nfet cyan \ + 0000 0505 0000 1414 \ + 0000 5050 0000 4141 \ + 0000 0505 0000 1414 \ + 0000 5050 0000 4141 + nfet magenta \ + 5050 2828 4141 A0A0 \ + 0505 8282 1414 0A0A \ + 5050 2828 4141 A0A0 \ + 0505 8282 1414 0A0A + pfet yellow \ + 6363 A0A0 5050 2828 \ + 3636 0A0A 0505 8282 \ + 6363 A0A0 5050 2828 \ + 3636 0A0A 0505 8282 + pfet cyan \ + 0000 5151 0000 5454 \ + 0000 1515 0000 1515 \ + 0000 5151 0000 5454 \ + 0000 1515 0000 1515 + pfet magenta \ + 9494 0A0A 2525 8282 \ + 4949 A0A0 5252 2828 \ + 9494 0A0A 2525 8282 \ + 4949 A0A0 5252 2828 + poly2,ecap,phr yellow \ + FFFF FFFF FFFF FFFF \ + FFFF FFFF FFFF FFFF \ + FFFF FFFF FFFF FFFF \ + FFFF FFFF FFFF FFFF + m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 cyan \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 \ + AAAA 0000 AAAA 0000 + m2,fm2,rm2,m2c/m2,m3c/m2 cyan \ + 0000 1111 0000 4444 \ + 0000 1111 0000 4444 \ + 0000 1111 0000 4444 \ + 0000 1111 0000 4444 + m2,fm2,rm2,m2c/m2,m3c/m2 magenta \ + 0000 4444 0000 1111 \ + 0000 4444 0000 1111 \ + 0000 4444 0000 1111 \ + 0000 4444 0000 1111 + m2c/m1,gv1 black \ + 0000 6666 6666 0000 \ + 0000 9999 9999 0000 \ + 0000 6666 6666 0000 \ + 0000 9999 9999 0000 + pad,glass black \ + 0300 0700 0E00 1C00 \ + 3800 7000 E000 C000 \ + 00C0 00E0 0070 0038 \ + 001C 000E 0007 0003 + nwell yellow \ + 0800 1000 2000 4000 \ + 8000 0001 0002 0004 \ + 0008 0010 0020 0040 \ + 0080 0010 0200 0400 + nwell cyan \ + 1000 2000 4000 8000 \ + 0001 0002 0004 0008 \ + 0010 0020 0040 0080 \ + 0100 0200 0400 0800 + pwell yellow \ + 1000 0400 0400 0100 \ + 0100 0040 0040 0010 \ + 0010 0004 0004 0001 \ + 0001 4000 4000 1000 + pwell cyan \ + 0000 0800 0000 0200 \ + 0000 0080 0000 0020 \ + 0000 0008 0000 0002 \ + 0000 8000 0000 2000 + pwell magenta \ + 0800 0000 0200 0000 \ + 0080 0000 0020 0000 \ + 0008 0000 0002 0000 \ + 8000 0000 2000 0000 + m3c/m2,gv2 black \ + 0100 0000 0000 0000 \ + 1010 0000 0000 0000 \ + 0001 0000 0000 0000 \ + 1010 0000 0000 0000 + m3c/m2,gv2 cyan \ + 0280 0000 0820 0000 \ + 2008 0000 8002 0000 \ + 8002 0000 2008 0000 \ + 0820 0000 0280 0000 + m3c/m2,gv2 magenta \ + 0100 06C0 0440 1830 \ + 1010 600C 4004 8003 \ + 0001 C006 4004 3018 \ + 1010 0C60 0440 0380 + m3c/m2,gv2 black \ + 0820 0820 0820 0FE0 \ + E00F 2008 2008 2008 \ + 2008 2008 2008 E00F \ + 0000 0FE0 0820 0820 + error_p,error_s,error_ps black \ + 0000 3C3C 4646 4A4A \ + 5252 6262 3C3C 0000 \ + 0000 3C3C 4646 4A4A \ + 5252 6262 3C3C 0000 + magnet yellow \ + AAAA 0000 5555 0000 \ + AAAA 0000 5555 0000 \ + AAAA 0000 5555 0000 \ + AAAA 0000 5555 0000 + fence magenta \ + FFFF 0000 0000 0000 \ + 0000 0000 0000 0000 \ + FFFF 0000 0000 0000 \ + 0000 0000 0000 0000 + rotate cyan \ + 0000 E0E0 E0E0 E0E0 \ + 0000 0000 0000 0000 \ + 0000 E0E0 E0E0 E0E0 \ + 0000 0000 0000 0000 + pc/a,ndc/a,pdc/a,psc/a,nsc/a,gc,gc,gc X + +style versatec + pfet \ + 07c0 0f80 1f00 3e00 \ + 7c00 f800 f001 e003 \ + c007 800f 001f 003e \ + 00c7 00f8 01f0 03e0 + nfet \ + 1f00 0f80 07c0 03e0 \ + 01f0 00f8 007c 003e \ + 001f 800f c007 e003 \ + f001 f800 7c00 3e00 + gv1 \ + c3c3 c3c3 0000 0000 \ + 0000 0000 c3c3 c3c3 \ + c3c3 c3c3 0000 0000 \ + 0000 0000 c3c3 c3c3 + pwell \ + 2020 2020 2020 2020 \ + 2020 2020 2020 2020 \ + 0000 0000 0000 0000 \ + 0000 0000 0000 0000 + nwell \ + 0808 0404 0202 0101 \ + 0000 0000 0000 0000 \ + 0808 0404 0202 0101 \ + 0000 0000 0000 0000 + poly,fp,rp,pc/a,nfet,pfet \ + 0808 0400 0202 0101 \ + 8080 4000 2020 1010 \ + 0808 0004 0202 0101 \ + 8080 0040 2020 1010 + m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 \ + 8080 0000 0000 0000 \ + 0808 0000 0000 0000 \ + 8080 0000 0000 0000 \ + 0808 0000 0000 0000 + pad,glass \ + 0000 0000 1c1c 3e3e \ + 3636 3e3e 1c1c 0000 \ + 0000 0000 1c1c 3e3e \ + 3636 3e3e 1c1c 0000 + nsd,nsc/a \ + 0808 1414 2222 4141 \ + 8080 4040 2020 1010 \ + 0808 1414 2222 4141 \ + 8080 4040 2020 1010 + m2,fm2,rm2,m2c/m2,m3c/m2 \ + 0000 1111 0000 0000 \ + 0000 1111 0000 0000 \ + 0000 1111 0000 0000 \ + 0000 1111 0000 0000 + pdiff,rpd,pdc/a,pfet \ + 0000 0808 5555 8080 \ + 0000 8080 5555 0808 \ + 0000 0808 5555 8080 \ + 0000 8080 5555 0808 + psd,psc/a \ + 1414 2222 0000 2222 \ + 4141 2222 0000 2222 \ + 1414 2222 0000 2222 \ + 4141 2222 0000 2222 + ndiff,rnd,ndc/a,nfet \ + 0808 1010 2020 4040 \ + 8080 4141 2222 1414 \ + 0808 1010 2020 4040 \ + 8080 4141 2222 1414 + pc/a,ndc/a,pdc/a,psc/a,nsc/a,gc,gc,gc X + +style gremlin + pfet 9 + nfet 10 + gv1 11 + pwell 15 + nwell 16 + poly,fp,rp,pc/a,nfet,pfet 19 + pc/a,ndc/a,pdc/a,psc/a,nsc/a,gc,gc,gc 22 + pad,glass 23 + nsd,nsc/a 24 + gv1 28 + pdiff,rpd,pdc/a,pfet 29 + psd,psc/a 30 + ndiff,rnd,ndc/a,nfet 31 + pc/a,ndc/a,pdc/a,psc/a,nsc/a,gc,gc,gc,gv1 X + +end + diff --git a/technology/scn3me_subm/tech/__init__.py b/technology/scn3me_subm/tech/__init__.py new file mode 100755 index 00000000..2573d2c2 --- /dev/null +++ b/technology/scn3me_subm/tech/__init__.py @@ -0,0 +1,6 @@ +""" +Import tech specific modules. +""" + +from .tech import * + diff --git a/technology/scn3me_subm/tech/calibreDRC_scn3me_subm.rul b/technology/scn3me_subm/tech/calibreDRC_scn3me_subm.rul new file mode 100755 index 00000000..91d35fb4 --- /dev/null +++ b/technology/scn3me_subm/tech/calibreDRC_scn3me_subm.rul @@ -0,0 +1,225 @@ +//////////////////////////////////////////////////////////// +// DEFINE BOOLEAN LAYERS +//////////////////////////////////////////////////////////// +LAYOUT USE DATABASE PRECISION YES + +layer pwell 41 +layer nwell 42 +layer active 43 +layer poly 46 +layer nimplant 45 +layer pimplant 44 +layer contact 25 +layer active_contact 48 +layer poly_contact 47 +layer metal1 49 +layer via1 50 +layer metal2 51 +layer via2 61 +layer metal3 62 +layer glass 52 +layer pad 26 + +//Enabling incremental connectivity for antenna rule checks +DRC Incremental Connect Yes + +well = nwell OR pwell +gate = poly AND active +implant = nimplant OR pimplant +fieldpoly = poly NOT active + +contactenc1 = active OR poly +contactenc = contactenc1 AND metal1 +diode = contact AND active +act_poly = interact poly active + +GROUP mask_check +//Well.2 Well.4 +Poly.1 Poly.2 Poly.3 Poly.4 Poly.5 +Active.1 Active.2 // Active.3 +Contact.1 Contact.2 Contact.3 Contact.4 +Contact.5 Contact.6 Metal1.1 Metal1.2 Metal1.3 + + + +//Well.1 { +//@Nwell and Pwell must not overlap +//AND nwell pwell +//} + +//Well.2 { +//@Min spacing of pwell to nwell = 0.00 +//EXTERNAL nwell pwell < 0.00 +//} + +//Well.4 { +//@Min width of nwell = 3.6 +//INTERNAL nwell < 3.6 +//} + +Poly.1 { +@Min width of poly = 0.6 +INTERNAL poly < 0.6 +} + +Poly.2 { +@Min spacing of gate poly = 0.9 +EXTERNAL gate < 0.9 +} + +Poly.3 { +@Min extension of poly past active = 0.6 +ENCLOSURE active poly < 0.6 +} + +Poly.4 { +@Minimum active enclosure of gate =0.6 +ENCLOSURE poly active < 0.6 +} + +Poly.5 { +@Minimum spacing of poly to active = 0.3 +EXTERNAL act_poly active < 0.3 +} + +Active.1 { +@Minimum width of active = 0.9 +INTERNAL active < 0.9 +} + +Active.2 { +@Minimum spacing of active areas = 0.9 +EXTERNAL active < 0.9 +} + +//Active.3 { +//@Minimum well enclosure of active = 1.8 +//ENCLOSURE active well < 1.8 +//} + +Contact.1 { +@Minimum width of contact = 0.6 +INTERNAL contact < 0.6 +} + +Contact.2 { +@Minimum spacing of contact = 0.9 +EXTERNAL contact < 0.9 +} + +Contact.3 { +@Contact must be inside metal1 and active or poly +NOT contact contactenc +} + +Contact.4 { +@Minimum active enclosure of contact = 0.3 +ENCLOSURE contact active < 0.3 +} + +Contact.5 { +@Minimum poly enclosure of contact = 0.3 +ENCLOSURE contact poly < 0.3 +} + +Contact.6 { +@Minimum spacing of contact to poly = 0.6 +EXTERNAL poly contact < 0.6 +} + +Metal1.1 { +@Minimum width of metal1 = 0.9 +INTERNAL metal1 < 0.9 +} + +Metal1.2 { +@Minimum spacing of metal1 = 0.9 +EXTERNAL metal1 < 0.9 +} + +Metal1.3 { +@Metal1 must extend past contact by 0.3 on two opposite sides +RECTANGLE ENCLOSURE contact metal1 +GOOD 0.00 0.3 OPPOSITE 0.00 0.3 OPPOSITE +} + +Metal1.4 { +@Metal1 must extend past via1 by 0.3 on two opposite sides +RECTANGLE ENCLOSURE via1 metal1 +GOOD 0.00 0.3 OPPOSITE 0.00 0.3 OPPOSITE +} + +Via1.1 { +@Minimum width of via1 = 0.6 +INTERNAL via1 < 0.6 +} + +Via1.2 { +@Minimum spacing of via1 = 0.6 +EXTERNAL via1 < 0.6 +} + +Via1.3 { +@Via1 must be inside metal1 +NOT via1 metal1 +} + + +Metal2.1 { +@Minimum width of metal2 = 0.9 +INTERNAL metal2 < 0.9 +} + +Metal2.2 { +@Minimum spacing of metal2 = 0.9 +EXTERNAL metal2 < 0.9 +} + +Metal2.3 { +@Metal2 must extend past via1 by 0.3 on two opposite sides +RECTANGLE ENCLOSURE via1 metal2 +GOOD 0.00 0.3 OPPOSITE 0.00 0.3 OPPOSITE +} + +Metal2.4 { +@Metal2 must extend past via2 by 0.3 on two opposite sides +RECTANGLE ENCLOSURE via2 metal2 +GOOD 0.00 0.3 OPPOSITE 0.00 0.3 OPPOSITE +} + +Via2.1 { +@Minimum width of via2 = 0.6 +INTERNAL via2 < 0.6 +} + +Via2.2 { +@Minimum spacing of via2 = 0.9 +EXTERNAL via2 < 0.9 +} + +Via2.3 { +@Via2 must be inside metal2 +NOT via2 metal2 +} + +Via2.4 { +@Via2 must be inside metal3 +NOT via2 metal3 +} + +Metal3.1 { +@Minimum width of metal3 = 1.5 +INTERNAL metal3 < 1.5 +} + +Metal3.2 { +@Minimum spacing of metal3 = 0.9 +EXTERNAL metal3 < 0.9 +} + +Metal3.3 { +@Metal3 must extend past via2 by 0.6 on two opposite sides +RECTANGLE ENCLOSURE via2 metal3 +GOOD 0.00 0.6 OPPOSITE 0.00 0.6 OPPOSITE +} + diff --git a/technology/scn3me_subm/tech/calibreLVS_scn3me_subm.rul b/technology/scn3me_subm/tech/calibreLVS_scn3me_subm.rul new file mode 100755 index 00000000..5d3516a6 --- /dev/null +++ b/technology/scn3me_subm/tech/calibreLVS_scn3me_subm.rul @@ -0,0 +1,123 @@ +TITLE "LVS Rule File for scn3me_subm" + +LVS POWER NAME vdd +LVS GROUND NAME gnd GROUND +LVS REDUCE PARALLEL MOS yes +LVS REDUCE SERIES MOS yes +LVS REDUCE SEMI SERIES MOS yes +LVS FILTER UNUSED MOS no +LVS RECOGNIZE GATES all +LVS COMPONENT TYPE PROPERTY element +LVS COMPONENT SUBTYPE PROPERTY model +LVS IGNORE PORTS no + +LVS REPORT mask.lvs.rep +LVS REPORT OPTION N +LVS REPORT MAXIMUM 50 +MASK RESULTS DATABASE maskdb + +precision 1000 +resolution 250 + +TEXT LAYER metal1 metal2 metal3 +PORT LAYER TEXT metal1 metal2 metal3 + + +layer pwell 41 +layer nwell 42 +layer active 43 +layer poly 46 +layer nimplant 45 +layer pimplant 44 +layer contact 25 +layer active_contact 48 +layer poly_contact 47 +layer metal1 49 +layer via1 50 +layer metal2 51 +layer via2 61 +layer metal3 62 +layer glass 52 +layer pad 26 + +connect metal1 metal2 by via1 +connect metal2 metal3 by via2 + +pdif = active and pimplant // P-diffusion +ndif = active and nimplant // N-diffusion + +ngate = poly and ndif // N-Transistor +pgate = poly and pdif // P-transistor + +nsrcdrn = ndif not ngate // N-tansistor Source and Drain contacts diffusion region +psrcdrn = pdif not pgate // P-tansistor Source and Drain contacts diffusion region + +pcont = psrcdrn and pwell + +ntapcont = active not interact pimplant +ptapcont = active not interact nimplant + +bulk = extent +nsub = (bulk not pwell) and nwell +ncont = nsrcdrn and nsub + +connect metal1 poly psrcdrn nsrcdrn by contact mask +connect psrcdrn pwell by pcont mask +connect nsrcdrn nsub by ncont mask + +ncont1= ntapcont and nsub +pcont1= ptapcont and pwell +connect metal1 ncont1 by contact mask +connect metal1 pcont1 by contact mask +connect ncont1 nsub +connect pcont1 pwell + +connect psrcdrn metal1 by contact +connect nsrcdrn metal1 by contact + +connect psrcdrn metal1 by active_contact +connect nsrcdrn metal1 by active_contact + +connect poly metal1 by contact + +connect poly metal1 by poly_contact + +device mp (p) pgate poly (G) psrcdrn (S) psrcdrn (D) nsub CMACRO FET_PROPERTIES pgate nsub +device mn (n) ngate poly (G) nsrcdrn (S) nsrcdrn (D) pwell CMACRO FET_PROPERTIES ngate pwell + +VARIABLE trace_delta 4e-9 + +DMACRO FET_TRACE device_type device_name { +TRACE PROPERTY device_type(device_name) l l trace_delta ABSOLUTE +TRACE PROPERTY device_type(device_name) w w trace_delta ABSOLUTE + +} + +CMACRO FET_TRACE MN n +CMACRO FET_TRACE MP p + +DMACRO FET_PROPERTIES seed well{ +[ +PROPERTY W, L, AS, AD, PS, PD + + AS = area(S) + AD = area(D) + PS = perimeter(S) + PD = perimeter(D) + if ( AS == 0 ) { + AD = area(D) / 2 + AS = AD + PD = perimeter(D) / 2 + PS = PD + } + if ( AD == 0 ) { + AS = area(S) / 2 + AD = AS + PS = perimeter(S) / 2 + PD = PS + } + W = (perim_co(seed,S) + perim_co(seed,D) ) * 0.5 + L = (perim(seed) - perim_co(seed,S) - perim_in(seed,S) - perim_co(seed,D) - perim_in(seed,D) ) * 0.5 + +] +} diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py new file mode 100755 index 00000000..2d9abe16 --- /dev/null +++ b/technology/scn3me_subm/tech/tech.py @@ -0,0 +1,307 @@ +import os +from design_rules import * + +""" +File containing the process technology parameters for SCMOS 3me, subm, 180nm. +""" + +#GDS file info +GDS={} +# gds units +# gds units +# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first +#is the size of a database unit in user units. The second is the size +#of a database unit in meters. For example, if your library was +#created with the default units (user unit = 1 m and 1000 database +#units per user unit), then the first number would be 0.001 and the +#second number would be 10-9. Typically, the first number is less than +#1, since you use more than 1 database unit per user unit. To +#calculate the size of a user unit in meters, divide the second number +#by the first." +GDS["unit"]=(0.001,1e-6) +# default label zoom +GDS["zoom"] = 0.5 + + +################################################### +##GDS Layer Map +################################################### + +# create the GDS layer map +layer={} +layer["vtg"] = -1 +layer["vth"] = -1 +layer["contact"] = 47 +layer["pwell"] = 41 +layer["nwell"] = 42 +layer["active"] = 43 +layer["pimplant"] = 44 +layer["nimplant"] = 45 +layer["poly"] = 46 +layer["active_contact"] = 48 +layer["metal1"] = 49 +layer["via1"] = 50 +layer["metal2"] = 51 +layer["via2"] = 61 +layer["metal3"] = 62 +layer["text"] = 63 +layer["boundary"] = 63 +layer["blockage"] = 83 + +################################################### +##END GDS Layer Map +################################################### + +################################################### +##DRC/LVS Rules Setup +################################################### +_lambda_ = 0.3 + +#technology parameter +parameter={} +parameter["min_tx_size"] = 4*_lambda_ +parameter["beta"] = 2 + +parameter["6T_inv_nmos_size"] = 8*_lambda_ +parameter["6T_inv_pmos_size"] = 3*_lambda_ +parameter["6T_access_size"] = 4*_lambda_ + +drclvs_home=os.environ.get("DRCLVS_HOME") + +drc = design_rules("scn3me_subm") + +drc["body_tie_down"] = 0 +drc["has_pwell"] = True +drc["has_nwell"] = True + + +#grid size is 1/2 a lambda +drc["grid"]=0.5*_lambda_ +#DRC/LVS test set_up +drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul" +drc["lvs_rules"]=drclvs_home+"/calibreLVS_scn3me_subm.rul" +drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/scn3me_subm/layers.map" + + +# minwidth_tx with contact (no dog bone transistors) +drc["minwidth_tx"] = 4*_lambda_ +drc["minlength_channel"] = 2*_lambda_ + +# 1.3 Minimum spacing between wells of same type (if both are drawn) +drc["well_to_well"] = 6*_lambda_ +# 1.4 Minimum spacing between wells of different type (if both are drawn) +drc["pwell_to_nwell"] = 0 +# 1.1 Minimum width +drc["minwidth_well"] = 12*_lambda_ + +# 3.1 Minimum width +drc["minwidth_poly"] = 2*_lambda_ +# 3.2 Minimum spacing over active +drc["poly_to_poly"] = 3*_lambda_ +# 3.3 Minimum gate extension of active +drc["poly_extend_active"] = 2*_lambda_ +# 5.5.b Minimum spacing between poly contact and other poly (alternative rules) +drc["poly_to_polycontact"] = 4*_lambda_ +# ?? +drc["active_enclosure_gate"] = 0.0 +# 3.5 Minimum field poly to active +drc["poly_to_active"] = _lambda_ +# 3.2.a Minimum spacing over field poly +drc["poly_to_field_poly"] = 3*_lambda_ +# Not a rule +drc["minarea_poly"] = 0.0 + +# ?? +drc["active_to_body_active"] = 4*_lambda_ # Fix me +# 2.1 Minimum width +drc["minwidth_active"] = 3*_lambda_ +# 2.2 Minimum spacing +drc["active_to_active"] = 3*_lambda_ +# 2.3 Source/drain active to well edge +drc["well_enclosure_active"] = 6*_lambda_ +# Reserved for asymmetric enclosures +drc["well_extend_active"] = 6*_lambda_ +# Not a rule +drc["minarea_active"] = 0.0 + +# 4.1 Minimum select spacing to channel of transistor to ensure adequate source/drain width +drc["implant_to_channel"] = 3*_lambda_ +# 4.2 Minimum select overlap of active +drc["implant_enclosure_active"] = 2*_lambda_ +# 4.3 Minimum select overlap of contact +drc["implant_enclosure_contact"] = _lambda_ +# Not a rule +drc["implant_to_contact"] = 0 +# Not a rule +drc["implant_to_implant"] = 0 +# Not a rule +drc["minwidth_implant"] = 0 + +# 6.1 Exact contact size +drc["minwidth_contact"] = 2*_lambda_ +# 5.3 Minimum contact spacing +drc["contact_to_contact"] = 3*_lambda_ +# 6.2.b Minimum active overlap +drc["active_enclosure_contact"] = _lambda_ +# Reserved for asymmetric enclosure +drc["active_extend_contact"] = _lambda_ +# 5.2.b Minimum poly overlap +drc["poly_enclosure_contact"] = _lambda_ +# Reserved for asymmetric enclosures +drc["poly_extend_contact"] = _lambda_ +# Reserved for other technologies +drc["contact_to_gate"] = 2*_lambda_ +# 5.4 Minimum spacing to gate of transistor +drc["contact_to_poly"] = 2*_lambda_ + +# 7.1 Minimum width +drc["minwidth_metal1"] = 3*_lambda_ +# 7.2 Minimum spacing +drc["metal1_to_metal1"] = 3*_lambda_ +# 7.3 Minimum overlap of any contact +drc["metal1_enclosure_contact"] = _lambda_ +# Reserved for asymmetric enclosure +drc["metal1_extend_contact"] = _lambda_ +# 8.3 Minimum overlap by metal1 +drc["metal1_enclosure_via1"] = _lambda_ +# Reserve for asymmetric enclosures +drc["metal1_extend_via1"] = _lambda_ +# Not a rule +drc["minarea_metal1"] = 0 + +# 8.1 Exact size +drc["minwidth_via1"] = 2*_lambda_ +# 8.2 Minimum via1 spacing +drc["via1_to_via1"] = 3*_lambda_ + +# 9.1 Minimum width +drc["minwidth_metal2"] = 3*_lambda_ +# 9.2 Minimum spacing +drc["metal2_to_metal2"] = 3*_lambda_ +# 9.3 Minimum overlap of via1 +drc["metal2_extend_via1"] = _lambda_ +# Reserved for asymmetric enclosures +drc["metal2_enclosure_via1"] = _lambda_ +# 14.3 Minimum overlap by metal2 +drc["metal2_extend_via2"] = _lambda_ +# Reserved for asymmetric enclosures +drc["metal2_enclosure_via2"] = _lambda_ +# Not a rule +drc["minarea_metal2"] = 0 + +# 14.1 Exact size +drc["minwidth_via2"] = 2*_lambda_ +# 14.2 Minimum spacing +drc["via2_to_via2"] = 3*_lambda_ + +# 15.1 Minimum width +drc["minwidth_metal3"] = 5*_lambda_ +# 15.2 Minimum spacing to metal3 +drc["metal3_to_metal3"] = 3*_lambda_ +# 15.3 Minimum overlap of via 2 +drc["metal3_extend_via2"] = 2*_lambda_ +# Reserved for asymmetric enclosures +drc["metal3_enclosure_via2"] = 2*_lambda_ +# Not a rule +drc["minarea_metal3"] = 0 + +################################################### +##END DRC/LVS Rules +################################################### + +################################################### +##Spice Simulation Parameters +################################################### + +# spice model info +spice={} +spice["nmos"]="n" +spice["pmos"]="p" +# This is a map of corners to model files +SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR") +# FIXME: Uncomment when we have the new spice models +#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] } +spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"], + "FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"], + "FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"], + "SF" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"], + "SS" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"], + "ST" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"], + "TS" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"], + "FT" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"], + "TF" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"], + } + + +#spice stimulus related variables +spice["feasible_period"] = 10 # estimated feasible period in ns +spice["supply_voltages"] = [4.5, 5.0, 5.5] # Supply voltage corners in [Volts] +spice["nom_supply_voltage"] = 5.0 # Nominal supply voltage in [Volts] +spice["rise_time"] = 0.05 # rise time in [Nano-seconds] +spice["fall_time"] = 0.05 # fall time in [Nano-seconds] +spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius) +spice["nom_temperature"] = 25 # Nominal temperature (celcius) + +#sram signal names +#FIXME: We don't use these everywhere... +spice["vdd_name"] = "vdd" +spice["gnd_name"] = "gnd" +spice["control_signals"] = ["CSB", "WEB"] +spice["data_name"] = "DATA" +spice["addr_name"] = "ADDR" +spice["minwidth_tx"] = drc["minwidth_tx"] +spice["channel"] = drc["minlength_channel"] +spice["clk"] = "clk" + +# analytical delay parameters +# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45. +spice["vdd_nominal"] = 5.0 # Typical Threshold voltage in Volts +spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts +spice["v_threshold_typical"] = 1.3 # Typical Threshold voltage in Volts +spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square +spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2 +spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms +spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff +spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff +spice["msflop_setup"] = 9 # DFF setup time in ps +spice["msflop_hold"] = 1 # DFF hold time in ps +spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps +spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load +spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad] +spice["dff_setup"] = 9 # DFF setup time in ps +spice["dff_hold"] = 1 # DFF hold time in ps +spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps +spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load +spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad] + +# analytical power parameters, many values are temporary +spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW +spice["inv_leakage"] = 1 # Leakage power of inverter in nW +spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW +spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW +spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW +spice["msflop_leakage"] = 1 # Leakage power of flop in nW +spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF + +spice["default_event_rate"] = 100 # Default event activity of every gate. MHz +spice["flop_transition_prob"] = 0.5 # Transition probability of inverter. +spice["inv_transition_prob"] = 0.5 # Transition probability of inverter. +spice["nand2_transition_prob"] = 0.1875 # Transition probability of 2-input nand. +spice["nand3_transition_prob"] = 0.1094 # Transition probability of 3-input nand. +spice["nor2_transition_prob"] = 0.1875 # Transition probability of 2-input nor. + +#Logical Effort relative values for the Handmade cells +parameter['le_tau'] = 23 #In pico-seconds. +parameter["min_inv_para_delay"] = 0.73 #In relative delay units +parameter['cap_relative_per_ff'] = 0.91 #Units of Relative Capacitance/ Femto-Farad +parameter["dff_clk_cin"] = 27.5 #In relative capacitance units +parameter["6tcell_wl_cin"] = 2 #In relative capacitance units +parameter["sa_en_pmos_size"] = 24*_lambda_ +parameter["sa_en_nmos_size"] = 9*_lambda_ +parameter["sa_inv_pmos_size"] = 18*_lambda_ +parameter["sa_inv_nmos_size"] = 9*_lambda_ +parameter['bitcell_drain_cap'] = 0.2 #In Femto-Farad, approximation of drain capacitance + +################################################### +##END Spice Simulation Parameters +################################################### diff --git a/technology/scn3me_subm/tf/README b/technology/scn3me_subm/tf/README new file mode 100644 index 00000000..400cfe98 --- /dev/null +++ b/technology/scn3me_subm/tf/README @@ -0,0 +1,19 @@ +;; NCSU CDK v. 1.6.0.beta +;; Last Modified: 2007-07-12 + +The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004, +2006, 2007. Users are free to use or modify the NCSU CDK as appropriate as long +as this notice appears in the modified package. The NCSU CDK is +provided with NO WARRANTY. + +As of version 1.5.1, all documentation for the NCSU CDK is provided +by the NCSU EDA Wiki which can be found at: + + http://www.eda.ncsu.edu/ + +This beta release of the kit is to be used in migrating to Cadence Virtuoso 6.1 +for OpenAccess. Details of the conversion of the CDK from the CDB version can +be found in the file cdb2oa/OA_Conversion.txt. + +This kit is not yet fully supported. Please post problems and solutions at +http://www.chiptalk.org -> Forums -> NCSU CDK -> NCSU CDK 1.6.0.beta for Virtuoso 6.1 diff --git a/technology/scn3me_subm/tf/display.drf b/technology/scn3me_subm/tf/display.drf new file mode 100644 index 00000000..4bd251e8 --- /dev/null +++ b/technology/scn3me_subm/tf/display.drf @@ -0,0 +1,714 @@ +drDefineDisplay( +;( DisplayName ) + ( display ) +) +drDefineColor( +;( DisplayName ColorsName Red Green Blue ) + ( display white 255 255 255 ) + ( display yellow 255 255 0 ) + ( display silver 217 230 255 ) + ( display cream 255 255 204 ) + ( display pink 255 191 242 ) + ( display magenta 255 0 255 ) + ( display lime 0 255 0 ) + ( display tan 255 230 191 ) + ( display cyan 0 255 255 ) + ( display cadetBlue 57 191 255 ) + ( display orange 255 128 0 ) + ( display red 255 51 51 ) + ( display purple 153 0 230 ) + ( display green 0 204 102 ) + ( display brown 191 64 38 ) + ( display blue 51 77 255 ) + ( display slate 140 140 166 ) + ( display gold 217 204 0 ) + ( display maroon 230 31 13 ) + ( display violet 94 0 230 ) + ( display forest 38 140 107 ) + ( display chocolate 128 38 38 ) + ( display navy 51 51 153 ) + ( display black 0 0 0 ) + ( display gray 204 204 217 ) + ( display winColor1 166 166 166 ) + ( display winColor2 115 115 115 ) + ( display winColor3 189 204 204 ) + ( display winColor4 204 204 204 ) + ( display winColor5 199 199 199 ) + ( display blinkRed 255 0 0 t ) + ( display blinkYellow 255 255 0 t ) + ( display blinkWhite 255 255 255 t ) + ( display winBack 224 224 224 ) + ( display winFore 128 0 0 ) + ( display winText 51 51 51 ) +) +drDefineStipple( +;( DisplayName StippleName Bitmap ) + ( display dots ( ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display dots1 ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display hLine ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) ) ) + ( display vLine ( ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) ) ) + ( display cross ( ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) ) ) + ( display grid ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) ) ) + ( display slash ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) ) ) + ( display backSlash ( ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) ) ) + ( display hZigZag ( ( 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 ) + ( 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ) + ( 0 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 ) + ( 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 ) + ( 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 0 ) + ( 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 ) + ( 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 ) + ( 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 ) ) ) + ( display vZigZag ( ( 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 ) + ( 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 ) + ( 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ) + ( 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 ) + ( 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 ) + ( 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 ) + ( 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 ) + ( 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 ) + ( 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 ) + ( 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 ) + ( 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ) + ( 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 ) + ( 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 ) + ( 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 ) + ( 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 ) + ( 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 ) ) ) + ( display hCurb ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display vCurb ( ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) ) ) + ( display brick ( ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) + ( 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 ) ) ) + ( display dagger ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) + ( 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 ) ) ) + ( display triangle ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 ) + ( 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display x ( ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ) ) ) + ( display stipple0 ( ( 1 ) ) ) + ( display stipple1 ( ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display stipple2 ( ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) + ( 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 ) ) ) + ( display stipple3 ( ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) ) ) + ( display stipple4 ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 ) ) ) + ( display stipple5 ( ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) ) ) + ( display stipple6 ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) ) ) + ( display stipple7 ( ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) + ( 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) + ( 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 ) + ( 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 ) ) ) + ( display stipple8 ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 ) ) ) + ( display stipple9 ( ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) + ( 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 ) ) ) + ( display stipple10 ( ( 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display stipple11 ( ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) ) ) + ( display dots2 ( ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) + ( display dots4 ( ( 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 ) ) ) + ( display dats5 ( ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) + ( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ) ) +) +drDefineLineStyle( +;( DisplayName LineStyle Size Pattern ) + ( display solid 1 (1 ) ) + ( display dashed 1 (1 1 1 0 0 1 1 1 ) ) + ( display dots 1 (1 0 0 ) ) + ( display dashDot 1 (1 1 1 0 0 1 0 0 ) ) + ( display shortDash 1 (1 1 0 0 ) ) + ( display doubleDash 1 (1 1 1 1 0 0 1 1 0 0 ) ) + ( display hidden 1 (1 0 0 0 ) ) + ( display thickLine 3 (1 1 1 ) ) + ( display lineStyle0 1 (1 ) ) + ( display lineStyle1 1 (1 1 1 0 1 1 1 0 1 1 1 0 1 1 0 1 ) ) +) +drDefinePacket( +;( DisplayName PacketName Stipple LineStyle Fill Outline [FillStyle]) + ( display NwellNet dots4 thickLine slate slate outlineStipple) + ( display border stipple0 solid tan tan solid ) + ( display y8 stipple0 solid gold gold solid ) + ( display background stipple1 lineStyle0 black black outlineStipple) + ( display y9 stipple0 solid silver silver solid ) + ( display Metal3Net dots4 solid navy navy outlineStipple) + ( display A1 stipple0 lineStyle0 winBack winBack solid ) + ( display pin solid lineStyle0 red red solid ) + ( display XPNet blank solid yellow yellow outline ) + ( display hardFence stipple0 solid red red solid ) + ( display PbaseNet dots4 solid yellow yellow outlineStipple) + ( display designFlow3 stipple1 lineStyle0 pink pink outlineStipple) + ( display A2 stipple0 lineStyle0 winBack winBack solid ) + ( display Unrouted1 stipple0 lineStyle1 brown brown solid ) + ( display RowLbl blank solid cyan cyan outline ) + ( display edgeLayerPin stipple0 solid yellow yellow solid ) + ( display instance blank solid winBack red outline ) + ( display Nselect dots4 solid green green outlineStipple) + ( display snap stipple0 solid yellow yellow solid ) + ( display pinAnt stipple0 solid red red solid ) + ( display winAttentionText solid solid winText winText solid ) + ( display designFlow2 stipple1 lineStyle0 purple purple outlineStipple) + ( display Unrouted2 stipple0 lineStyle1 red red solid ) + ( display hilite blank solid white white outline ) + ( display P2Con solid lineStyle0 orange orange solid ) + ( display designFlow1 stipple1 lineStyle0 red red outlineStipple) + ( display grid1 stipple0 solid gray gray solid ) + ( display Unrouted3 stipple0 lineStyle1 pink pink solid ) + ( display ViaNet x solid magenta magenta outlineStipple) + ( display select stipple0 solid tan tan solid ) + ( display Poly2Net dots4 lineStyle0 orange orange outlineStipple) + ( display winText solid solid winText winText solid ) + ( display Unrouted4 stipple0 lineStyle1 orange orange solid ) + ( display wireLbl solid lineStyle0 cyan cyan solid ) + ( display designFlow7 stipple1 lineStyle0 cyan cyan outlineStipple) + ( display align stipple0 solid tan tan solid ) + ( display Poly2Pin blank solid yellow yellow outline ) + ( display Unrouted5 stipple0 lineStyle1 green green solid ) + ( display unset stipple0 solid forest forest solid ) + ( display Poly1Net dots4 lineStyle0 red red outlineStipple) + ( display Resistor dots2 lineStyle0 cyan cyan outlineStipple) + ( display DiodeNet dots4 lineStyle0 cream cream outlineStipple) + ( display designFlow6 stipple1 lineStyle0 tan tan outlineStipple) + ( display Unrouted6 stipple0 lineStyle1 blue blue solid ) + ( display resist stipple0 solid cyan cyan solid ) + ( display designFlow5 stipple1 lineStyle0 silver silver outlineStipple) + ( display CapWellNet brick solid slate slate outlineStipple) + ( display Unrouted7 stipple0 lineStyle1 purple purple solid ) + ( display CannotoccupyBnd blank solid red red outline ) + ( display winTopShadow solid solid white white solid ) + ( display designFlow4 stipple1 lineStyle0 black black outlineStipple) + ( display softFence stipple0 solid yellow yellow solid ) + ( display ResistorNet dots4 solid cyan cyan outlineStipple) + ( display winError solid solid winColor5 winColor5 solid ) + ( display changedLayerTl1 stipple0 solid yellow yellow solid ) + ( display prBoundaryLbl stipple0 solid purple purple solid ) + ( display ActXNet x solid yellow yellow outlineStipple) + ( display Pbase stipple10 lineStyle0 yellow yellow outlineStipple) + ( display Active dots2 lineStyle0 yellow yellow outlineStipple) + ( display changedLayerTl0 stipple0 solid red red solid ) + ( display spike stipple0 solid purple purple solid ) + ( display Metal3 grid solid navy violet outlineStipple) + ( display text blank solid white white outline ) + ( display Poly1Pin stipple0 lineStyle0 red red solid ) + ( display Row blank solid cyan cyan outline ) + ( display Pwell stipple9 lineStyle0 slate slate outlineStipple) + ( display Metal2 stipple5 lineStyle0 magenta magenta outlineStipple) + ( display wire solid lineStyle0 cyan cyan solid ) + ( display ActX solid solid yellow yellow solid ) + ( display Metal1 stipple6 lineStyle0 cadetBlue cadetBlue outlineStipple) + ( display Cannotoccupy blank solid red red outline ) + ( display GroupLbl stipple0 solid green green solid ) + ( display axis stipple0 solid slate slate solid ) + ( display SiBlockNet x dashed tan tan outlineStipple) + ( display edgeLayer stipple0 solid gray gray solid ) + ( display annotate2 stipple0 solid lime lime solid ) + ( display Metal1Pin stipple0 lineStyle0 blue blue solid ) + ( display Diode stipple7 lineStyle0 cream cream outlineStipple) + ( display Glass X lineStyle0 white white X ) + ( display ViaXNet x solid magenta magenta outlineStipple) + ( display annotate3 stipple0 solid cyan cyan solid ) + ( display Poly2 dots1 lineStyle0 orange orange outlineStipple) + ( display deviceAnt stipple0 solid yellow yellow solid ) + ( display winBottomShadow solid solid winColor1 winColor1 solid ) + ( display PselectNet dots4 solid brown brown outlineStipple) + ( display comment stipple0 lineStyle0 winBack winBack outlineStipple) + ( display Poly1 dots lineStyle0 red red outlineStipple) + ( display Unrouted stipple0 lineStyle1 winColor5 winColor5 solid ) + ( display stretch stipple0 solid yellow yellow solid ) + ( display XP blank lineStyle0 winBack gold outline ) + ( display annotate1 stipple0 solid pink pink solid ) + ( display Group stipple2 solid green green outlineStipple) + ( display deviceLbl stipple0 solid green green solid ) + ( display annotate6 stipple0 solid silver silver solid ) + ( display GlassNet blank solid yellow yellow outline ) + ( display Canplace blank solid cyan cyan outline ) + ( display annotate7 stipple0 solid red red solid ) + ( display Via2 solid solid navy navy solid ) + ( display Metal2Pin stipple0 lineStyle0 magenta magenta solid ) + ( display annotate4 stipple0 solid yellow yellow solid ) + ( display device1 stipple1 lineStyle0 green green outlineStipple) + ( display "90" blank solid white white outline ) + ( display markerWarn x solid yellow yellow outlineStipple) + ( display text2 stipple1 lineStyle0 white white outlineStipple) + ( display CapacitorNet dots4 lineStyle0 tan tan outlineStipple) + ( display designFlow stipple1 lineStyle0 green green outlineStipple) + ( display hilite1 stipple0 solid silver silver solid ) + ( display device blank solid green green outline ) + ( display prBoundary stipple0 solid purple purple solid ) + ( display annotate5 stipple0 solid white white solid ) + ( display text1 stipple0 dashed white white solid ) + ( display Via solid solid magenta magenta solid ) + ( display Capacitor stipple7 lineStyle0 tan tan outlineStipple) + ( display markerErr x solid white white outlineStipple) + ( display unknown stipple0 solid yellow yellow solid ) + ( display annotate stipple0 solid orange orange solid ) + ( display P1ConNet x solid red red outlineStipple) + ( display hilite3 stipple0 solid cyan cyan solid ) + ( display winActiveBanner solid solid winColor3 winColor3 solid ) + ( display pinLbl stipple0 solid red red solid ) + ( display device2 stipple0 lineStyle1 green green solid ) + ( display grid stipple0 solid slate slate solid ) + ( display winBackground solid solid winBack winBack solid ) + ( display Metal1Net dots4 lineStyle0 blue blue outlineStipple) + ( display hilite2 stipple0 solid tan tan solid ) + ( display annotate8 stipple0 solid tan tan solid ) + ( display hilite5 stipple0 solid lime lime solid ) + ( display annotate9 stipple0 solid green green solid ) + ( display Metal2Net dots4 lineStyle0 magenta magenta outlineStipple) + ( display Metal3Pin stipple0 solid navy navy solid ) + ( display hilite4 stipple0 solid gray gray solid ) + ( display y0 stipple0 solid gray gray solid ) + ( display supply stipple0 solid lime lime solid ) + ( display ActiveNet dots4 lineStyle0 yellow yellow outlineStipple) + ( display hilite7 stipple0 solid cream cream solid ) + ( display y1 stipple0 solid brown brown solid ) + ( display defaultPacket x solid chocolate winColor2 outlineStipple) + ( display Via2Net cross solid navy navy outlineStipple) + ( display NselectNet dots4 solid green green outlineStipple) + ( display Unrouted8 stipple0 lineStyle1 gold gold solid ) + ( display hilite6 stipple0 solid orange orange solid ) + ( display y2 stipple0 solid red red solid ) + ( display winBorder solid solid winColor2 winColor2 solid ) + ( display Nwell dats5 thickLine slate slate outlineStipple) + ( display Unrouted9 stipple0 lineStyle1 silver silver solid ) + ( display hilite9 stipple0 solid pink pink solid ) + ( display SiBlock blank dashed tan tan outline ) + ( display y3 stipple0 solid orange orange solid ) + ( display prBoundaryBnd stipple0 solid cyan cyan solid ) + ( display winForeground solid solid winFore winFore solid ) + ( display hilite8 stipple0 solid magenta magenta solid ) + ( display y4 stipple0 solid yellow yellow solid ) + ( display Pselect dots1 solid brown brown outlineStipple) + ( display winInactiveBanner solid solid winColor4 winColor4 solid ) + ( display designFlow9 stipple1 lineStyle0 orange orange outlineStipple) + ( display winButton solid solid winFore winFore solid ) + ( display y5 stipple0 solid green green solid ) + ( display hiz stipple0 solid orange orange solid ) + ( display drive stipple0 solid blue blue solid ) + ( display wireFlt stipple0 dashed red red solid ) + ( display instanceLbl stipple0 solid gold gold solid ) + ( display P2ConNet x lineStyle0 orange orange outlineStipple) + ( display designFlow8 stipple1 lineStyle0 navy navy outlineStipple) + ( display y6 stipple0 solid blue blue solid ) + ( display PwellNet dots4 lineStyle0 slate slate outlineStipple) + ( display P1Con solid solid red red solid ) + ( display CapWell dagger solid slate slate outlineStipple) + ( display y7 stipple0 solid purple purple solid ) + ( display ViaX solid solid magenta magenta solid ) + ( display HR x solid chocolate winColor2 outlineStipple) + ( display HRnet x solid chocolate winColor2 outlineStipple) +) diff --git a/technology/scn3me_subm/tf/glade_scn3me_subm.py b/technology/scn3me_subm/tf/glade_scn3me_subm.py new file mode 100644 index 00000000..d2f9aa7e --- /dev/null +++ b/technology/scn3me_subm/tf/glade_scn3me_subm.py @@ -0,0 +1,7 @@ +import os +CWD = os.environ.get("OPENRAM_TECH") + "/scn3me_subm/tf" +ui().importCds("default", CWD+"/display.drf", CWD+"/mosis.tf", 1000, 1, CWD+"/layers.map") + + + + diff --git a/technology/scn3me_subm/tf/layers.map b/technology/scn3me_subm/tf/layers.map new file mode 100644 index 00000000..b5440f23 --- /dev/null +++ b/technology/scn3me_subm/tf/layers.map @@ -0,0 +1,16 @@ +Pwell drawing 41 0 +Nwell drawing 42 0 +Active drawing 43 0 +Poly1 drawing 46 0 +Pselect drawing 45 0 +Nselect drawing 44 0 +contact drawing 25 0 +P1Con drawing 47 0 +ActX drawing 48 0 +Metal1 drawing 49 0 +Via drawing 50 0 +Metal2 drawing 51 0 +Via2 drawing 61 0 +Metal3 drawing 62 0 +Glass drawing 52 0 +comment drawing 63 0 diff --git a/technology/scn3me_subm/tf/mosis.tf b/technology/scn3me_subm/tf/mosis.tf new file mode 100644 index 00000000..759221f1 --- /dev/null +++ b/technology/scn3me_subm/tf/mosis.tf @@ -0,0 +1,848 @@ +; Generated on Sep 28 16:05:23 1998 +; with @(#)$CDS: icfb.exe version 4.4.1 06/17/98 23:40 (cds10067) $ +; +; Matt Clapp fixed: October 10, 2002 +; added via devices, deleted useless app-specific crap, +; added lxExtractRules so undo in layout editor doesn't +; complain. + + +;******************************** +; LAYER DEFINITION +;******************************** + +layerDefinitions( + techLayers( + ;( LayerName Layer# Abbreviation ) + ;( --------- ------ ------------ ) + ;User-Defined Layers: + ( P2Con 3 P2Con ) + ( Poly2 7 Poly2 ) + ( Pbase 10 Pbase ) + ( Resistor 16 Resisto ) + ( Capacitor 17 Capacit ) + ( Diode 18 Diode ) + ( SiBlock 29 SiBlock ) + ( HR 34 HR ) + ( Pwell 41 Pwell ) + ( Nwell 42 Nwell ) + ( Active 43 Active ) + ( Pselect 44 Pselect ) + ( Nselect 45 Nselect ) + ( Poly1 46 Poly1 ) + ( P1Con 47 P1Con ) + ( ActX 48 ActX ) + ( Metal1 49 Metal1 ) + ( Via 50 Via ) + ( Metal2 51 Metal2 ) + ( Glass 52 Glass ) + ( CapWell 59 CapWell ) + ( XP 60 XP ) + ( Via2 61 Via2 ) + ( Metal3 62 Metal3 ) + ( A1 80 A1 ) + ( A2 81 A2 ) + ( comment 117 comment ) + ;System-Reserved Layers: + ( Unrouted 200 Unroute ) + ( Row 201 Row ) + ( Group 202 Group ) + ( Cannotoccupy 203 Cannoto ) + ( Canplace 204 Canplac ) + ( hardFence 205 hardFen ) + ( softFence 206 softFen ) + ( y0 207 y0 ) + ( y1 208 y1 ) + ( y2 209 y2 ) + ( y3 210 y3 ) + ( y4 211 y4 ) + ( y5 212 y5 ) + ( y6 213 y6 ) + ( y7 214 y7 ) + ( y8 215 y8 ) + ( y9 216 y9 ) + ( designFlow 217 designF ) + ( stretch 218 stretch ) + ( edgeLayer 219 edgeLay ) + ( changedLayer 220 changed ) + ( unset 221 unset ) + ( unknown 222 unknown ) + ( spike 223 spike ) + ( hiz 224 hiz ) + ( resist 225 resist ) + ( drive 226 drive ) + ( supply 227 supply ) + ( wire 228 wire ) + ( pin 229 pin ) + ( text 230 text ) + ( device 231 device ) + ( border 232 border ) + ( snap 233 snap ) + ( align 234 align ) + ( prBoundary 235 prBound ) + ( instance 236 instanc ) + ( annotate 237 annotat ) + ( marker 238 marker ) + ( select 239 select ) + ( grid 251 grid ) + ( axis 252 axis ) + ( hilite 253 hilite ) + ( background 254 backgro ) + ) ;techLayers + + techPurposes( + ;( PurposeName Purpose# Abbreviation ) + ;( ----------- -------- ------------ ) + ;User-Defined Purposes: + ;System-Reserved Purposes: + ( warning 234 wng ) + ( tool1 235 tl1 ) + ( tool0 236 tl0 ) + ( label 237 lbl ) + ( flight 238 flt ) + ( error 239 err ) + ( annotate 240 ant ) + ( drawing1 241 dr1 ) + ( drawing2 242 dr2 ) + ( drawing3 243 dr3 ) + ( drawing4 244 dr4 ) + ( drawing5 245 dr5 ) + ( drawing6 246 dr6 ) + ( drawing7 247 dr7 ) + ( drawing8 248 dr8 ) + ( drawing9 249 dr9 ) + ( boundary 250 bnd ) + ( pin 251 pin ) + ( drawing 252 drw ) + ( net 253 net ) + ( cell 254 cel ) + ( all 255 all ) + ) ;techPurposes + + techLayerPurposePriorities( + ;layers are ordered from lowest to highest priority + ; (higher priority is drawn on top of lower priority) + ;( LayerName Purpose ) + ;( --------- ------- ) + ( background drawing ) + ( grid drawing ) + ( grid drawing1 ) + ( Nwell drawing ) + ( Pwell drawing ) + ( CapWell drawing ) + ( Pselect drawing ) + ( Nselect drawing ) + ( Active drawing ) + ( ActX drawing ) + ( SiBlock drawing ) + ( HR drawing ) + ( Poly1 drawing ) + ( P1Con drawing ) + ( Poly2 drawing ) + ( P2Con drawing ) + ( Metal1 drawing ) + ( Via drawing ) + ( Metal2 drawing ) + ( Via2 drawing ) + ( Metal3 drawing ) + ( annotate drawing ) + ( annotate drawing1 ) + ( annotate drawing2 ) + ( annotate drawing3 ) + ( annotate drawing4 ) + ( annotate drawing5 ) + ( annotate drawing6 ) + ( annotate drawing7 ) + ( annotate drawing8 ) + ( annotate drawing9 ) + ( Poly1 pin ) + ( Metal1 pin ) + ( Metal2 pin ) + ( Metal3 pin ) + ( Glass drawing ) + ( XP drawing ) + ( prBoundary drawing ) + ( prBoundary boundary ) + ( instance drawing ) + ( prBoundary label ) + ( instance label ) + ( Row drawing ) + ( Nwell net ) + ( align drawing ) + ( Pwell net ) + ( CapWell net ) + ( hardFence drawing ) + ( Active net ) + ( softFence drawing ) + ( Row label ) + ( Group drawing ) + ( Group label ) + ( Cannotoccupy drawing ) + ( Cannotoccupy boundary ) + ( Canplace drawing ) + ( ActX net ) + ( A2 drawing ) + ( A1 drawing ) + ( comment drawing ) + ( border drawing ) + ( Pselect net ) + ( Nselect net ) + ( SiBlock net ) + ( HR net ) + ( wire drawing ) + ( Poly1 net ) + ( wire label ) + ( P1Con net ) + ( wire flight ) + ( Metal1 net ) + ( device annotate ) + ( Metal2 net ) + ( device label ) + ( Via net ) + ( Metal3 net ) + ( Via2 net ) + ( pin label ) + ( text drawing ) + ( pin drawing ) + ( text drawing1 ) + ( pin annotate ) + ( device drawing ) + ( axis drawing ) + ( edgeLayer drawing ) + ( edgeLayer pin ) + ( snap drawing ) + ( stretch drawing ) + ( y0 drawing ) + ( y1 drawing ) + ( y2 drawing ) + ( y3 drawing ) + ( y4 drawing ) + ( y5 drawing ) + ( y6 drawing ) + ( y7 drawing ) + ( y8 drawing ) + ( y9 drawing ) + ( hilite drawing ) + ( hilite drawing1 ) + ( hilite drawing2 ) + ( hilite drawing3 ) + ( hilite drawing4 ) + ( hilite drawing5 ) + ( hilite drawing6 ) + ( hilite drawing7 ) + ( hilite drawing8 ) + ( hilite drawing9 ) + ( select drawing ) + ( drive drawing ) + ( hiz drawing ) + ( resist drawing ) + ( spike drawing ) + ( supply drawing ) + ( unknown drawing ) + ( unset drawing ) + ( designFlow drawing ) + ( designFlow drawing1 ) + ( designFlow drawing2 ) + ( designFlow drawing3 ) + ( designFlow drawing4 ) + ( designFlow drawing5 ) + ( designFlow drawing6 ) + ( designFlow drawing7 ) + ( designFlow drawing8 ) + ( designFlow drawing9 ) + ( changedLayer tool0 ) + ( changedLayer tool1 ) + ( marker warning ) + ( marker error ) + ( device drawing1 ) + ( Pbase drawing ) + ( Pbase net ) + ( Resistor net ) + ( Resistor drawing ) + ( Capacitor net ) + ( Capacitor drawing ) + ( Diode net ) + ( Diode drawing ) + ( Poly2 net ) + ( P2Con net ) + ( device drawing2 ) + ( Unrouted drawing ) + ( text drawing2 ) + ( Unrouted drawing1 ) + ( Unrouted drawing2 ) + ( Unrouted drawing3 ) + ( Unrouted drawing4 ) + ( Unrouted drawing5 ) + ( Unrouted drawing6 ) + ( Unrouted drawing7 ) + ( Unrouted drawing8 ) + ( Unrouted drawing9 ) + ) ;techLayerPurposePriorities + + techDisplays( + ;( LayerName Purpose Packet Vis Sel Con2ChgLy DrgEnbl Valid ) + ;( --------- ------- ------ --- --- --------- ------- ----- ) + ( background drawing background t nil nil nil nil ) + ( grid drawing grid t nil nil nil nil ) + ( grid drawing1 grid1 t nil nil nil nil ) + ( Nwell drawing Nwell t t t t t ) + ( Pwell drawing Pwell t t t t nil ) + ( Active drawing Active t t t t t ) + ( ActX drawing ActX t t t t t ) + ( Pselect drawing Pselect t t t t t ) + ( Nselect drawing Nselect t t t t t ) + ( SiBlock drawing SiBlock t t t t t ) + ( HR drawing HR t t t t t ) + ( CapWell drawing CapWell t t t t t ) + ( Poly1 drawing Poly1 t t t t t ) + ( P1Con drawing P1Con t t t t t ) + ( Metal1 drawing Metal1 t t t t t ) + ( Via drawing Via t t t t t ) + ( Metal2 drawing Metal2 t t t t t ) + ( annotate drawing annotate t t nil t nil ) + ( annotate drawing1 annotate1 t t nil t nil ) + ( annotate drawing2 annotate2 t t nil t nil ) + ( annotate drawing3 annotate3 t t nil t nil ) + ( annotate drawing4 annotate4 t t nil t nil ) + ( annotate drawing5 annotate5 t t nil t nil ) + ( annotate drawing6 annotate6 t t nil t nil ) + ( annotate drawing7 annotate7 t t nil t nil ) + ( annotate drawing8 annotate8 t t nil t nil ) + ( annotate drawing9 annotate9 t t nil t nil ) + ( Via2 drawing Via2 t t t t t ) + ( Metal3 drawing Metal3 t t t t t ) + ( Glass drawing Glass t t t nil t ) + ( XP drawing XP t t t nil t ) + ( Metal1 pin Metal1Pin t t t nil t ) + ( Metal2 pin Metal2Pin t t t nil t ) + ( Metal3 pin Metal3Pin t t t nil t ) + ( Poly1 pin Poly1Pin t t t nil t ) + ( prBoundary drawing prBoundary t t nil t nil ) + ( prBoundary boundary prBoundaryBnd t t nil t nil ) + ( instance drawing instance t t nil t t ) + ( prBoundary label prBoundaryLbl t t t t nil ) + ( instance label instanceLbl t t t t nil ) + ( Row drawing Row t t t t nil ) + ( Nwell net NwellNet t t t nil nil ) + ( align drawing align t t nil t nil ) + ( Pwell net PwellNet t t t nil nil ) + ( CapWell net CapWellNet t t t nil nil ) + ( SiBlock net SiBlockNet t t t nil nil ) + ( HR net HRnet t t t nil nil ) + ( hardFence drawing hardFence t t t t nil ) + ( Active net ActiveNet t t t nil nil ) + ( softFence drawing softFence t t t t nil ) + ( Row label RowLbl t t t t nil ) + ( Group drawing Group t t t t nil ) + ( Group label GroupLbl t t t t nil ) + ( Cannotoccupy drawing Cannotoccupy t t t t nil ) + ( Cannotoccupy boundary CannotoccupyBnd t t t t nil ) + ( Canplace drawing Canplace t t t t nil ) + ( ActX net ActXNet t t t nil nil ) + ( A2 drawing A2 t t t t nil ) + ( A1 drawing A1 t t t t nil ) + ( comment drawing comment t t t t nil ) + ( border drawing border t t t t nil ) + ( Pselect net PselectNet t t t nil nil ) + ( Nselect net NselectNet t t t nil nil ) + ( wire drawing wire t t t t nil ) + ( Poly1 net Poly1Net t t t nil nil ) + ( wire label wireLbl t t t t nil ) + ( P1Con net P1ConNet t t t nil nil ) + ( wire flight wireFlt t t t t nil ) + ( Metal1 net Metal1Net t t t nil nil ) + ( device annotate deviceAnt t t t t nil ) + ( Metal2 net Metal2Net t t t nil nil ) + ( Metal3 net Metal3Net t t t nil nil ) + ( device label deviceLbl t t t t nil ) + ( Via net ViaNet t t t nil nil ) + ( Via2 net Via2Net t t t nil nil ) + ( pin label pinLbl t t t t nil ) + ( text drawing text t t t t t ) + ( pin drawing pin t t t t nil ) + ( text drawing1 text1 t t t t nil ) + ( pin annotate pinAnt t t t t nil ) + ( device drawing device t t t t nil ) + ( axis drawing axis t t t t nil ) + ( edgeLayer drawing edgeLayer t t nil t nil ) + ( edgeLayer pin edgeLayerPin t t nil t nil ) + ( snap drawing snap t t nil t nil ) + ( stretch drawing stretch t t nil t nil ) + ( y0 drawing y0 t t nil t nil ) + ( y1 drawing y1 t t nil t nil ) + ( y2 drawing y2 t t nil t nil ) + ( y3 drawing y3 t t nil t nil ) + ( y4 drawing y4 t t nil t nil ) + ( y5 drawing y5 t t nil t nil ) + ( y6 drawing y6 t t nil t nil ) + ( y7 drawing y7 t t nil t nil ) + ( y8 drawing y8 t t nil t nil ) + ( y9 drawing y9 t t nil t nil ) + ( hilite drawing hilite t t nil t nil ) + ( hilite drawing1 hilite1 t t t t nil ) + ( hilite drawing2 hilite2 t t nil t nil ) + ( hilite drawing3 hilite3 t t t t nil ) + ( hilite drawing4 hilite4 t t t t nil ) + ( hilite drawing5 hilite5 t t t t nil ) + ( hilite drawing6 hilite6 t t t t nil ) + ( hilite drawing7 hilite7 t t t t nil ) + ( hilite drawing8 hilite8 t t t t nil ) + ( hilite drawing9 hilite9 t t t t nil ) + ( select drawing select t t nil t nil ) + ( drive drawing drive t t t t nil ) + ( hiz drawing hiz t t t t nil ) + ( resist drawing resist t t t t nil ) + ( spike drawing spike t t t t nil ) + ( supply drawing supply t t t t nil ) + ( unknown drawing unknown t t t t nil ) + ( unset drawing unset t t t t nil ) + ( designFlow drawing designFlow t t t nil nil ) + ( designFlow drawing1 designFlow1 t t t nil nil ) + ( designFlow drawing2 designFlow2 t t t nil nil ) + ( designFlow drawing3 designFlow3 t t t nil nil ) + ( designFlow drawing4 designFlow4 t t t nil nil ) + ( designFlow drawing5 designFlow5 t t t nil nil ) + ( designFlow drawing6 designFlow6 t t t nil nil ) + ( designFlow drawing7 designFlow7 t t t nil nil ) + ( designFlow drawing8 designFlow8 t t t nil nil ) + ( designFlow drawing9 designFlow9 t t t nil nil ) + ( changedLayer tool0 changedLayerTl0 nil nil nil nil nil ) + ( changedLayer tool1 changedLayerTl1 nil nil t nil nil ) + ( marker warning markerWarn t t t t nil ) + ( marker error markerErr t t t t nil ) + ( device drawing1 device1 t t t t nil ) + ( Poly2 net Poly2Net t t t nil nil ) + ( Poly2 drawing Poly2 t t t t t ) + ( P2Con net P2ConNet t t t nil nil ) + ( P2Con drawing P2Con t t t t t ) + ( Pbase net PbaseNet t t t nil nil ) + ( Pbase drawing Pbase t t t t t ) + ( Resistor net ResistorNet t t t nil nil ) + ( Resistor drawing Resistor t t t t t ) + ( Capacitor net CapacitorNet t t t nil nil ) + ( Capacitor drawing Capacitor t t t t t ) + ( Diode net DiodeNet t t t nil nil ) + ( Diode drawing Diode t t t t t ) + ( device drawing2 device2 t t t t nil ) + ( Unrouted drawing Unrouted t t t t nil ) + ( text drawing2 text2 t t t t nil ) + ( Unrouted drawing1 Unrouted1 t t t t nil ) + ( Unrouted drawing2 Unrouted2 t t t t nil ) + ( Unrouted drawing3 Unrouted3 t t t t nil ) + ( Unrouted drawing4 Unrouted4 t t t t nil ) + ( Unrouted drawing5 Unrouted5 t t t t nil ) + ( Unrouted drawing6 Unrouted6 t t t t nil ) + ( Unrouted drawing7 Unrouted7 t t t t nil ) + ( Unrouted drawing8 Unrouted8 t t t t nil ) + ( Unrouted drawing9 Unrouted9 t t t t nil ) + ) ;techDisplays + +; I don't think the following is necessary (or used!) +techLayerProperties( +;( PropName Layer1 [ Layer2 ] PropValue ) + ( contactLimit P2Con 10000 ) + ( eqPinLimit P2Con 10000 ) + ( horizontalJogLength P2Con 2147483648.000000 ) + ( routingGrid P2Con 1.000000 ) + ( verticalJogLength P2Con 2147483648.000000 ) + ( routingGrid Poly2 1.000000 ) + ( contactLimit Active 10000 ) + ( eqPinLimit Active 10000 ) + ( horizontalJogLength Active 2147483648.000000 ) + ( routingGrid Active 1.000000 ) + ( verticalJogLength Active 2147483648.000000 ) + ( routingGrid Poly1 1.000000 ) + ( contactLimit P1Con 10000 ) + ( eqPinLimit P1Con 10000 ) + ( horizontalJogLength P1Con 2147483648.000000 ) + ( routingGrid P1Con 1.000000 ) + ( verticalJogLength P1Con 2147483648.000000 ) + ( contactLimit ActX 10000 ) + ( eqPinLimit ActX 10000 ) + ( horizontalJogLength ActX 2147483648.000000 ) + ( routingGrid ActX 1.000000 ) + ( verticalJogLength ActX 2147483648.000000 ) + ( routingGrid Metal1 1.000000 ) + ( contactLimit Via 10000 ) + ( eqPinLimit Via 10000 ) + ( horizontalJogLength Via 2147483648.000000 ) + ( routingGrid Via 1.000000 ) + ( verticalJogLength Via 2147483648.000000 ) + ( routingGrid Metal2 1.000000 ) +) + +) ;layerDefinitions + + +;******************************** +; DEVICE RULES +;******************************** + +devices( + tcCreateCDSDeviceClass() + + symContactDevice( + ;( deviceName viaLayer viaPurpose + ( VIA Via drawing + + ; layer1 purpose1 [implant1] + Metal1 drawing + + ; layer2 purpose2 [implant2] + Metal2 drawing + + ; width length [( row column xPitch yPitch xBias yBias )] + ; 2 2 ( 1 1 _NA_ _NA_ _NA_ _NA_ ) + 2 2 + + ; encLayer1 encLayer2 legalRegion ) + 1 1 _NA_) + ) ;symContactDevice + + symContactDevice( + ;( deviceName viaLayer viaPurpose + ( VIA2 Via2 drawing + + ; layer1 purpose1 [implant1] + Metal2 drawing + + ; layer2 purpose2 [implant2] + Metal3 drawing + + ; width length [( row column xPitch yPitch xBias yBias )] + ; 2 2 ( 1 1 _NA_ _NA_ _NA_ _NA_ ) + 2 2 + + ; encLayer1 encLayer2 legalRegion ) + 1 2 _NA_) + ) ;symContactDevice + +) ;devices + + +;******************************** +; LAYER RULES +;******************************** + +layerRules( + streamLayers( + ;( layer streamNumber dataType translate ) + ;( ----- ------------ -------- --------- ) + ( ("background" "drawing") 0 0 nil ) + ( ("grid" "drawing") 0 0 nil ) + ( ("grid" "drawing1") 0 0 nil ) + ( ("Nwell" "drawing") 42 0 t ) + ( ("Pwell" "drawing") 41 0 t ) + ( ("Active" "drawing") 43 0 t ) + ( ("ActX" "drawing") 48 0 t ) + ( ("Pselect" "drawing") 44 0 t ) + ( ("Nselect" "drawing") 45 0 t ) + ( ("Poly1" "drawing") 46 0 t ) + ( ("P1Con" "drawing") 47 0 t ) + ( ("Metal1" "drawing") 49 0 t ) + ( ("Metal2" "drawing") 51 0 t ) + ( ("annotate" "drawing") 0 0 nil ) + ( ("annotate" "drawing1") 0 0 nil ) + ( ("annotate" "drawing2") 0 0 nil ) + ( ("annotate" "drawing3") 0 0 nil ) + ( ("annotate" "drawing4") 0 0 nil ) + ( ("annotate" "drawing5") 0 0 nil ) + ( ("annotate" "drawing6") 0 0 nil ) + ( ("annotate" "drawing7") 0 0 nil ) + ( ("annotate" "drawing8") 0 0 nil ) + ( ("annotate" "drawing9") 0 0 nil ) + ( ("Via" "drawing") 50 0 t ) + ( ("Glass" "drawing") 52 0 t ) + ( ("XP" "drawing") 60 0 t ) + ( ("Metal2" "pin") 0 0 nil ) + ( ("Poly1" "pin") 0 0 nil ) + ( ("prBoundary" "drawing") 0 0 nil ) + ( ("Metal1" "pin") 0 0 nil ) + ( ("prBoundary" "boundary") 0 0 nil ) + ( ("instance" "drawing") 246 0 nil ) + ( ("instance" "label") 0 0 nil ) + ( ("Nwell" "net") 0 0 nil ) + ( ("align" "drawing") 0 0 nil ) + ( ("Pwell" "net") 0 0 nil ) + ( ("hardFence" "drawing") 0 0 nil ) + ( ("Active" "net") 0 0 nil ) + ( ("softFence" "drawing") 0 0 nil ) + ( ("ActX" "net") 0 0 nil ) + ( ("A2" "drawing") 5 0 nil ) + ( ("A1" "drawing") 2 0 nil ) + ( ("comment" "drawing") 0 0 nil ) + ( ("border" "drawing") 0 0 nil ) + ( ("Pselect" "net") 0 0 nil ) + ( ("Nselect" "net") 0 0 nil ) + ( ("wire" "drawing") 0 0 nil ) + ( ("Poly1" "net") 0 0 nil ) + ( ("P1Con" "net") 0 0 nil ) + ( ("Metal1" "net") 0 0 nil ) + ( ("Metal2" "net") 0 0 nil ) + ( ("device" "label") 0 0 nil ) + ( ("Via" "net") 0 0 nil ) + ( ("pin" "label") 0 0 nil ) + ( ("text" "drawing") 63 0 t ) + ( ("pin" "drawing") 0 0 nil ) + ( ("device" "drawing") 0 0 nil ) + ( ("axis" "drawing") 0 0 nil ) + ( ("edgeLayer" "drawing") 0 0 nil ) + ( ("edgeLayer" "pin") 0 0 nil ) + ( ("snap" "drawing") 0 0 nil ) + ( ("stretch" "drawing") 0 0 nil ) + ( ("y0" "drawing") 0 0 nil ) + ( ("y1" "drawing") 0 0 nil ) + ( ("y2" "drawing") 0 0 nil ) + ( ("y3" "drawing") 0 0 nil ) + ( ("y4" "drawing") 0 0 nil ) + ( ("y5" "drawing") 0 0 nil ) + ( ("y6" "drawing") 0 0 nil ) + ( ("y7" "drawing") 0 0 nil ) + ( ("y8" "drawing") 0 0 nil ) + ( ("y9" "drawing") 0 0 nil ) + ( ("hilite" "drawing") 0 0 nil ) + ( ("hilite" "drawing2") 0 0 nil ) + ( ("select" "drawing") 0 0 nil ) + ( ("drive" "drawing") 0 0 nil ) + ( ("hiz" "drawing") 0 0 nil ) + ( ("resist" "drawing") 0 0 nil ) + ( ("spike" "drawing") 0 0 nil ) + ( ("supply" "drawing") 0 0 nil ) + ( ("unknown" "drawing") 0 0 nil ) + ( ("unset" "drawing") 0 0 nil ) + ( ("changedLayer" "tool0") 0 0 nil ) + ( ("Resistor" "net") 0 0 nil ) + ( ("Resistor" "drawing") 0 0 nil ) + ( ("Capacitor" "net") 0 0 nil ) + ( ("Capacitor" "drawing") 0 0 nil ) + ( ("Diode" "net") 0 0 nil ) + ( ("Diode" "drawing") 0 0 nil ) + ( ("Poly2" "net") 0 0 nil ) + ( ("Poly2" "drawing") 0 0 nil ) + ( ("P2Con" "net") 0 0 nil ) + ( ("P2Con" "drawing") 0 0 nil ) + ( ("Pbase" "drawing") 0 0 nil ) + ( ("Pbase" "net") 0 0 nil ) + ( P2Con 0 0 nil ) + ( Poly2 0 0 nil ) + ( Pwell 0 0 nil ) + ( Nwell 0 0 nil ) + ( Active 0 0 nil ) + ( Pselect 0 0 nil ) + ( Nselect 0 0 nil ) + ( Poly1 0 0 nil ) + ( P1Con 0 0 nil ) + ( ActX 0 0 nil ) + ( Metal1 0 0 nil ) + ( Via 0 0 nil ) + ( Metal2 0 0 nil ) + ( Glass 0 0 nil ) + ( XP 0 0 nil ) + ( ("Via2" "drawing") 50 0 t ) + ( ("Via2" "net") 0 0 nil ) + ( ("Metal3" "drawing") 50 0 t ) + ( ("Metal3" "net") 0 0 nil ) + ( ("Metal3" "pin") 0 0 nil ) + ( ("CapWell" "drawing") 0 0 nil ) + ( ("CapWell" "net") 0 0 nil ) + ( ("SiBlock" "drawing") 0 0 nil ) + ( ("SiBlock" "net") 0 0 nil ) + ( ("HR" "drawing") 0 0 nil ) + ( ("HR" "net") 0 0 nil ) + ) ;streamLayers + + viaLayers( + ;( layer1 viaLayer layer2 ) + ;( ------ -------- ------ ) + ( Metal2 Via2 Metal3 ) + ( Metal1 Via Metal2 ) + ( Active ActX Poly1 ) + ( Poly1 P1Con Metal1 ) + ( Poly2 P2Con Metal1 ) + ) ;viaLayers + +) ;layerRules + + +;******************************** +; PHYSICAL RULES +;******************************** + +physicalRules( + orderedSpacingRules( + ;( rule layer1 layer2 value ) + ;( ---- ------ ------ ----- ) + ( minEnclosure "prBoundary" "Metal1" 0.0 ) + ( minEnclosure "Metal2" "Via" 1.0 ) + ( minEnclosure "Metal1" "Via" 1.0 ) + ( minEnclosure "Metal1" "P1Con" 1.0 ) + ( minEnclosure "Metal1" "ActX" 1.0 ) + ( minEnclosure "Nselect" "Active" 2.0 ) + ( minEnclosure "Pselect" "Active" 2.0 ) + ( minEnclosure "Active" "ActX" 1.0 ) + ( minEnclosure "Pwell" "Active" 5.0 ) + ( minEnclosure "Nwell" "Active" 5.0 ) + ) ;orderedSpacingRules + + spacingRules( + ;( rule layer1 layer2 value ) + ;( ---- ------ ------ ----- ) + ( minSpacing "P2Con" 2.0 ) + ( minSpacing "Poly2" 3.0 ) + ( minSpacing "Pwell" 9.0 ) + ( minSpacing "Nwell" 9.0 ) + ( minSpacing "Active" 3.0 ) + ( minSpacing "Pselect" 2.0 ) + ( minSpacing "Nselect" 2.0 ) + ( minSpacing "Poly1" 2.0 ) + ( minSpacing "P1Con" 2.0 ) + ( minSpacing "ActX" 2.0 ) + ( minSpacing "Metal1" 3.0 ) + ( minSpacing "Via" 3.0 ) + ( minSpacing "Via2" 3.0 ) + ( minSpacing "Metal2" 3.0 ) + ( minSpacing "Metal3" 4.0 ) + ( minSpacing "Glass" 75.0 ) + ( minSpacing "XP" 100.0 ) + ( minSpacing "Metal2" 4.0 ) + ( minSpacing "P1Con" "Via" 2.0 ) + ( minSpacing "ActX" "Via" 2.0 ) + ( minSpacing "ActX" "P2Con" 2.0 ) + ( minSpacing "Poly2" "P2Con" 4.0 ) + ( minSpacing "Poly1" "P1Con" 4.0 ) + ( minSpacing "ActX" "P1Con" 2.0 ) + ( minSpacing "Active" "P1Con" 2.0 ) + ( minSpacing "Active" "Poly2" 2.0 ) + ( minSpacing "Poly1" "Poly2" 2.0 ) + ( minSpacing "Active" "Poly1" 2.0 ) + ( minSpacing "ActX" "Poly1" 2.0 ) + ( minSpacing "Pselect" "Nselect" 0.0 ) + ( minSpacing "Nwell" "Pwell" 9.0 ) + ( minWidth "P2Con" 2.0 ) + ( minWidth "Poly2" 3.0 ) + ( minWidth "Pwell" 10.0 ) + ( minWidth "Nwell" 10.0 ) + ( minWidth "Active" 3.0 ) + ( minWidth "Pselect" 2.0 ) + ( minWidth "Nselect" 2.0 ) + ( minWidth "Poly1" 2.0 ) + ( minWidth "P1Con" 2.0 ) + ( minWidth "ActX" 2.0 ) + ( minWidth "Metal1" 4.0 ) + ( minWidth "Via" 2.0 ) + ( minWidth "Metal2" 4.0 ) + ( minWidth "Glass" 75.0 ) + ( minWidth "XP" 100.0 ) + ( minWidth "Metal3" 6.0 ) + ) ;spacingRules + + mfgGridResolution( + ( 1.000000 ) + ) ;mfgGridResolution + +) ;physicalRules + + +;******************************** +; ELECTRICAL RULES +;******************************** + +electricalRules( + characterizationRules( + ;( rule layer1 layer2 value ) + ;( ---- ------ ------ ----- ) + ( areaCap "P2Con" 0.0 ) + ( areaCap "Poly2" 0.0 ) + ( areaCap "Active" 0.0 ) + ( areaCap "Poly1" 6e-05 ) + ( areaCap "P1Con" 0.0 ) + ( areaCap "ActX" 0.0 ) + ( areaCap "Metal1" 2.6e-05 ) + ( areaCap "Via" 0.0 ) + ( areaCap "Metal2" 1.6e-05 ) + ( edgeCapacitance "P2Con" 0.0 ) + ( edgeCapacitance "Poly2" 0.0 ) + ( edgeCapacitance "Active" 0.0 ) + ( edgeCapacitance "Poly1" 0.0 ) + ( edgeCapacitance "P1Con" 0.0 ) + ( edgeCapacitance "ActX" 0.0 ) + ( edgeCapacitance "Metal1" 0.0 ) + ( edgeCapacitance "Via" 0.0 ) + ( edgeCapacitance "Metal2" 0.0 ) + ( sheetRes "P2Con" 0.0 ) + ( sheetRes "Poly2" 0.0 ) + ( sheetRes "Active" 0.0 ) + ( sheetRes "Poly1" 23.0 ) + ( sheetRes "P1Con" 0.0 ) + ( sheetRes "ActX" 0.0 ) + ( sheetRes "Metal1" 0.04 ) + ( sheetRes "Via" 0.0 ) + ( sheetRes "Metal2" 0.07 ) + ( currentDensity "P2Con" 1.0 ) + ( currentDensity "Poly2" 1.0 ) + ( currentDensity "Active" 1.0 ) + ( currentDensity "Poly1" 1.0 ) + ( currentDensity "P1Con" 1.0 ) + ( currentDensity "ActX" 1.0 ) + ( currentDensity "Metal1" 1.0 ) + ( currentDensity "Via" 1.0 ) + ( currentDensity "Metal2" 1.0 ) + ) ;characterizationRules + +) ;electricalRules + + +;******************************** +; LAYOUT EDITOR RULES +;******************************** +; specifies the ordering of the layers in the LSW + +leRules( + leLswLayers( + ;( layer purpose ) + ; ----- ------- ) + ( Nwell drawing ) + ( Pselect drawing ) + ( Nselect drawing ) + ( Active drawing ) + ( ActX drawing ) + ( Poly1 drawing ) + ( P1Con drawing ) + ( Metal1 drawing ) + ( Via drawing ) + ( Metal2 drawing ) + ( Via2 drawing ) + ( Metal3 drawing ) + ( Poly1 pin ) + ( Metal1 pin ) + ( Metal2 pin ) + ( Metal3 pin ) + ( Poly2 drawing ) + ( P2Con drawing ) + ( instance drawing ) + ( text drawing ) + ( CapWell drawing ) + ( SiBlock drawing ) + ( HR drawing ) + ( Pbase drawing ) + ( Resistor drawing ) + ( Capacitor drawing ) + ( Diode drawing ) + ( Glass drawing ) + ( XP drawing ) + + ) ;leLswLayers +) ;leRules + + +;******************************** +; VIRTUOSO XL RULES +;******************************** +; specifies the ordering of the layers in the LSW + +lxRules( + lxExtractLayers( + (Metal1 Metal2 Metal3) + ) ;lxExtractLayers +) ;lxRules + diff --git a/technology/scn4m_subm/__init__.py b/technology/scn4m_subm/__init__.py index e54e3e33..c7a863f0 100644 --- a/technology/scn4m_subm/__init__.py +++ b/technology/scn4m_subm/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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. # #!/usr/bin/python """ diff --git a/technology/scn4m_subm/gds_lib/cell_6t.gds b/technology/scn4m_subm/gds_lib/cell_6t.gds index df644048..14d6ab7e 100644 Binary files a/technology/scn4m_subm/gds_lib/cell_6t.gds and b/technology/scn4m_subm/gds_lib/cell_6t.gds differ diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds b/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds new file mode 100644 index 00000000..42727119 Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds differ diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds b/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds new file mode 100644 index 00000000..34d692e8 Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds differ diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds b/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds new file mode 100644 index 00000000..4a950a68 Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds differ diff --git a/technology/scn4m_subm/gds_lib/replica_cell_6t.gds b/technology/scn4m_subm/gds_lib/replica_cell_6t.gds index f16f7b13..191f1206 100644 Binary files a/technology/scn4m_subm/gds_lib/replica_cell_6t.gds and b/technology/scn4m_subm/gds_lib/replica_cell_6t.gds differ diff --git a/technology/scn4m_subm/gds_lib/write_driver.gds b/technology/scn4m_subm/gds_lib/write_driver.gds index 1f9274ac..8223c795 100644 Binary files a/technology/scn4m_subm/gds_lib/write_driver.gds and b/technology/scn4m_subm/gds_lib/write_driver.gds differ diff --git a/technology/scn4m_subm/mag_lib/cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/cell_1w_1r.mag new file mode 100644 index 00000000..9aec1c5d --- /dev/null +++ b/technology/scn4m_subm/mag_lib/cell_1w_1r.mag @@ -0,0 +1,142 @@ +magic +tech scmos +timestamp 1542220294 +<< nwell >> +rect 0 46 54 75 +<< pwell >> +rect 0 0 54 46 +<< ntransistor >> +rect 14 33 16 37 +rect 22 29 24 37 +rect 30 29 32 37 +rect 38 33 40 37 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 54 24 57 +rect 30 54 32 57 +<< ndiffusion >> +rect 13 33 14 37 +rect 16 33 17 37 +rect 21 33 22 37 +rect 17 29 22 33 +rect 24 29 25 37 +rect 29 29 30 37 +rect 32 33 33 37 +rect 37 33 38 37 +rect 40 33 41 37 +rect 32 29 37 33 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 17 25 23 +rect 29 17 30 23 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 54 22 57 +rect 24 54 25 57 +rect 29 54 30 57 +rect 32 54 33 57 +<< ndcontact >> +rect 9 33 13 37 +rect 17 33 21 37 +rect 25 29 29 37 +rect 33 33 37 37 +rect 41 33 45 37 +rect 25 17 29 23 +<< pdcontact >> +rect 17 54 21 58 +rect 33 54 37 58 +<< psubstratepcontact >> +rect 25 9 29 13 +<< polysilicon >> +rect 22 57 24 60 +rect 30 57 32 60 +rect 22 44 24 54 +rect 30 51 32 54 +rect 31 47 32 51 +rect 14 37 16 44 +rect 22 40 23 44 +rect 22 37 24 40 +rect 30 37 32 47 +rect 38 37 40 44 +rect 14 31 16 33 +rect 38 31 40 33 +rect 14 23 16 24 +rect 22 23 24 29 +rect 30 23 32 29 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 27 47 31 51 +rect 10 40 14 44 +rect 23 40 27 44 +rect 40 40 44 44 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 68 25 72 +rect 29 68 54 72 +rect 0 61 54 65 +rect 10 44 14 61 +rect 17 51 20 54 +rect 17 47 27 51 +rect 17 37 20 47 +rect 34 44 37 54 +rect 27 40 37 44 +rect 40 44 44 61 +rect 34 37 37 40 +rect 6 33 9 37 +rect 45 33 48 37 +rect 25 23 29 29 +rect 25 13 29 17 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 2 33 6 37 +rect 48 33 52 37 +rect 16 24 20 28 +rect 34 24 38 28 +rect 16 2 20 6 +rect 34 2 38 6 +<< pdm12contact >> +rect 25 54 29 58 +<< ndm12contact >> +rect 9 17 13 21 +rect 41 17 45 21 +<< nsm12contact >> +rect 25 68 29 72 +<< metal2 >> +rect 2 37 6 72 +rect 2 0 6 33 +rect 9 21 13 72 +rect 25 58 29 68 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 72 +rect 41 0 45 17 +rect 48 37 52 72 +rect 48 0 52 33 +<< comment >> +rect 0 0 54 70 +<< labels >> +rlabel metal1 19 63 19 63 1 wl0 +rlabel metal1 19 70 19 70 5 vdd +rlabel metal1 27 4 27 4 1 wl1 +rlabel psubstratepcontact 27 11 27 11 1 gnd +rlabel metal2 4 7 4 7 2 bl0 +rlabel metal2 11 7 11 7 1 bl1 +rlabel metal2 43 7 43 7 1 br1 +rlabel metal2 50 7 50 7 8 br0 +<< end >> diff --git a/technology/scn4m_subm/mag_lib/cell_6t.mag b/technology/scn4m_subm/mag_lib/cell_6t.mag index f2e9906a..bb9d943d 100644 --- a/technology/scn4m_subm/mag_lib/cell_6t.mag +++ b/technology/scn4m_subm/mag_lib/cell_6t.mag @@ -1,117 +1,118 @@ magic tech scmos -timestamp 1536091415 +timestamp 1560809302 << nwell >> -rect -8 29 42 51 +rect -8 35 42 57 << pwell >> -rect -8 -8 42 29 +rect -8 -2 42 35 << ntransistor >> -rect 7 10 9 18 -rect 29 10 31 18 -rect 10 3 14 5 -rect 24 3 28 5 +rect 7 16 9 24 +rect 29 16 31 24 +rect 10 9 14 11 +rect 24 9 28 11 << ptransistor >> -rect 7 37 11 40 -rect 27 37 31 40 +rect 7 43 11 46 +rect 27 43 31 46 << ndiffusion >> +rect -2 22 7 24 +rect 2 18 7 22 rect -2 16 7 18 -rect 2 12 7 16 -rect -2 10 7 12 -rect 9 14 10 18 -rect 9 10 14 14 -rect 28 14 29 18 -rect 24 10 29 14 +rect 9 20 10 24 +rect 9 16 14 20 +rect 28 20 29 24 +rect 24 16 29 20 +rect 31 22 36 24 +rect 31 18 32 22 rect 31 16 36 18 -rect 31 12 32 16 -rect 31 10 36 12 -rect 10 5 14 10 -rect 24 5 28 10 -rect 10 2 14 3 -rect 24 2 28 3 +rect 10 11 14 16 +rect 24 11 28 16 +rect 10 8 14 9 +rect 24 8 28 9 << pdiffusion >> -rect 2 37 7 40 -rect 11 37 12 40 -rect 26 37 27 40 -rect 31 37 32 40 +rect 2 43 7 46 +rect 11 43 12 46 +rect 26 43 27 46 +rect 31 43 32 46 << ndcontact >> -rect -2 12 2 16 -rect 10 14 14 18 -rect 24 14 28 18 -rect 32 12 36 16 -rect 10 -2 14 2 -rect 24 -2 28 2 +rect -2 18 2 22 +rect 10 20 14 24 +rect 24 20 28 24 +rect 32 18 36 22 +rect 10 4 14 8 +rect 24 4 28 8 << pdcontact >> -rect -2 36 2 40 -rect 12 36 16 40 -rect 22 36 26 40 -rect 32 36 36 40 +rect -2 42 2 46 +rect 12 42 16 46 +rect 22 42 26 46 +rect 32 42 36 46 << psubstratepcontact >> -rect -2 22 2 26 -rect 32 22 36 26 +rect -2 28 2 32 +rect 32 28 36 32 << nsubstratencontact >> -rect 32 44 36 48 +rect 32 50 36 54 << polysilicon >> -rect 7 40 11 42 -rect 27 40 31 42 -rect 7 35 11 37 -rect 7 21 9 35 -rect 27 34 31 37 -rect 15 33 31 34 -rect 19 32 31 33 -rect 7 20 21 21 -rect 7 19 24 20 -rect 7 18 9 19 -rect 29 18 31 32 -rect 7 8 9 10 -rect 17 5 21 6 -rect 29 8 31 10 -rect -2 3 10 5 -rect 14 3 24 5 -rect 28 3 36 5 +rect 7 46 11 48 +rect 27 46 31 48 +rect 7 41 11 43 +rect 7 27 9 41 +rect 27 40 31 43 +rect 15 39 31 40 +rect 19 38 31 39 +rect 7 26 21 27 +rect 7 25 24 26 +rect 7 24 9 25 +rect 29 24 31 38 +rect 7 14 9 16 +rect 17 11 21 12 +rect 29 14 31 16 +rect -2 9 10 11 +rect 14 9 24 11 +rect 28 9 36 11 << polycontact >> -rect 15 29 19 33 -rect 21 20 25 24 -rect 17 6 21 10 +rect 15 35 19 39 +rect 21 26 25 30 +rect 17 12 21 16 << metal1 >> -rect -2 44 15 48 -rect 19 44 32 48 -rect -2 40 2 44 -rect 32 40 36 44 -rect 11 36 12 40 -rect 26 36 27 40 -rect -2 26 2 29 -rect -2 16 2 22 -rect 11 18 15 36 -rect 23 24 27 36 -rect 25 20 27 24 -rect 14 14 15 18 -rect 23 18 27 20 -rect 32 26 36 29 -rect 23 14 24 18 -rect 32 16 36 22 -rect -2 6 17 9 -rect 21 6 36 9 -rect -2 5 36 6 +rect -2 50 15 54 +rect 19 50 32 54 +rect -2 46 2 50 +rect 32 46 36 50 +rect 11 42 12 46 +rect 26 42 27 46 +rect -2 32 2 35 +rect -2 22 2 28 +rect 11 24 15 42 +rect 23 30 27 42 +rect 25 26 27 30 +rect 14 20 15 24 +rect 23 24 27 26 +rect 32 32 36 35 +rect 23 20 24 24 +rect 32 22 36 28 +rect -2 12 17 15 +rect 21 12 36 15 +rect -2 11 36 12 << m2contact >> -rect 15 44 19 48 -rect -2 29 2 33 -rect 32 29 36 33 -rect 6 -2 10 2 -rect 20 -2 24 2 +rect 15 50 19 54 +rect -2 35 2 39 +rect 32 35 36 39 +rect 6 4 10 8 +rect 20 4 24 8 << metal2 >> -rect -2 33 2 48 -rect -2 -2 2 29 -rect 6 2 10 48 -rect 24 -2 28 48 -rect 32 33 36 48 -rect 32 -2 36 29 +rect -2 39 2 54 +rect -2 0 2 35 +rect 6 8 10 54 +rect 6 0 10 4 +rect 24 0 28 54 +rect 32 39 36 54 +rect 32 0 36 35 << bb >> -rect 0 0 34 46 +rect 0 0 34 52 << labels >> -rlabel metal2 0 0 0 0 1 gnd -rlabel metal2 34 0 34 0 1 gnd -rlabel m2contact 17 46 17 46 5 vdd -rlabel metal2 8 43 8 43 1 bl -rlabel metal2 26 43 26 43 1 br -rlabel metal1 4 7 4 7 1 wl +rlabel metal2 0 6 0 6 1 gnd +rlabel metal2 34 6 34 6 1 gnd +rlabel m2contact 17 52 17 52 5 vdd +rlabel metal2 8 49 8 49 1 bl +rlabel metal2 26 49 26 49 1 br +rlabel metal1 4 13 4 13 1 wl << end >> diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag b/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag new file mode 100644 index 00000000..60e24aca --- /dev/null +++ b/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag @@ -0,0 +1,136 @@ +magic +tech scmos +timestamp 1562188987 +<< nwell >> +rect 0 46 54 75 +<< pwell >> +rect 0 0 54 46 +<< ntransistor >> +rect 14 33 16 37 +rect 22 29 24 37 +rect 30 29 32 37 +rect 38 33 40 37 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 54 24 57 +rect 30 54 32 57 +<< ndiffusion >> +rect 13 33 14 37 +rect 16 33 17 37 +rect 21 33 22 37 +rect 17 29 22 33 +rect 24 29 25 37 +rect 29 29 30 37 +rect 32 33 33 37 +rect 37 33 38 37 +rect 40 33 41 37 +rect 32 29 37 33 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 17 25 23 +rect 29 17 30 23 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 54 22 57 +rect 24 54 25 57 +rect 29 54 30 57 +rect 32 54 33 57 +<< ndcontact >> +rect 9 33 13 37 +rect 17 33 21 37 +rect 25 29 29 37 +rect 33 33 37 37 +rect 41 33 45 37 +rect 9 17 13 21 +rect 25 17 29 23 +rect 41 17 45 21 +<< pdcontact >> +rect 17 54 21 58 +rect 25 54 29 58 +rect 33 54 37 58 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 25 68 29 72 +<< polysilicon >> +rect 22 57 24 60 +rect 30 57 32 60 +rect 22 44 24 54 +rect 30 51 32 54 +rect 31 47 32 51 +rect 14 37 16 44 +rect 22 40 23 44 +rect 22 37 24 40 +rect 30 37 32 47 +rect 38 37 40 44 +rect 14 31 16 33 +rect 38 31 40 33 +rect 14 23 16 24 +rect 22 23 24 29 +rect 30 23 32 29 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 27 47 31 51 +rect 10 40 14 44 +rect 23 40 27 44 +rect 40 40 44 44 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 68 25 72 +rect 29 68 54 72 +rect 0 61 54 65 +rect 10 44 14 61 +rect 17 51 20 54 +rect 17 47 27 51 +rect 17 37 20 47 +rect 34 44 37 54 +rect 27 40 37 44 +rect 40 44 44 61 +rect 34 37 37 40 +rect 2 33 9 37 +rect 45 33 52 37 +rect 25 23 29 29 +rect 25 13 29 17 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 68 29 72 +rect 25 54 29 58 +rect 16 24 20 28 +rect 34 24 38 28 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 0 6 72 +rect 9 0 13 72 +rect 25 58 29 68 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 0 45 72 +rect 48 0 52 72 +<< comment >> +rect 0 0 54 70 +<< labels >> +rlabel metal1 19 63 19 63 1 wl0 +rlabel metal1 19 70 19 70 5 vdd +rlabel metal1 27 4 27 4 1 wl1 +rlabel psubstratepcontact 27 11 27 11 1 gnd +rlabel metal2 4 7 4 7 2 bl0 +rlabel metal2 11 7 11 7 1 bl1 +rlabel metal2 43 7 43 7 1 br1 +rlabel metal2 50 7 50 7 8 br0 +<< end >> diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag new file mode 100644 index 00000000..03e49f03 --- /dev/null +++ b/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag @@ -0,0 +1,136 @@ +magic +tech scmos +timestamp 1562189027 +<< nwell >> +rect 0 46 54 75 +<< pwell >> +rect 0 0 54 46 +<< ntransistor >> +rect 14 33 16 37 +rect 22 29 24 37 +rect 30 29 32 37 +rect 38 33 40 37 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 54 24 57 +rect 30 54 32 57 +<< ndiffusion >> +rect 13 33 14 37 +rect 16 33 17 37 +rect 21 33 22 37 +rect 17 29 22 33 +rect 24 29 25 37 +rect 29 29 30 37 +rect 32 33 33 37 +rect 37 33 38 37 +rect 40 33 41 37 +rect 32 29 37 33 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 17 25 23 +rect 29 17 30 23 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 54 22 57 +rect 24 54 25 57 +rect 29 54 30 57 +rect 32 54 33 57 +<< ndcontact >> +rect 9 33 13 37 +rect 17 33 21 37 +rect 25 29 29 37 +rect 33 33 37 37 +rect 41 33 45 37 +rect 9 17 13 21 +rect 25 17 29 23 +rect 41 17 45 21 +<< pdcontact >> +rect 17 54 21 58 +rect 25 54 29 58 +rect 33 54 37 58 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 25 68 29 72 +<< polysilicon >> +rect 22 57 24 60 +rect 30 57 32 60 +rect 22 44 24 54 +rect 30 51 32 54 +rect 31 47 32 51 +rect 14 37 16 44 +rect 22 40 23 44 +rect 22 37 24 40 +rect 30 37 32 47 +rect 38 37 40 44 +rect 14 31 16 33 +rect 38 31 40 33 +rect 14 23 16 24 +rect 22 23 24 29 +rect 30 23 32 29 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 27 47 31 51 +rect 10 40 14 44 +rect 23 40 27 44 +rect 40 40 44 44 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 68 25 72 +rect 29 68 54 72 +rect 0 61 54 65 +rect 10 44 14 61 +rect 17 51 20 54 +rect 17 47 27 51 +rect 17 37 20 47 +rect 34 44 37 54 +rect 27 40 37 44 +rect 40 44 44 61 +rect 34 37 37 40 +rect 2 33 9 37 +rect 45 33 52 37 +rect 25 23 29 29 +rect 25 13 29 17 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 68 29 72 +rect 25 54 29 58 +rect 16 24 20 28 +rect 34 24 38 28 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 0 6 72 +rect 9 0 13 72 +rect 25 58 29 68 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 0 45 72 +rect 48 0 52 72 +<< comment >> +rect 0 0 54 70 +<< labels >> +rlabel metal1 19 63 19 63 1 wl0 +rlabel metal1 19 70 19 70 5 vdd +rlabel metal1 27 4 27 4 1 wl1 +rlabel psubstratepcontact 27 11 27 11 1 gnd +rlabel metal2 4 7 4 7 2 bl0 +rlabel metal2 11 7 11 7 1 bl1 +rlabel metal2 43 7 43 7 1 br1 +rlabel metal2 50 7 50 7 8 br0 +<< end >> diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag b/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag new file mode 100644 index 00000000..74562f15 --- /dev/null +++ b/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag @@ -0,0 +1,115 @@ +magic +tech scmos +timestamp 1560809362 +<< nwell >> +rect -8 35 42 57 +<< pwell >> +rect -8 -2 42 35 +<< ntransistor >> +rect 7 16 9 24 +rect 29 16 31 24 +rect 10 9 14 11 +rect 24 9 28 11 +<< ptransistor >> +rect 7 43 11 46 +rect 27 43 31 46 +<< ndiffusion >> +rect -2 22 7 24 +rect 2 18 7 22 +rect -2 16 7 18 +rect 9 20 10 24 +rect 9 16 14 20 +rect 28 20 29 24 +rect 24 16 29 20 +rect 31 22 36 24 +rect 31 18 32 22 +rect 31 16 36 18 +rect 10 11 14 16 +rect 24 11 28 16 +rect 10 8 14 9 +rect 24 8 28 9 +<< pdiffusion >> +rect 2 43 7 46 +rect 11 43 12 46 +rect 26 43 27 46 +rect 31 43 32 46 +<< ndcontact >> +rect -2 18 2 22 +rect 10 20 14 24 +rect 24 20 28 24 +rect 32 18 36 22 +rect 10 4 14 8 +rect 24 4 28 8 +<< pdcontact >> +rect -2 42 2 46 +rect 12 42 16 46 +rect 22 42 26 46 +rect 32 42 36 46 +<< psubstratepcontact >> +rect -2 28 2 32 +rect 32 28 36 32 +<< nsubstratencontact >> +rect 32 50 36 54 +<< polysilicon >> +rect 7 46 11 48 +rect 27 46 31 48 +rect 7 41 11 43 +rect 7 27 9 41 +rect 27 40 31 43 +rect 15 39 31 40 +rect 19 38 31 39 +rect 7 26 21 27 +rect 7 25 24 26 +rect 7 24 9 25 +rect 29 24 31 38 +rect 7 14 9 16 +rect 17 11 21 12 +rect 29 14 31 16 +rect -2 9 10 11 +rect 14 9 24 11 +rect 28 9 36 11 +<< polycontact >> +rect 15 35 19 39 +rect 21 26 25 30 +rect 17 12 21 16 +<< metal1 >> +rect -2 50 15 54 +rect 19 50 32 54 +rect -2 46 2 50 +rect 32 46 36 50 +rect 11 42 12 46 +rect 26 42 27 46 +rect -2 32 2 35 +rect -2 22 2 28 +rect 11 24 15 42 +rect 23 30 27 42 +rect 25 26 27 30 +rect 14 20 15 24 +rect 23 24 27 26 +rect 32 32 36 35 +rect 23 20 24 24 +rect 32 22 36 28 +rect -2 12 17 15 +rect 21 12 36 15 +rect -2 11 36 12 +<< m2contact >> +rect 15 50 19 54 +rect -2 35 2 39 +rect 32 35 36 39 +<< metal2 >> +rect -2 39 2 54 +rect -2 0 2 35 +rect 6 0 10 54 +rect 24 0 28 54 +rect 32 39 36 54 +rect 32 0 36 35 +<< bb >> +rect 0 0 34 52 +<< labels >> +rlabel metal2 0 6 0 6 1 gnd +rlabel metal2 34 6 34 6 1 gnd +rlabel m2contact 17 52 17 52 5 vdd +rlabel metal2 8 49 8 49 1 bl +rlabel metal2 26 49 26 49 1 br +rlabel metal1 4 13 4 13 1 wl +<< end >> diff --git a/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag new file mode 100644 index 00000000..f215ff04 --- /dev/null +++ b/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag @@ -0,0 +1,145 @@ +magic +tech scmos +timestamp 1542221056 +<< nwell >> +rect 0 46 54 75 +<< pwell >> +rect 0 0 54 46 +<< ntransistor >> +rect 14 33 16 37 +rect 22 29 24 37 +rect 30 29 32 37 +rect 38 33 40 37 +rect 14 17 16 23 +rect 22 17 24 23 +rect 30 17 32 23 +rect 38 17 40 23 +<< ptransistor >> +rect 22 54 24 57 +rect 30 54 32 57 +<< ndiffusion >> +rect 13 33 14 37 +rect 16 33 17 37 +rect 21 33 22 37 +rect 17 29 22 33 +rect 24 29 25 37 +rect 29 29 30 37 +rect 32 33 33 37 +rect 37 33 38 37 +rect 40 33 41 37 +rect 32 29 37 33 +rect 9 21 14 23 +rect 13 17 14 21 +rect 16 17 22 23 +rect 24 17 25 23 +rect 29 17 30 23 +rect 32 17 38 23 +rect 40 21 45 23 +rect 40 17 41 21 +<< pdiffusion >> +rect 21 54 22 57 +rect 24 54 25 57 +rect 29 54 30 57 +rect 32 54 33 57 +<< ndcontact >> +rect 9 33 13 37 +rect 17 33 21 37 +rect 25 29 29 37 +rect 33 33 37 37 +rect 41 33 45 37 +rect 9 17 13 21 +rect 25 17 29 23 +rect 41 17 45 21 +<< pdcontact >> +rect 17 54 21 58 +rect 25 54 29 58 +rect 33 54 37 58 +<< psubstratepcontact >> +rect 25 9 29 13 +<< nsubstratencontact >> +rect 25 68 29 72 +<< polysilicon >> +rect 22 57 24 60 +rect 30 57 32 60 +rect 22 44 24 54 +rect 30 51 32 54 +rect 31 47 32 51 +rect 14 37 16 44 +rect 22 40 23 44 +rect 22 37 24 40 +rect 30 37 32 47 +rect 38 37 40 44 +rect 14 31 16 33 +rect 38 31 40 33 +rect 14 23 16 24 +rect 22 23 24 29 +rect 30 23 32 29 +rect 38 23 40 24 +rect 14 15 16 17 +rect 22 15 24 17 +rect 30 15 32 17 +rect 38 15 40 17 +<< polycontact >> +rect 27 47 31 51 +rect 10 40 14 44 +rect 23 40 27 44 +rect 40 40 44 44 +rect 12 24 16 28 +rect 38 24 42 28 +<< metal1 >> +rect 0 68 25 72 +rect 29 68 54 72 +rect 0 61 54 65 +rect 10 44 14 61 +rect 29 54 33 58 +rect 17 51 20 54 +rect 17 47 27 51 +rect 17 37 20 47 +rect 34 44 37 54 +rect 27 40 37 44 +rect 40 44 44 61 +rect 34 37 37 40 +rect 6 33 9 37 +rect 45 33 48 37 +rect 25 23 29 29 +rect 25 13 29 17 +rect 0 9 25 13 +rect 29 9 54 13 +rect 0 2 16 6 +rect 20 2 34 6 +rect 38 2 54 6 +<< m2contact >> +rect 25 68 29 72 +rect 25 54 29 58 +rect 2 33 6 37 +rect 48 33 52 37 +rect 16 24 20 28 +rect 34 24 38 28 +rect 9 17 13 21 +rect 41 17 45 21 +rect 16 2 20 6 +rect 34 2 38 6 +<< metal2 >> +rect 2 37 6 72 +rect 2 0 6 33 +rect 9 21 13 72 +rect 25 58 29 68 +rect 9 0 13 17 +rect 16 6 20 24 +rect 34 6 38 24 +rect 41 21 45 72 +rect 41 0 45 17 +rect 48 37 52 72 +rect 48 0 52 33 +<< comment >> +rect 0 0 54 70 +<< labels >> +rlabel metal1 19 63 19 63 1 wl0 +rlabel metal1 19 70 19 70 5 vdd +rlabel metal1 27 4 27 4 1 wl1 +rlabel psubstratepcontact 27 11 27 11 1 gnd +rlabel metal2 4 7 4 7 2 bl0 +rlabel metal2 11 7 11 7 1 bl1 +rlabel metal2 43 7 43 7 1 br1 +rlabel metal2 50 7 50 7 8 br0 +<< end >> diff --git a/technology/scn4m_subm/mag_lib/replica_cell_6t.mag b/technology/scn4m_subm/mag_lib/replica_cell_6t.mag index c28cb2c6..b5a5f7b8 100644 --- a/technology/scn4m_subm/mag_lib/replica_cell_6t.mag +++ b/technology/scn4m_subm/mag_lib/replica_cell_6t.mag @@ -1,118 +1,119 @@ magic tech scmos -timestamp 1541443051 +timestamp 1560809329 << nwell >> -rect -8 29 42 51 +rect -8 35 42 57 << pwell >> -rect -8 -8 42 29 +rect -8 -2 42 35 << ntransistor >> -rect 7 10 9 18 -rect 29 10 31 18 -rect 10 3 14 5 -rect 24 3 28 5 +rect 7 16 9 24 +rect 29 16 31 24 +rect 10 9 14 11 +rect 24 9 28 11 << ptransistor >> -rect 7 37 11 40 -rect 27 37 31 40 +rect 7 43 11 46 +rect 27 43 31 46 << ndiffusion >> +rect -2 22 7 24 +rect 2 18 7 22 rect -2 16 7 18 -rect 2 12 7 16 -rect -2 10 7 12 -rect 9 14 10 18 -rect 9 10 14 14 -rect 28 14 29 18 -rect 24 10 29 14 +rect 9 20 10 24 +rect 9 16 14 20 +rect 28 20 29 24 +rect 24 16 29 20 +rect 31 22 36 24 +rect 31 18 32 22 rect 31 16 36 18 -rect 31 12 32 16 -rect 31 10 36 12 -rect 10 5 14 10 -rect 24 5 28 10 -rect 10 2 14 3 -rect 24 2 28 3 +rect 10 11 14 16 +rect 24 11 28 16 +rect 10 8 14 9 +rect 24 8 28 9 << pdiffusion >> -rect 2 37 7 40 -rect 11 37 12 40 -rect 26 37 27 40 -rect 31 37 32 40 +rect 2 43 7 46 +rect 11 43 12 46 +rect 26 43 27 46 +rect 31 43 32 46 << ndcontact >> -rect -2 12 2 16 -rect 10 14 14 18 -rect 24 14 28 18 -rect 32 12 36 16 -rect 10 -2 14 2 -rect 24 -2 28 2 +rect -2 18 2 22 +rect 10 20 14 24 +rect 24 20 28 24 +rect 32 18 36 22 +rect 10 4 14 8 +rect 24 4 28 8 << pdcontact >> -rect -2 36 2 40 -rect 12 36 16 40 -rect 22 36 26 40 -rect 32 36 36 40 +rect -2 42 2 46 +rect 12 42 16 46 +rect 22 42 26 46 +rect 32 42 36 46 << psubstratepcontact >> -rect -2 22 2 26 -rect 32 22 36 26 +rect -2 28 2 32 +rect 32 28 36 32 << nsubstratencontact >> -rect 32 44 36 48 +rect 32 50 36 54 << polysilicon >> -rect 7 40 11 42 -rect 27 40 31 42 -rect 7 35 11 37 -rect 7 21 9 35 -rect 27 34 31 37 -rect 15 33 31 34 -rect 19 32 31 33 -rect 7 20 21 21 -rect 7 19 24 20 -rect 7 18 9 19 -rect 29 18 31 32 -rect 7 8 9 10 -rect 17 5 21 6 -rect 29 8 31 10 -rect -2 3 10 5 -rect 14 3 24 5 -rect 28 3 36 5 +rect 7 46 11 48 +rect 27 46 31 48 +rect 7 41 11 43 +rect 7 27 9 41 +rect 27 40 31 43 +rect 15 39 31 40 +rect 19 38 31 39 +rect 7 26 21 27 +rect 7 25 24 26 +rect 7 24 9 25 +rect 29 24 31 38 +rect 7 14 9 16 +rect 17 11 21 12 +rect 29 14 31 16 +rect -2 9 10 11 +rect 14 9 24 11 +rect 28 9 36 11 << polycontact >> -rect 15 29 19 33 -rect 21 20 25 24 -rect 17 6 21 10 +rect 15 35 19 39 +rect 21 26 25 30 +rect 17 12 21 16 << metal1 >> -rect -2 44 15 48 -rect 19 44 32 48 -rect -2 40 2 44 -rect 22 40 26 44 -rect 32 40 36 44 -rect 11 36 12 40 -rect 26 36 27 40 -rect -2 26 2 29 -rect -2 16 2 22 -rect 11 18 15 36 -rect 23 24 27 36 -rect 25 20 27 24 -rect 14 14 15 18 -rect 23 18 27 20 -rect 32 26 36 29 -rect 23 14 24 18 -rect 32 16 36 22 -rect -2 6 17 9 -rect 21 6 36 9 -rect -2 5 36 6 +rect -2 50 15 54 +rect 19 50 32 54 +rect -2 46 2 50 +rect 22 46 26 50 +rect 32 46 36 50 +rect 11 42 12 46 +rect 26 42 27 46 +rect -2 32 2 35 +rect -2 22 2 28 +rect 11 24 15 42 +rect 23 30 27 42 +rect 25 26 27 30 +rect 14 20 15 24 +rect 23 24 27 26 +rect 32 32 36 35 +rect 23 20 24 24 +rect 32 22 36 28 +rect -2 12 17 15 +rect 21 12 36 15 +rect -2 11 36 12 << m2contact >> -rect 15 44 19 48 -rect -2 29 2 33 -rect 32 29 36 33 -rect 6 -2 10 2 -rect 20 -2 24 2 +rect 15 50 19 54 +rect -2 35 2 39 +rect 32 35 36 39 +rect 6 4 10 8 +rect 20 4 24 8 << metal2 >> -rect -2 33 2 48 -rect -2 -2 2 29 -rect 6 2 10 48 -rect 24 -2 28 48 -rect 32 33 36 48 -rect 32 -2 36 29 +rect -2 39 2 54 +rect -2 0 2 35 +rect 6 8 10 54 +rect 6 0 10 4 +rect 24 0 28 54 +rect 32 39 36 54 +rect 32 0 36 35 << bb >> -rect 0 0 34 46 +rect 0 0 34 52 << labels >> -rlabel metal2 0 0 0 0 1 gnd -rlabel metal2 34 0 34 0 1 gnd -rlabel m2contact 17 46 17 46 5 vdd -rlabel metal2 8 43 8 43 1 bl -rlabel metal2 26 43 26 43 1 br -rlabel metal1 4 7 4 7 1 wl +rlabel metal2 0 6 0 6 1 gnd +rlabel metal2 34 6 34 6 1 gnd +rlabel m2contact 17 52 17 52 5 vdd +rlabel metal2 8 49 8 49 1 bl +rlabel metal2 26 49 26 49 1 br +rlabel metal1 4 13 4 13 1 wl << end >> diff --git a/technology/scn4m_subm/mag_lib/setup.tcl b/technology/scn4m_subm/mag_lib/setup.tcl index 01639fe2..95e7dbea 100644 --- a/technology/scn4m_subm/mag_lib/setup.tcl +++ b/technology/scn4m_subm/mag_lib/setup.tcl @@ -2,14 +2,13 @@ ignore class c equate class {-circuit1 nfet} {-circuit2 n} equate class {-circuit1 pfet} {-circuit2 p} -# This circuit has symmetries and needs to be flattened to resolve them -# or the banks won't pass +# We must flatten these because the ports are disconnected +flatten class {-circuit1 dummy_cell_6t} +flatten class {-circuit1 dummy_cell_1rw_1r} +flatten class {-circuit1 dummy_cell_1w_1r} flatten class {-circuit1 bitcell_array_0} -flatten class {-circuit1 bitcell_array_1} -#flatten class {-circuit1 precharge_array_0} -#flatten class {-circuit1 precharge_array_1} -#flatten class {-circuit1 precharge_array_2} -#flatten class {-circuit1 precharge_array_3} +flatten class {-circuit1 pbitcell_0} +flatten class {-circuit1 pbitcell_1} property {-circuit1 nfet} remove as ad ps pd property {-circuit1 pfet} remove as ad ps pd property {-circuit2 n} remove as ad ps pd diff --git a/technology/scn4m_subm/mag_lib/write_driver.mag b/technology/scn4m_subm/mag_lib/write_driver.mag index 9144f9d2..0aa48197 100644 --- a/technology/scn4m_subm/mag_lib/write_driver.mag +++ b/technology/scn4m_subm/mag_lib/write_driver.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1556015973 +timestamp 1565304081 << nwell >> rect -3 101 37 138 rect -3 0 37 51 @@ -10,7 +10,6 @@ rect -3 51 37 101 << ntransistor >> rect 9 178 11 190 rect 17 178 19 190 -rect 15 163 27 165 rect 9 144 11 148 rect 17 144 19 148 rect 10 82 12 89 @@ -31,10 +30,6 @@ rect 8 178 9 190 rect 11 178 12 190 rect 16 178 17 190 rect 19 178 20 190 -rect 15 165 27 166 -rect 15 162 27 163 -rect 12 158 15 161 -rect 12 156 16 158 rect 8 144 9 148 rect 11 144 12 148 rect 16 144 17 148 @@ -71,8 +66,6 @@ rect 3 35 7 38 rect 4 178 8 190 rect 12 178 16 190 rect 20 178 24 190 -rect 15 166 27 170 -rect 15 158 27 162 rect 4 144 8 148 rect 12 144 16 148 rect 20 144 24 148 @@ -95,7 +88,6 @@ rect 11 38 15 45 rect 19 38 23 45 rect 27 38 31 45 << psubstratepcontact >> -rect 12 152 16 156 rect 26 82 30 89 << nsubstratencontact >> rect 12 118 16 122 @@ -109,8 +101,6 @@ rect 9 176 11 178 rect 17 173 19 178 rect 6 171 19 173 rect 6 168 8 171 -rect 13 163 15 165 -rect 27 163 33 165 rect 9 148 11 150 rect 17 148 19 150 rect 9 132 11 144 @@ -133,12 +123,9 @@ rect 18 89 20 90 rect 10 81 12 82 rect 10 79 13 81 rect 2 71 3 75 -rect 11 71 13 79 +rect 11 67 13 79 rect 18 79 20 82 rect 18 77 23 79 -rect 31 71 33 163 -rect 11 69 33 71 -rect 11 67 13 69 rect 8 65 13 67 rect 8 64 10 65 rect 16 64 18 66 @@ -164,13 +151,9 @@ rect 15 10 19 14 rect 5 193 10 197 rect 5 190 8 193 rect 32 182 33 186 -rect 13 170 16 178 -rect 13 166 15 170 rect 4 148 8 164 -rect 12 158 15 162 -rect 12 156 16 158 -rect 23 157 27 158 -rect 12 148 16 152 +rect 12 163 16 178 +rect 12 148 16 159 rect 4 132 8 144 rect 20 142 24 144 rect 30 142 33 182 @@ -194,12 +177,12 @@ rect 27 45 31 60 rect 3 35 7 38 rect 19 35 23 38 rect 7 31 19 35 -rect 0 24 7 28 -rect 11 24 36 28 +rect 3 24 7 28 +rect 11 24 31 28 << m2contact >> rect 10 193 14 197 rect 20 190 24 194 -rect 23 153 27 157 +rect 12 159 16 163 rect 16 118 20 122 rect 26 89 30 90 rect 26 86 30 89 @@ -215,12 +198,12 @@ rect 15 0 19 6 rect 0 0 34 203 << labels >> rlabel metal2 15 1 15 1 1 din -rlabel metal1 2 25 2 25 3 en rlabel m2contact 21 66 21 66 1 gnd rlabel m2contact 28 88 28 88 1 gnd rlabel m2contact 21 33 21 33 1 vdd rlabel m2contact 18 120 18 120 1 vdd -rlabel m2contact 25 155 25 155 1 gnd rlabel metal2 12 201 12 201 5 bl rlabel metal2 22 201 22 201 5 br +rlabel m2contact 14 161 14 161 1 gnd +rlabel metal1 17 26 17 26 1 en << end >> diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp b/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp new file mode 100644 index 00000000..9766a840 --- /dev/null +++ b/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT dummy_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1_noconn gnd n w=1.2u l=0.4u +MM8 RA_to_R_right Q gnd gnd n w=1.2u l=0.4u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.2u l=0.4u +MM6 RA_to_R_left wl1 bl1_noconn gnd n w=1.2u l=0.4u +MM5 Q wl0 bl0_noconn gnd n w=0.8u l=0.4u +MM4 Q_bar wl0 br0_noconn gnd n w=0.8u l=0.4u +MM1 Q Q_bar gnd gnd n w=1.6u l=0.4u +MM0 Q_bar Q gnd gnd n w=1.6u l=0.4u +MM3 Q Q_bar vdd vdd p w=0.6u l=0.4u +MM2 Q_bar Q vdd vdd p w=0.6u l=0.4u +.ENDS + diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp b/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp new file mode 100644 index 00000000..f5424998 --- /dev/null +++ b/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT dummy_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1_noconn gnd n w=1.2u l=0.4u +MM8 RA_to_R_right Q gnd gnd n w=1.2u l=0.4u +MM7 RA_to_R_left Q_bar gnd gnd n w=1.2u l=0.4u +MM6 RA_to_R_left wl1 bl1_noconn gnd n w=1.2u l=0.4u +MM5 Q wl0 bl0_noconn gnd n w=0.8u l=0.4u +MM4 Q_bar wl0 br0_noconn gnd n w=0.8u l=0.4u +MM1 Q Q_bar gnd gnd n w=1.6u l=0.4u +MM0 Q_bar Q gnd gnd n w=1.6u l=0.4u +MM3 Q Q_bar vdd vdd p w=0.6u l=0.4u +MM2 Q_bar Q vdd vdd p w=0.6u l=0.4u +.ENDS + diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp b/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp new file mode 100644 index 00000000..3b0584df --- /dev/null +++ b/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp @@ -0,0 +1,17 @@ + +*********************** "dummy_cell_6t" ****************************** +.SUBCKT dummy_cell_6t bl br wl vdd gnd + +* Inverter 1 +M1000 Q Qbar vdd vdd p w=0.6u l=0.8u +M1002 Q Qbar gnd gnd n w=1.6u l=0.4u + +* Inverter 2 +M1001 vdd Q Qbar vdd p w=0.6u l=0.8u +M1003 gnd Q Qbar gnd n w=1.6u l=0.4u + +* Access transistors +M1004 Q wl bl_noconn gnd n w=0.8u l=0.4u +M1005 Qbar wl br_noconn gnd n w=0.8u l=0.4u + +.ENDS diff --git a/technology/scn4m_subm/sp_lib/write_driver.sp b/technology/scn4m_subm/sp_lib/write_driver.sp index d1dbf9b2..e86da288 100644 --- a/technology/scn4m_subm/sp_lib/write_driver.sp +++ b/technology/scn4m_subm/sp_lib/write_driver.sp @@ -28,9 +28,8 @@ M_14 din_gated_bar din_gated gnd gnd n W=0.8u L=0.4u ************************************************ * pull down with en enable -M_15 bl din_gated_bar net_5 gnd n W=2.4u L=0.4u -M_16 br din_bar_gated_bar net_5 gnd n W=2.4u L=0.4u -M_17 net_5 en gnd gnd n W=2.4u L=0.4u +M_15 bl din_gated_bar gnd gnd n W=2.4u L=0.4u +M_16 br din_bar_gated_bar gnd gnd n W=2.4u L=0.4u diff --git a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech index deaae865..7207f681 100644 --- a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech +++ b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech @@ -1764,6 +1764,11 @@ cifinput style lambda=0.20(p) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -2450,10 +2455,6 @@ style lambda=0.20(p) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -2470,6 +2471,11 @@ style lambda=0.20(p) style lambda=0.20(s) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -3158,10 +3164,6 @@ style lambda=0.20(s) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -3178,6 +3180,11 @@ style lambda=0.20(s) style lambda=0.20(ps) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -3810,10 +3817,6 @@ style lambda=0.20(ps) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -3830,6 +3833,11 @@ style lambda=0.20(ps) style lambda=0.20() scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -4516,10 +4524,6 @@ style lambda=0.20() and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -4536,6 +4540,11 @@ style lambda=0.20() style lambda=0.20(c) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -4989,10 +4998,6 @@ style lambda=0.20(c) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -5009,6 +5014,11 @@ style lambda=0.20(c) style lambda=0.20(cs) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -5464,10 +5474,6 @@ style lambda=0.20(cs) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -5484,6 +5490,11 @@ style lambda=0.20(cs) style lambda=0.20(cps) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -5940,10 +5951,6 @@ style lambda=0.20(cps) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * @@ -5960,6 +5967,11 @@ style lambda=0.20(cps) style lambda=0.20(cp) scalefactor 20 + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma BB 63 0 + layer nwell CWN and-not CWNR and-not CTA @@ -6414,10 +6426,6 @@ style lambda=0.20(cp) and-not CBA calma CAA 43 * - layer comment CX - labels CX - calma CX 63 * - calma CTA 60 * calma CRW 65 * diff --git a/technology/scn4m_subm/tech/__init__.py b/technology/scn4m_subm/tech/__init__.py index a516facc..662a09b6 100644 --- a/technology/scn4m_subm/tech/__init__.py +++ b/technology/scn4m_subm/tech/__init__.py @@ -1,9 +1,9 @@ # 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. +# 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 tech specific modules. diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 15278c7b..9d0e8aad 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -1,15 +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. +# 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 os from design_rules import * """ -File containing the process technology parameters for SCMOS 3me, subm, 180nm. +File containing the process technology parameters for SCMOS 4m, 0.35um """ #GDS file info @@ -86,8 +86,8 @@ drc["has_nwell"] = True drc["grid"]=0.5*_lambda_ #DRC/LVS test set_up -drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul" -drc["lvs_rules"]=drclvs_home+"/calibreLVS_scn3me_subm.rul" +drc["drc_rules"]=None #drclvs_home+"/calibreDRC_scn3me_subm.rul" +drc["lvs_rules"]=None #drclvs_home+"/calibreLVS_scn3me_subm.rul" drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/scn3me_subm/layers.map" # minwidth_tx with contact (no dog bone transistors) @@ -321,16 +321,12 @@ spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input no parameter['le_tau'] = 23 #In pico-seconds. parameter["min_inv_para_delay"] = .73 #In relative delay units parameter['cap_relative_per_ff'] = .91 #Units of Relative Capacitance/ Femto-Farad -parameter["static_delay_stages"] = 4 -parameter["static_fanout_per_stage"] = 3 -parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]] parameter["dff_clk_cin"] = 27.5 #In relative capacitance units parameter["6tcell_wl_cin"] = 2 #In relative capacitance units parameter["sa_en_pmos_size"] = 24*_lambda_ parameter["sa_en_nmos_size"] = 9*_lambda_ parameter["sa_inv_pmos_size"] = 18*_lambda_ parameter["sa_inv_nmos_size"] = 9*_lambda_ -parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array parameter['bitcell_drain_cap'] = 0.2 #In Femto-Farad, approximation of drain capacitance ###################################################