# Ruby file for KLayout for work with LEF. # klayout -rm LEF.rbm ###################################### $app = RBA::Application.instance $mw = $app.main_window ###################################### class MenuHandler < RBA::Action def initialize( t, k, &action ) self.title = t self.shortcut = k @action = action end def triggered @action.call( self ) end private @action end ###################################### class LEFCell def initialize(macro) @name = macro @bb = LEFShape.rect("prBoundary", 0, 0, 0, 0) @pins = Array.new @obs = Array.new @cell = $layout.add_cell(@name) end def render @bb.draw @pins.each { |pin| pin.draw pin.label } @obs.each { |blockage| blockage.draw } end def name return @name end def pins return @pins end def obs return @obs end def cell return @cell end def bb(rect) @bb = rect return @bb end end ###################################### class LEFShape def LEFShape.rect(layer, x1, y1, x2, y2) LEFShape.new.set_rect(layer, x1, y1, x2, y2) end def LEFShape.polygon(layer, p) LEFShape.new.set_polygon(layer, p) end def set_rect(layer, x1, y1, x2, y2) @layer = layer @rect = RBA::DBox.new(x1, y1, x2, y2) @polygon = nil return self end def set_polygon(layer, points) @layer = layer @rect = nil @polygon = RBA::DPolygon.new(points.collect { |xy| RBA::DPoint.new(xy[0], xy[1]) }) return self end def draw @layer_id = 0 @layer_tmp = @layer + ":bnd" if defined? self.name @layer_tmp = @layer + ":net" end @layer_id = $lid[@layer_tmp] if ! @layer_id @layer_id = create_layer(@layer_tmp, 0x000000, 0x0000ff, 1) end if @rect @intbox = RBA::Box.from_dbox(@rect) $layout.cell($cell).shapes(@layer_id).insert_box(@intbox) end if @polygon @intpolygon = RBA::Polygon.from_dpoly(@polygon) $layout.cell($cell).shapes(@layer_id).insert(@intpolygon) end end def layer return @layer end def rect return @rect end def polygon return @polygon end end ###################################### class LEFPin < LEFShape def initialize(name, shape) @name = name @layer = shape.layer @rect = shape.rect @polygon = shape.polygon end def label @orig = nil if @rect @orig = RBA::DTrans.new(@rect.center.x, @rect.center.y) end if @polygon @polygon.each_point_hull do |p| @orig = RBA::DTrans.new(p.x + 5, p.y + 5) break end end if @orig @text = RBA::Text.new(@name, RBA::Trans.from_dtrans(@orig)) @layer_id = $lid["text:net"] if ! @layer_id @layer_id = create_layer("text:net", 0xffffff, 0xffffff, 1) end $layout.cell($cell).shapes(@layer_id).insert_text(@text) end end def name return @name end end ###################################### def get_layers if ENV['lvlyp'] f = $cv.load_layer_props(ENV['lvlyp']) l = $cv.begin_layers while ! l.at_end? l.current.name =~ /^\s*(\S+)\s*/ $lid[$1] = l.current.source_layer_index(0) l.next end end end ###################################### def create_layer(name, frame, fill, stipple) $lid[name] = $layout.insert_layer(RBA::LayerInfo.new(name)) ln = RBA::LayerPropertiesNode::new ln.name = name ln.dither_pattern = stipple ln.fill_color = frame ln.frame_color = fill ln.width = 1 ln.source_name = name $cv.insert_layer($cv.end_layers, ln) return $lid[name] end ##################################### def stringToPoints(s, coeff) points = [] x = nil s.split(/\s+/).each do |c| if x points.push([ x, c.to_f * coeff ]) x = nil else x = c.to_f * coeff end end return points end ##################################### def parseLEF(lef) cellList = Array.new cell = 0 layer = "" shape = 0 pin_name = "" flag = 0 macro = 0 coeff = 1000 x1 = 0 y1 = 0 x2 = 0 y2 = 0 x_origin = 0 y_origin = 0 in_polygon = false poly_points = [] lef.each { |line| case line when /^\s*DATABASE\s+MICRONS\s+(\d+)/ coeff = $1.to_f flag = 0 when /^\s*MACRO\s+(\S+)/ macro = LEFCell.new($1) cellList.push(macro) flag = 0 when /^\s*FOREIGN\s+\S+\s+(\S+)\s+(\S+?)\s*;/ x1 = $1.to_f * coeff y1 = $2.to_f * coeff flag = 0 when /^\s*ORIGIN\s+(\S+)\s+(\S+?)\s*;/ x_origin = $1.to_f * coeff y_origin = $2.to_f * coeff flag = 0 when /^\s*SIZE\s+(\S+)\s+BY\s+(\S+?)\s*;/ if macro != 0 x2 = $1.to_f * coeff - x_origin y2 = $2.to_f * coeff - y_origin macro.bb(LEFShape.rect("prBoundary", x1, y1, x2, y2)) end flag = 0 when /^\s*LAYER\s+(\S+?)\s*;/ layer = $1 flag = flag & 3 when /^\s*RECT\s+(\S+)\s+(\S+)\s+(\S+)\s(\S+?)\s*;/ shape = LEFShape.rect(layer, ($1.to_f * coeff), ($2.to_f * coeff), ($3.to_f * coeff), ($4.to_f * coeff)) flag = flag | 4 when /^\s*POLYGON\s+(.*?)\s*;/ points = stringToPoints($1, coeff) shape = LEFShape.polygon(layer, points); flag = flag | 4 when /^\s*POLYGON\s*$/ in_polygon = true poly_points = [] when /^\s*POLYGON\s+(.*)\s*$/ in_polygon = true poly_points = stringToPoints($1, coeff) when /^\s*PIN\s+(\S+)/ pin_name = $1 flag = 1 when /^\s*END\s+(\S+)/ if $1 == pin_name then flag = 0 end when /^\s*OBS/ flag = 2 when /^\s*END\s*$/ if flag == 6 || flag == 2 flag = 2 elsif flag == 5 flag = 1 end when /^\s*([\d+\-\s\.]*)\s*;/ if in_polygon in_polygon = false stringToPoints($1, coeff).each { |p| poly_points.push(p) } shape = LEFShape.polygon(layer, poly_points); flag = flag | 4 end when /^\s*([\d+\-\s\.]*)\s*$/ if in_polygon stringToPoints($1, coeff).each { |p| poly_points.push(p) } end else flag = flag & 3 end # print flag.to_s, " - ", line case flag when 5 pin = LEFPin.new(pin_name, shape) macro.pins.push(pin) # print pin_name, "\n" when 6 macro.obs.push(shape) end } return cellList end ###################################### def openLEF $clv = $mw.create_layout(0) $cv = $mw.current_view $layout = $cv.cellview(0).layout $lid = Hash.new file = RBA::FileDialog.get_open_file_name("Open LEF", ".", "LEF File (*.lef *.plef)") if file.has_value? == false return end lef = IO.readlines(file.value) $cellList = parseLEF(lef) $cellList.each { |item| $cell = item.cell item.render } get_layers() $cv.select_cell_path( [$cell], 0 ) $cv.zoom_fit $cv.max_hier end ###################################### menu = $mw.menu $open_LEF = MenuHandler.new("Open LEF", "Ctrl+Shift+L") { openLEF } menu.insert_item("file_menu.#2", "rba_test", $open_LEF)