Hi Matthias,
Christmas is coming soon...
So, one thing which will be helpful, its a reader of LEF/DEF.
In a 1st step, the LEF reader, like that we will can easely verify our LEFs
I think that this topic goes w/ the other one: GDS to LEF.
Regards,
Joaquim
Comments
Hi Joaquim,
I received that request already a couple of times.
However, I am lacking a good example currently. Do you have a link to a public source of LEF/DEF sample files?
Best regards,
Matthias
for the specifications of the format (they have also a LEF/DEF Toolkit but I don't know really if you can use it):
http://www.si2.org/openeda.si2.org/help/group_ld.php?group=6
for a free library (you have to register but its free):
http://www.nangate.com/index.php?option=com_content&task=view&id=137&Itemid=137
if you need some others LEF examples or if you have questions, you can send me directly a mail if you want.
Regards,
Joaquim
Thanks for the links. I'll have a look.
Best regards,
Matthias
Now I'm using simple ruby script (not universal but enough for my purposes).
1. I run 'klayout -r script.rb';
2. File -> Open LEF
Script below (only for LEF observing)
Thanks. Sergey.
-------------------------------------
<pre>
# Ruby file for KLayout for work with LEF.
# klayout -r LEF.rb
######################################
$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 = LEFRect.new("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 LEFRect
def initialize(layer, x1, y1, x2, y2)
@layer = layer
@rect = RBA::DBox.new(x1, y1, x2, y2)
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
@intbox = RBA::Box.from_dbox(@rect)
$layout.cell($cell).shapes(@layer_id).insert_box(@intbox)
end
def layer
return @layer
end
def rect
return @rect
end
end
######################################
class LEFPin < LEFRect
def initialize(name, box)
@name = name
@box = box
@layer = @box.layer
@rect = @box.rect
end
def label
@orig = RBA::DTrans.new(@rect.center.x, @rect.center.y)
@text = RBA::Text.new(@name, RBA::Trans.from_dtrans(@orig))
# if @name =~ /vdd/
# print "vdd ", (@rect.center.x/1000).to_s, " ", (@rect.center.y/1000).to_s, "\n"
# end
# if @name =~ /vss/
# print "vss ", (@rect.center.x/1000).to_s, " ", (@rect.center.y/1000).to_s, "\n"
# end
@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
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)
ln = RBA::LayerPropertiesNode::new
ln.name = name
ln.dither_pattern = stipple
ln.fill_color = frame
ln.frame_color = fill
ln.width = 1
ln.source_layer_index = $lid[name]
$cv.insert_layer($cv.end_layers, ln)
return $lid[name]
end
#####################################
def parseLEF(lef)
cellList = Array.new
cell = 0
layer = ""
rect = 0
pin_name = ""
flag = 0
macro = 0
coeff = 1000
x1 = 0
y1 = 0
x2 = 0
y2 = 0
x_origin = 0
y_origin = 0
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(LEFRect.new("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*;/
rect = LEFRect.new(layer, ($1.to_f * coeff), ($2.to_f * coeff), ($3.to_f * coeff), ($4.to_f * coeff))
flag = flag | 4
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
else
flag = flag & 3
end
# print flag.to_s, " - ", line
case flag
when 5
pin = LEFPin.new(pin_name, rect)
macro.pins.push(pin)
# print pin_name, "\n"
when 6
macro.obs.push(rect)
end
}
return cellList
end
######################################
def openLEF
$clv = $mw.create_layout(0)
$cv = $mw.current_view
$layout = $cv.cellview(0).layout
$lid = Hash.new
get_layers()
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
}
$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)
$app.exec
</pre>
How to format code?
I have a problem with "Markdown" radio button.
Thanks. Sergey.
Hi Sergey,
Thanks for providing the script. Great job!
Since I think it's useful for many users, I have (hopefully) restored the formatting and put it on the server. It can be downloaded here: LEF.rb.
BTW: "Markdown" is one of those Wiki-style plain text markup languages. It's documented here. Code formatting can be achieved by indenting with 4 spaces.
Best regards,
Matthias
the script works very well.
I would like to define a different color for each lef-layer when I read the .lef.
How can I do?
thanks,
Salvatore
Some of my pins aren't define as RECT but :
PIN A
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER M1 ;
POLYGON 0.140 0.980 0.255 0.980 0.255 1.710 0.140 1.710 ;
END
END A
In the Lef.rb script the POLYGON case doesn't exist.
How to draw a polygon?
Thanks,
Salvatore
Hi Salvatore,
You can specify a layer properties file to use with the LEF import script by defining an environment variable named "lvlyp". The values of this variable should be the absolute path of a layer properties file. This file will be loaded when the LEF file has been imported.
Regarding the POLYGON problem I changed the LEF.rb script so it supports these shape types as well. I hope I didn't spoil it.
Best regards,
Matthias
thank you, now it works for the POLYGON too but only if the POLYGON definition is on the same line
of the .LEF.
For example :
PIN vdd
DIRECTION INOUT ;
USE POWER ;
SHAPE ABUTMENT ;
PORT
LAYER M1 ;
POLYGON 0.000 2.240 0.610 2.240 0.610 1.640 0.730 1.640
0.730 2.240 1.945 2.240 1.945 1.610 2.085 1.610 2.085 2.240
3.325 2.240 3.325 1.600 3.455 1.600 3.455 2.240 3.800 2.240
3.800 2.800 0.000 2.800 ;
END
END vdd
In this case the POLYGON end (;) is on a different line and so it doesn't work.
Best regards,
Salvatore.
Hi Salvatore,
I tried to fix the script accordingly. Hopefully it's working now. The download link is the same than before (LEF.rb).
Best regards,
Matthias
great! It's working. But there is a last issue :
- the pin name label position is in the center of the polygon boundary box so sometime it isn't over the pin polygon.
Thank you for your support.
Salvatore
Hi Salvatore,
I tried to fix that issue by using the leftmost bottom point and putting a text close to this point (displaced by 5 DBU's). I hope that is a useful heuristics to provide a point "inside" the polygon.
I replaced the file already. The download link remains the same.
Best regards,
Matthias
Great script ! I have slightly modified the LEF.rb script to map the LEF layers to GDS metal layers.
I now want to load the default "layer properties" as specified in the setup. What is the ruby code to load the default layer map file ?
Nick
Hi Nick,
I have not tested it myself yet, but this code should work:
A more elaborate version should do some more error checking and try to resolve relative paths.
Best regards,
Matthias
It works perfectly ! Many many thanks. If you want the new code feel free to contact me.
Nick