diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 66f61402..78b2a7dd 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -30,9 +30,26 @@ class pin_layout: return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1]) def __repr__(self): - """ override print function output """ - return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1]) + """ + override repr function output (don't include + name since pin shapes could have same shape but diff name e.g. blockage vs A) + """ + return "(layer={} ll={} ur={})".format(self.layer,self.rect[0],self.rect[1]) + def __hash__(self): + """ Implement the hash function for sets etc. """ + return hash(repr(self)) + + def __lt__(self, other): + """ Provide a function for ordering items by the ll point """ + (ll, ur) = self.rect + (oll, our) = other.rect + + if ll.x < oll.x and ll.y < oll.y: + return True + + return False + def __eq__(self, other): """ Check if these are the same pins for duplicate checks """ if isinstance(other, self.__class__): @@ -71,6 +88,10 @@ class pin_layout: """ Check if a shape overlaps with a rectangle """ (ll,ur) = self.rect (oll,our) = other.rect + + # Can only overlap on the same layer + if self.layer != other.layer: + return False # Start assuming no overlaps x_overlaps = False diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 8f38b7ec..18a51b61 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -87,15 +87,15 @@ class grid: self.target.append(n) - def add_source(self,track_list): + def add_source(self,track_list,value=True): debug.info(3,"Adding source list={0}".format(str(track_list))) for n in track_list: debug.info(4,"Adding source ={0}".format(str(n))) - self.set_source(n) + self.set_source(n,value) self.set_blocked(n,False) - def set_target(self,track_list,value=True): + def add_target(self,track_list,value=True): debug.info(3,"Adding target list={0}".format(str(track_list))) for n in track_list: debug.info(4,"Adding target ={0}".format(str(n))) diff --git a/compiler/router/grid_cell.py b/compiler/router/grid_cell.py index c0948382..3f145ef4 100644 --- a/compiler/router/grid_cell.py +++ b/compiler/router/grid_cell.py @@ -4,7 +4,6 @@ class grid_cell: visited, etc. """ def __init__(self): - self.visited = False self.path = False self.blocked = False self.source = False @@ -17,7 +16,6 @@ class grid_cell: Reset the dynamic info about routing. The pins/blockages are not reset so that they can be reused. """ - self.visited=False self.min_cost=-1 self.min_path=None self.blocked=False diff --git a/compiler/router/router.py b/compiler/router/router.py index 5b2b845f..1a955318 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -40,18 +40,18 @@ class router: self.pins = {} # A set of connected pin groups self.pin_groups = {} - # The corresponding sets of grids for each pin - self.pin_grids = {} - # The set of partially covered pins to avoid for each pin - self.pin_partials = {} + # The corresponding sets (components) of grids for each pin + self.pin_components = {} # A set of blocked grids self.blocked_grids = set() # A list of pin layout shapes that are blocked self.blockages=[] - # A list of paths that are blocked + # A list of paths that have been "routed" self.paths = [] + # The list of supply rails that may be routed + self.supply_rails = [] # The boundary will determine the limits to the size of the routing grid self.boundary = self.layout.measureBoundary(self.top_name) @@ -134,16 +134,16 @@ class router: Retrieve the pin shapes from the layout. """ shape_list=self.layout.getAllPinShapesByLabel(str(pin_name)) - pin_list = [] + pin_set = set() for shape in shape_list: (name,layer,boundary)=shape rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] pin = pin_layout(pin_name, rect, layer) debug.info(2,"Found pin {}".format(str(pin))) - pin_list.append(pin) + pin_set.add(pin) - debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin))) - self.pins[pin_name] = pin_list + debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name))) + self.pins[pin_name] = pin_set def find_pins(self,pin_name): """ @@ -175,8 +175,7 @@ class router: """ self.pins = {} self.pin_groups = {} - self.pin_grids = {} - self.pin_partials = {} + self.pin_components = {} # DO NOT clear the blockages as these don't change self.rg.reinit() @@ -409,7 +408,7 @@ class router: track in the track and leaves half a DRC space in each direction. """ # space depends on which layer it is - if track[2]==0: + if self.get_layer(track[2])==self.horiz_layer_name: space = 0.5*self.horiz_layer_spacing else: space = 0.5*self.vert_layer_spacing @@ -444,34 +443,40 @@ class router: """ Analyze the shapes of a pin and combine them into groups which are connected. """ - pin_list = self.pins[pin_name] - + pin_set = self.pins[pin_name] + local_debug=False # Put each pin in an equivalence class of it's own - equiv_classes = [[x] for x in pin_list] - #print("INITIAL\n",equiv_classes) + equiv_classes = [set([x]) for x in pin_set] + if local_debug: + print("INITIAL\n",equiv_classes) def compare_classes(class1, class2): """ Determine if two classes should be combined and if so return the combined set. Otherwise, return None. """ - #print("CL1:\n",class1) - #print("CL2:\n",class2) + if local_debug: + print("CLASS1:\n",class1) + print("CLASS2:\n",class2) # Compare each pin in each class, # and if any overlap, return the combined the class for p1 in class1: for p2 in class2: if p1.overlaps(p2): - combined_class = class1+class2 - #print("COM:",pformat(combined_class)) + combined_class = class1 | class2 + if local_debug: + print("COMBINE:",pformat(combined_class)) return combined_class - + + if local_debug: + print("NO COMBINE") return None def combine_classes(equiv_classes): """ Recursive function to combine classes. """ - #print("\nRECURSE:\n",pformat(equiv_classes)) + if local_debug: + print("\nRECURSE:\n",pformat(equiv_classes)) if len(equiv_classes)==1: return(equiv_classes) @@ -490,111 +495,128 @@ class router: return(equiv_classes) reduced_classes = combine_classes(equiv_classes) - #print("FINAL ",reduced_classes) - self.pin_groups[pin_name] = reduced_classes + if local_debug: + print("FINAL ",reduced_classes) + self.pin_groups[pin_name]=reduced_classes def convert_pins(self, pin_name): """ Convert the pin groups into pin tracks and blockage tracks """ try: - self.pin_grids[pin_name] + self.pin_components[pin_name] except: - self.pin_grids[pin_name] = [] - try: - self.pin_partials[pin_name] - except: - self.pin_partials[pin_name] = [] + self.pin_components[pin_name] = [] found_pin = False for pg in self.pin_groups[pin_name]: + print("PG ",pg) # Keep the same groups for each pin - self.pin_grids[pin_name].append(set()) - self.pin_partials[pin_name].append(set()) - pin_set = set() - partial_set = set() + blockage_set = set() for pin in pg: - debug.info(2,"Converting {0}".format(pin)) + debug.info(2," Converting {0}".format(pin)) (pin_in_tracks,partial_in_tracks)=self.convert_pin_to_tracks(pin) - # In the blockages, what did this shape expand as? blockage_in_tracks = self.convert_blockage(pin) - # At least one of the groups must have some valid tracks - if (len(pin_in_tracks)>0): - found_pin = True pin_set.update(pin_in_tracks) - partial_set.update(partial_in_tracks) - partial_set.update(blockage_in_tracks) + pin_set.update(partial_in_tracks) + + blockage_set.update(blockage_in_tracks) - debug.info(2," grids {}".format(pin_set)) - debug.info(2," parts {}".format(partial_set)) + debug.info(2," pins {}".format(pin_set)) + debug.info(2," blocks {}".format(blockage_set)) - # We can just block all of the partials, so combine the groups - self.pin_partials[pin_name][-1].add(frozenset(partial_set)) - # We need to route each of the classes, so don't combine the groups - self.pin_grids[pin_name][-1].add(frozenset(pin_set)) - - # This happens when a shape is covered partially by one shape and fully by another - self.pin_partials[pin_name][-1].difference_update(pin_set) + # At least one of the groups must have some valid tracks + if (len(pin_set) == 0): + self.write_debug_gds() + debug.error("Unable to find pin on grid.",-1) + + # We need to route each of the components, so don't combine the groups + self.pin_components[pin_name].append(pin_set) - # These will be blocked depending on what we are routing + # Add all of the blocked grids to the set for the design + self.blocked_grids.update(blockage_set) + + # Remove the pins from the blockages since we didn't know + # they were pins when processing blockages self.blocked_grids.difference_update(pin_set) - self.blocked_grids.difference_update(partial_set) - if not found_pin: - self.write_debug_gds() - debug.error("Unable to find pin on grid.",-1) - def add_pin(self, pin_name, is_source=False): + def add_source(self, pin_name): """ - This will mark the grids for all pin components as a source or a target. + This will mark the grids for all pin components as a source. Marking as source or target also clears blockage status. """ for i in range(self.num_pin_components(pin_name)): - self.add_pin_component(pin_name, i, is_source) + self.add_pin_component_source(pin_name, i) + def add_target(self, pin_name): + """ + This will mark the grids for all pin components as a target. + Marking as source or target also clears blockage status. + """ + for i in range(self.num_pin_components(pin_name)): + self.add_pin_component_target(pin_name, i) + def num_pin_components(self, pin_name): """ This returns how many disconnected pin components there are. """ - debug.check(len(self.pin_grids[pin_name]) == len(self.pin_partials[pin_name]), - "Pin grid and partial blockage component sizes don't match.") - return len(self.pin_grids[pin_name]) + return len(self.pin_components[pin_name]) - def add_pin_component(self, pin_name, index, is_source=False): + def add_pin_component_source(self, pin_name, index): """ - This will mark only the pin tracks from the indexed pin component as a source/target. + This will mark only the pin tracks from the indexed pin component as a source. It also unsets it as a blockage. """ debug.check(index1: + self.cell.add_route(self.layers,abs_path) + self.add_enclosure(abs_path[-1]) + + def add_enclosure(self, loc): + """ + Add a metal enclosure that is the size of the routing grid minus a spacing on each side. + """ + (ll,ur) = self.convert_track_to_pin(loc) + self.cell.add_rect_center(layer=self.get_layer(loc.z), + offset=vector(loc.x,loc.y), + width=ur.x-ll.x, + height=ur.y-ll.y) + + + def add_via(self,loc,size=1): """ Add a via centered at the current location @@ -761,8 +800,9 @@ class router: if prev_inertia!=next_inertia: newpath.append(path[i]) - # always add the last path - newpath.append(path[-1]) + # always add the last path unless it was a single point + if len(path)>1: + newpath.append(path[-1]) return newpath @@ -783,6 +823,7 @@ class router: if path: debug.info(1,"Found path: cost={0} ".format(cost)) debug.info(2,str(path)) + self.paths.append(path) self.add_route(path) else: self.write_debug_gds() diff --git a/compiler/router/signal_grid.py b/compiler/router/signal_grid.py index d5d38bcb..5c88d74d 100644 --- a/compiler/router/signal_grid.py +++ b/compiler/router/signal_grid.py @@ -64,15 +64,21 @@ class signal_grid(grid): # over-ridden if the route fails due to pruning a feasible solution. cost_bound = detour_scale*self.cost_to_target(self.source[0])*grid.PREFERRED_COST + # Check if something in the queue is already a source and a target! + for s in self.source: + if self.is_target(s): + return((grid_path([vector3d(s)]),0)) + # Make sure the queue is empty if we run another route while len(self.q)>0: heappop(self.q) - + # Put the source items into the queue self.init_queue() cheapest_path = None cheapest_cost = None - + + # Keep expanding and adding to the priority queue until we are done while len(self.q)>0: # should we keep the path in the queue as well or just the final node? diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index 7acc61a1..664f8305 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -67,16 +67,16 @@ class signal_router(router): # Now add the blockages self.set_blockages(self.blocked_grids,True) - self.set_blockages(self.pin_partial[src],True) - self.set_blockages(self.pin_partial[dest],True) + #self.set_blockages(self.pin_partials[src],True) + #self.set_blockages(self.pin_partials[dest],True) # Add blockages from previous paths self.set_path_blockages() # Now add the src/tgt if they are not blocked by other shapes - self.add_pin(src,True) - self.add_pin(dest,False) + self.add_source(src) + self.add_target(dest) if not self.run_router(detour_scale): return False diff --git a/compiler/router/supply_grid.py b/compiler/router/supply_grid.py index c584e5ae..bd9dab87 100644 --- a/compiler/router/supply_grid.py +++ b/compiler/router/supply_grid.py @@ -20,7 +20,8 @@ class supply_grid(signal_grid): def reinit(self): """ Reinitialize everything for a new route. """ - + self.source = [] + self.target = [] # Reset all the cells in the map for p in self.map.values(): p.reset() diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 28ecc044..37b9ff76 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -65,21 +65,29 @@ class supply_router(router): self.find_pins(self.gnd_name) # Add the supply rails in a mesh network and connect H/V with vias - self.prepare_blockages(block_names=[self.vdd_name],unblock_names=[self.gnd_name]) + # Block everything + self.prepare_blockages() + # Clear the rail we're routing + self.set_blockages(self.pin_components[self.gnd_name],False) + # Determine the rail locations self.route_supply_rails(self.gnd_name,0) - self.prepare_blockages(block_names=[self.gnd_name],unblock_names=[self.vdd_name]) + # Block everything + self.prepare_blockages() + # Clear the rail we're routing + self.set_blockages(self.pin_components[self.vdd_name],False) + # Determine the rail locations self.route_supply_rails(self.vdd_name,1) # Route the supply pins to the supply rails - #self.route_pins_to_rails(gnd_name) - #self.route_pins_to_rails(vdd_name) + self.route_pins_to_rails(gnd_name) + self.route_pins_to_rails(vdd_name) self.write_debug_gds() - return False + return True - def prepare_blockages(self, block_names=None, unblock_names=None): + def prepare_blockages(self): """ Reset and add all of the blockages in the design. Names is a list of pins to add as a blockage. @@ -87,55 +95,72 @@ class supply_router(router): # 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) + #print("BLOCKING:",self.blocked_grids) self.set_blockages(self.blocked_grids,True) - # This is conservative to prevent DRC violations on partially blocked tracks - if block_names: - for name in block_names: - # These are the partially blocked tracks around supply pins. - print("BLOCKING PARTIALS:",name,self.pin_partials[name]) - self.set_blockages(self.pin_partials[name],True) - # These are the actual supply pins - self.set_blockages(self.pin_grids[name],True) - print("BLOCKING GRIDS:",name,self.pin_grids[name]) - # This will unblock - if unblock_names: - for name in unblock_names: - # These are the partially blocked tracks around supply pins. - self.set_blockages(self.pin_partials[name],False) - print("UNBLOCKING PARTIALS:",name,self.pin_partials[name]) - # These are the actual supply pins - self.set_blockages(self.pin_grids[name],False) - print("UNBLOCKING GRIDS:",name,self.pin_grids[name]) - + + # Block all of the supply rails (some will be unblocked if they're a target) + self.set_supply_rail_blocked(True) + + # Block all of the pin components (some will be unblocked if they're a source/target) + for name in self.pin_components.keys(): + self.set_blockages(self.pin_components[name],True) + # These are the paths that have already been routed. self.set_path_blockages() def connect_supply_rails(self, name): """ - Add vias between overlapping supply rails. + Determine which supply rails overlap and can accomodate a via. + Remove any paths that do not have a via since they are disconnected. """ - paths = [x for x in self.paths if x.name == name] - + # Split into horizontal and vertical - vertical_paths = [x for x in paths if x[0][0].z==1] - horizontal_paths = [x for x in paths if x[0][0].z==0] - - shared_areas = [] - for v in vertical_paths: - for h in horizontal_paths: + vertical_paths = [(i,x) for i,x in enumerate(self.supply_rails) if x[0][0].z==1 and x.name==name] + horizontal_paths = [(i,x) for i,x in enumerate(self.supply_rails) if x[0][0].z==0 and x.name==name] + + # Flag to see if the paths have a via + via_flag = [False] * len(self.supply_rails) + # Ignore the other nets that we aren't considering + for i,p in enumerate(self.supply_rails): + if p.name != name: + via_flag[i]=True + + # Compute a list of "shared areas" that are bigger than a via + via_areas = [] + for vindex,v in vertical_paths: + for hindex,h in horizontal_paths: + # Compute the overlap of the two paths, None if no overlap overlap = v.overlap(h) if overlap: (ll,ur) = overlap - # Only add if the overlap is wide enough + # We can add a via only if it is a full track width in each dimension if ur.x-ll.x >= self.rail_track_width-1 and ur.y-ll.y >= self.rail_track_width-1: - shared_areas.append(overlap) + via_flag[vindex]=True + via_flag[hindex]=True + via_areas.append(overlap) - for (ll,ur) in shared_areas: + # Go through and add the vias at the center of the intersection + for (ll,ur) in via_areas: center = (ll + ur).scale(0.5,0.5,0) self.add_via(center,self.rail_track_width) + + # Remove the paths that have not been connected by any via + remove_indices = [i for i,x in enumerate(via_flag) if not x] + for index in remove_indices: + debug.info(1,"Removing disconnected supply rail {}".format(self.supply_rails[index])) + del self.supply_rails[index] + def add_supply_rails(self, name): + """ + Add the shapes that represent the routed supply rails. + This is after the paths have been pruned and only include rails that are + connected with vias. + """ + for wave_path in self.supply_rails: + if wave_path.name == name: + self.add_wavepath(name, wave_path) + def route_supply_rails(self, name, supply_number): @@ -154,7 +179,7 @@ class supply_router(router): wave = [vector3d(0,offset+i,0) for i in range(self.rail_track_width)] # While we can keep expanding east in this horizontal track while wave and wave[0].x < max_xoffset: - wave = self.route_supply_rail(name, wave, direction.EAST) + wave = self.find_supply_rail(name, wave, direction.EAST) # Vertical supply rails @@ -164,16 +189,14 @@ class supply_router(router): wave = [vector3d(offset+i,0,1) for i in range(self.rail_track_width)] # While we can keep expanding north in this vertical track while wave and wave[0].y < max_yoffset: - wave = self.route_supply_rail(name, wave, direction.NORTH) + wave = self.find_supply_rail(name, wave, direction.NORTH) - # Remember index of path size which is how many rails we had at the start - self.num_rails = len(self.paths) - - # Add teh supply rail vias + # Add the supply rail vias (and prune disconnected rails) self.connect_supply_rails(name) + # Add the rails themselves + self.add_supply_rails(name) - - def route_supply_rail(self, name, seed_wave, direct): + def find_supply_rail(self, name, seed_wave, direct): """ This finds the first valid starting location and routes a supply rail in the given direction. @@ -191,12 +214,9 @@ class supply_router(router): if not wave_path: return None - # Filter any path that won't span 2 rails - # so that we can guarantee it is connected if len(wave_path)>=2*self.rail_track_width: - self.add_wavepath(name, wave_path) wave_path.name = name - self.paths.append(wave_path) + self.supply_rails.append(wave_path) # seed the next start wave location wave_end = wave_path[-1] @@ -206,26 +226,27 @@ class supply_router(router): - def route_pins_to_rails(self,pin_name): + def route_pins_to_rails(self, pin_name): """ This will route each of the pin components to the supply rails. After it is done, the cells are added to the pin blockage list. """ + + num_components = self.num_pin_components(pin_name) + debug.info(0,"Pin {0} has {1} components to route.".format(pin_name, num_components)) # For every component - for index in range(self.num_pin_components(pin_name)): + for index in range(num_components): + debug.info(0,"Routing component {0} {1}".format(pin_name, index)) self.rg.reinit() - self.prepare_blockages(block_names=None,unblock_names=[pin_name]) - - # Block all the pin components first - self.set_component_blockages(pin_name, True) - + self.prepare_blockages() + # Add the single component of the pin as the source # which unmarks it as a blockage too - self.add_pin_component(pin_name,index,is_source=True) + self.add_pin_component_source(pin_name,index) # Add all of the rails as targets # Don't add the other pins, but we could? @@ -234,7 +255,10 @@ class supply_router(router): # Actually run the A* router self.run_router(detour_scale=5) - + #if index==1: + # self.write_debug_gds() + # import sys + # sys.exit(1) diff --git a/compiler/router/tests/10_supply_grid_test.py b/compiler/router/tests/10_supply_grid_test.py index 2fa5cb7b..792e6956 100755 --- a/compiler/router/tests/10_supply_grid_test.py +++ b/compiler/router/tests/10_supply_grid_test.py @@ -42,7 +42,7 @@ class no_blockages_test(openram_test): self.connect_inst(cell.pin_map.keys()) r=router(module=cell) - layer_stack =("metal3","via2","metal2") + layer_stack =("metal3","via3","metal4") self.assertTrue(r.route(self,layer_stack)) r=routing("10_supply_grid_test_{0}".format(OPTS.tech_name)) diff --git a/compiler/router/tests/config_scn4m_subm.py b/compiler/router/tests/config_scn4m_subm.py index 40addd69..ca112a97 100755 --- a/compiler/router/tests/config_scn4m_subm.py +++ b/compiler/router/tests/config_scn4m_subm.py @@ -2,7 +2,7 @@ word_size = 1 num_words = 16 num_banks = 1 -tech_name = "scn3me_subm" +tech_name = "scn4m_subm" process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 0cb93582..55e803b4 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -43,9 +43,9 @@ def write_magic_script(cell_name, gds_name, extract=False): # (e.g. with routes) f.write("flatten {}_new\n".format(cell_name)) f.write("load {}_new\n".format(cell_name)) - #f.write("cellname rename {0}_new {0}\n".format(cell_name)) - #f.write("load {}\n".format(cell_name)) - f.write("writeall force {0}_new\n".format(cell_name)) + f.write("cellname rename {0}_new {0}\n".format(cell_name)) + f.write("load {}\n".format(cell_name)) + f.write("writeall force\n") f.write("drc check\n") f.write("drc catchup\n") f.write("drc count total\n") diff --git a/technology/scn4m_subm/tf/display.drf b/technology/scn4m_subm/tf/display.drf index aeeefe2c..39349998 100644 --- a/technology/scn4m_subm/tf/display.drf +++ b/technology/scn4m_subm/tf/display.drf @@ -546,7 +546,7 @@ drDefinePacket( ( display background stipple1 lineStyle0 black black outlineStipple) ( display y9 stipple0 solid silver silver solid ) ( display Metal3Net dots4 solid navy navy outlineStipple) - ( display Metal3Net dots4 solid tan tan outlineStipple) + ( display Metal4Net dots4 solid tan tan outlineStipple) ( display A1 stipple0 lineStyle0 winBack winBack solid ) ( display pin solid lineStyle0 red red solid ) ( display XPNet blank solid yellow yellow outline ) @@ -640,6 +640,7 @@ drDefinePacket( ( display Canplace blank solid cyan cyan outline ) ( display annotate7 stipple0 solid red red solid ) ( display Via2 solid solid navy navy solid ) + ( display Via3 solid solid tan tan solid ) ( display Metal2Pin stipple0 lineStyle0 magenta magenta solid ) ( display annotate4 stipple0 solid yellow yellow solid ) ( display device1 stipple1 lineStyle0 green green outlineStipple) diff --git a/technology/scn4m_subm/tf/glade_scn4me_subm.py b/technology/scn4m_subm/tf/glade_scn4m_subm.py similarity index 64% rename from technology/scn4m_subm/tf/glade_scn4me_subm.py rename to technology/scn4m_subm/tf/glade_scn4m_subm.py index d2f9aa7e..314727c3 100644 --- a/technology/scn4m_subm/tf/glade_scn4me_subm.py +++ b/technology/scn4m_subm/tf/glade_scn4m_subm.py @@ -1,5 +1,5 @@ import os -CWD = os.environ.get("OPENRAM_TECH") + "/scn3me_subm/tf" +CWD = os.environ.get("OPENRAM_TECH") + "/scn4m_subm/tf" ui().importCds("default", CWD+"/display.drf", CWD+"/mosis.tf", 1000, 1, CWD+"/layers.map") diff --git a/technology/scn4m_subm/tf/mosis.tf b/technology/scn4m_subm/tf/mosis.tf index e48d76a0..bae7f07a 100644 --- a/technology/scn4m_subm/tf/mosis.tf +++ b/technology/scn4m_subm/tf/mosis.tf @@ -147,6 +147,8 @@ layerDefinitions( ( Metal2 drawing ) ( Via2 drawing ) ( Metal3 drawing ) + ( Via3 drawing ) + ( Metal4 drawing ) ( annotate drawing ) ( annotate drawing1 ) ( annotate drawing2 ) @@ -161,6 +163,7 @@ layerDefinitions( ( Metal1 pin ) ( Metal2 pin ) ( Metal3 pin ) + ( Metal4 pin ) ( Glass drawing ) ( XP drawing ) ( prBoundary drawing ) @@ -203,6 +206,8 @@ layerDefinitions( ( Via net ) ( Metal3 net ) ( Via2 net ) + ( Metal4 net ) + ( Via3 net ) ( pin label ) ( text drawing ) ( pin drawing ) @@ -313,11 +318,14 @@ layerDefinitions( ( annotate drawing9 annotate9 t t nil t nil ) ( Via2 drawing Via2 t t t t t ) ( Metal3 drawing Metal3 t t t t t ) + ( Via3 drawing Via3 t t t t t ) + ( Metal4 drawing Metal4 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 ) + ( Metal4 pin Metal4Pin 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 ) @@ -356,6 +364,7 @@ layerDefinitions( ( device annotate deviceAnt t t t t nil ) ( Metal2 net Metal2Net t t t nil nil ) ( Metal3 net Metal3Net t t t nil nil ) + ( Metal4 net Metal4Net 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 )