def add_cif_polygons(uv_layer, cif_layer): print '%s: adding %d boxes' % (uv_layer.name, len(cif_layer.boxes)) for box in cif_layer.boxes: ''' CIF uses lower left coordinate system Convert to internal representation, upper left UL Vertical B 22 94 787 2735 Horizontal B 116 22 740 2793 ''' #print '.', if False: print 'start' print box.xpos print box.ypos print box.width print box.height # FIXME: change this into one operation since this now takes non-negligible amount of time #uvp = UVPolygon.from_rect(box.xpos, box.ypos, box.width, box.height) uvp = UVPolygon.from_rect_ex(box.xpos, box.ypos, box.width, box.height, flip_height = uv_layer.height) if False: print uvp uvp.show() #uvp.flip_horizontal(uv_layer.height) #print uvp #uvp.show() uv_layer.add_uvpolygon(uvp)
def from_cif_init(self, file_name = "in.cif"): self.vias = Layer() self.metal = Layer() self.polysilicon = Layer() self.diffusion = Layer() self.labels = Layer() self.metal_gnd = None self.metal_vcc = None self.default_layer_names() parsed = CIFParser.parse(file_name) print 'CIF width: %d' % parsed.width print 'CIF height: %d' % parsed.height self.rebuild_layer_lists(False) # Make sizes the furthest point found for layer in self.layers + [self.labels]: #print 'Setting %s to %s' % (layer.name, parsed.width) layer.width = parsed.width layer.height = parsed.height def add_cif_polygons(uv_layer, cif_layer): print '%s: adding %d boxes' % (uv_layer.name, len(cif_layer.boxes)) for box in cif_layer.boxes: ''' CIF uses lower left coordinate system Convert to internal representation, upper left UL Vertical B 22 94 787 2735 Horizontal B 116 22 740 2793 ''' #print '.', if False: print 'start' print box.xpos print box.ypos print box.width print box.height # FIXME: change this into one operation since this now takes non-negligible amount of time #uvp = UVPolygon.from_rect(box.xpos, box.ypos, box.width, box.height) uvp = UVPolygon.from_rect_ex(box.xpos, box.ypos, box.width, box.height, flip_height = uv_layer.height) if False: print uvp uvp.show() #uvp.flip_horizontal(uv_layer.height) #print uvp #uvp.show() uv_layer.add_uvpolygon(uvp) #sys.exit(1) # uv_layer.show() #sys.exit(1) print 'Width: %d, height: %d' % (parsed.width, parsed.height) print 'Parsed labels: %d' % len(parsed.labels) for label in parsed.labels: # Make it a smallish object # Really 1 pix should be fine...but I'm more afraid of corner cases breaking things # Get it working first and then debug corner cases if needed # Maybe length should be related to text length uvpoly = UVPolygon.from_rect_ex(label.x, label.y, 20, 20, flip_height = parsed.height) uvpoly.text = label.text print uvpoly #uvpoly.show() self.labels.add_uvpolygon(uvpoly) #self.labels.show() #sys.exit(1) for layer_id in parsed.layers: layer = parsed.layers[layer_id] bench = Benchmark() # NMOS metal if layer_id == CIFLayer.NM: add_cif_polygons(self.metal, layer) # NMOS poly elif layer_id == CIFLayer.NP: add_cif_polygons(self.polysilicon, layer) # NMOS diffusion elif layer_id == CIFLayer.ND: add_cif_polygons(self.diffusion, layer) # NMOS contact elif layer_id == CIFLayer.NC: add_cif_polygons(self.vias, layer) else: raise Exception('Unsupported layer type %s' % repr(layer_id)) print bench #self.compute_wh() self.init()
def parse_statement(self, statement, scalar=None): '''Must be comment free and stripped of extra spaces. Return True on end''' global box_limit global g_limit_polygon # Skip blanks if statement == '': return False if False: scalar = 1.0 self.scalar = 1.0 #print 'Parising %s' % statement parts = statement.split() key = parts[0].upper() print_orig = g_print_result if self.cur_subroutine: if key == "DF": if self.cur_subroutine is None: raise Exception('DF without DS') # Note that we correctly drop the old routine if unneeded self.subroutines[ self.cur_subroutine.number] = self.cur_subroutine # Not sure if this is true, but it seems logical anyway self.active_layer = None self.cur_subroutine = None return False else: self.cur_subroutine.add(statement) return False ret = False if key == "E": ret = True elif key == "L": layer_id = Layer.str2id(parts[1]) # Hmm can you switch layers? Probably if layer_id in self.layers: self.active_layer = self.layers[layer_id] else: self.active_layer = Layer() self.active_layer.id = layer_id self.layers[layer_id] = self.active_layer if BOX_MAX: box_limit = 0 elif key == "C": ''' Call a subroutine Syntax: C <number> ''' self.subroutines[int(parts[1])].call(self) print_orig = False elif key == "DS": ''' Define the start of a subroutine Syntax: DS <number> <scale numerator> <scale demon> ''' subroutine = Subroutine() subroutine.number = int(parts[1]) subroutine.scale_numerator = int(parts[2]) subroutine.scale_denominator = int(parts[3]) self.cur_subroutine = subroutine print_orig = False elif key == "B": print_orig = False if BOX_MAX: if box_limit == BOX_MAX: print 'Last accepted box: ' + repr(statement) if box_limit > BOX_MAX: return False box_limit += 1 ''' Syntax: B <length> <width> <xpos> <ypos> [rotation] ; ''' if self.active_layer is None: raise Exception('Must be in layer to use box') ''' B length width xpos ypos [rotation] ; a box the center of which is at (xpos, ypos) and is length across in x and width tall in y. However, I don't like dealing with that so I'm translating ''' width_orig = int(parts[1]) height_orig = int(parts[2]) xpos_orig = int(parts[3]) ypos_orig = int(parts[4]) width = width_orig * self.scalar height = height_orig * self.scalar xpos = xpos_orig * self.scalar ypos = ypos_orig * self.scalar # Lambda design rules FTW if not scalar is None: xpos *= scalar ypos *= scalar width *= scalar height *= scalar xpos_corner = xpos - width / 2.0 ypos_corner = ypos - height / 2.0 perform_action = True if g_limit_polygon: feature_poly = UVPolygon.from_rect_ex(xpos_corner, ypos_corner, width, height) if not g_limit_polygon.intersects(feature_poly): perform_action = False if perform_action: # Should truncate to int? Don't do it unless it becomes a problem rotation = None if len(parts) >= 6: rotation = int(parts[5]) if self.corner_coordinates: self.add_box(width, height, xpos_corner, ypos_corner, rotation) else: self.add_box(width, height, xpos, ypos, rotation) if g_print_result: rotation_str = '' if not rotation is None: rotation_str = ' %d' % rotation width_i = int(width) height_i = int(height) # Skip invalid geometries if not width_i == 0 and not height_i == 0: print 'B %d %d %d %d%s;' % ( width_i, height_i, int(xpos + width / 2.0), int(ypos + height / 2.0), rotation_str) elif key == "9": ''' Cell name Syntax: 9 <text> Ignore, unused for now ''' self.cell_name = statement[2:] elif key == "94": ''' Label Syntax: 94 <label token> <x> <y> [layer] ''' text = parts[1] x = int(int(parts[2]) * self.scalar) y = int(int(parts[3]) * self.scalar) # Lambda design rules FTW if not scalar is None: x *= scalar y *= scalar layer_id = None if len(parts) >= 5: layer_str = parts[4] layer_id = layer_id = Layer.str2id(layer_str) self.add_label(text, x, y, layer_id) if g_print_result: print_orig = False layer_str = '' if not layer_id is None: printed_layer_str = ' %s' % layer_str print '94 %s %d %d%s;' % (text, x, y, printed_layer_str) else: raise Exception("Couldn't parse statement %s" % statement) if print_orig: print statement + ';' return ret
from pr0ntools.jssim.layer import Layer from pr0ntools.jssim.options import Options from pr0ntools.jssim.transistor import * from pr0ntools.jssim.cif.parser import Parser as CIFParser from pr0ntools.jssim.cif.parser import Layer as CIFLayer import sys from pr0ntools.jssim.layer import UVPolygon, Net, Nets, PolygonRenderer, Point from pr0ntools.jssim.util import set_debug_width, set_debug_height if False: clip_x_min = 250 clip_x_max = 360 clip_y_min = 150 clip_y_max = 250 clip_poly = UVPolygon.from_rect_ex(clip_x_min, clip_y_min, clip_x_max - clip_x_min + 1, clip_y_max - clip_y_min + 1) clip_poly.color = 'white' else: clip_poly = False class Generator: def __init__(self): self.vias = None self.metal_gnd = None self.metal_vcc = None self.metal = None self.polysilicon = None self.diffusion = None self.labels = None @staticmethod
def parse_statement(self, statement, scalar = None): '''Must be comment free and stripped of extra spaces. Return True on end''' global box_limit global g_limit_polygon # Skip blanks if statement == '': return False if False: scalar = 1.0 self.scalar = 1.0 #print 'Parising %s' % statement parts = statement.split() key = parts[0].upper() print_orig = g_print_result if self.cur_subroutine: if key == "DF": if self.cur_subroutine is None: raise Exception('DF without DS') # Note that we correctly drop the old routine if unneeded self.subroutines[self.cur_subroutine.number] = self.cur_subroutine # Not sure if this is true, but it seems logical anyway self.active_layer = None self.cur_subroutine = None return False else: self.cur_subroutine.add(statement) return False ret = False if key == "E": ret = True elif key == "L": layer_id = Layer.str2id(parts[1]) # Hmm can you switch layers? Probably if layer_id in self.layers: self.active_layer = self.layers[layer_id] else: self.active_layer = Layer() self.active_layer.id = layer_id self.layers[layer_id] = self.active_layer if BOX_MAX: box_limit = 0 elif key == "C": ''' Call a subroutine Syntax: C <number> ''' self.subroutines[int(parts[1])].call(self) print_orig = False elif key == "DS": ''' Define the start of a subroutine Syntax: DS <number> <scale numerator> <scale demon> ''' subroutine = Subroutine() subroutine.number = int(parts[1]) subroutine.scale_numerator = int(parts[2]) subroutine.scale_denominator = int(parts[3]) self.cur_subroutine = subroutine print_orig = False elif key == "B": print_orig = False if BOX_MAX: if box_limit == BOX_MAX: print 'Last accepted box: ' + repr(statement) if box_limit > BOX_MAX: return False box_limit += 1 ''' Syntax: B <length> <width> <xpos> <ypos> [rotation] ; ''' if self.active_layer is None: raise Exception('Must be in layer to use box') ''' B length width xpos ypos [rotation] ; a box the center of which is at (xpos, ypos) and is length across in x and width tall in y. However, I don't like dealing with that so I'm translating ''' width_orig = int(parts[1]) height_orig = int(parts[2]) xpos_orig = int(parts[3]) ypos_orig = int(parts[4]) width = width_orig * self.scalar height = height_orig * self.scalar xpos = xpos_orig * self.scalar ypos = ypos_orig * self.scalar # Lambda design rules FTW if not scalar is None: xpos *= scalar ypos *= scalar width *= scalar height *= scalar xpos_corner = xpos - width / 2.0 ypos_corner = ypos - height / 2.0 perform_action = True if g_limit_polygon: feature_poly = UVPolygon.from_rect_ex(xpos_corner, ypos_corner, width, height) if not g_limit_polygon.intersects(feature_poly): perform_action = False if perform_action: # Should truncate to int? Don't do it unless it becomes a problem rotation = None if len(parts) >= 6: rotation = int(parts[5]) if self.corner_coordinates: self.add_box(width, height, xpos_corner, ypos_corner, rotation) else: self.add_box(width, height, xpos, ypos, rotation) if g_print_result: rotation_str = '' if not rotation is None: rotation_str = ' %d' % rotation width_i = int(width) height_i = int(height) # Skip invalid geometries if not width_i == 0 and not height_i == 0: print 'B %d %d %d %d%s;' % (width_i, height_i, int(xpos + width / 2.0), int(ypos + height / 2.0), rotation_str) elif key == "9": ''' Cell name Syntax: 9 <text> Ignore, unused for now ''' self.cell_name = statement[2:] elif key == "94": ''' Label Syntax: 94 <label token> <x> <y> [layer] ''' text = parts[1] x = int(int(parts[2]) * self.scalar) y = int(int(parts[3]) * self.scalar) # Lambda design rules FTW if not scalar is None: x *= scalar y *= scalar layer_id = None if len(parts) >= 5: layer_str = parts[4] layer_id = layer_id = Layer.str2id(layer_str) self.add_label(text, x, y, layer_id) if g_print_result: print_orig = False layer_str = '' if not layer_id is None: printed_layer_str = ' %s' % layer_str print '94 %s %d %d%s;' % (text, x, y, printed_layer_str) else: raise Exception("Couldn't parse statement %s" % statement) if print_orig: print statement + ';' return ret