mirror of https://github.com/KLayout/klayout.git
New integration, WIP
This commit is contained in:
parent
fdb7d90550
commit
d0d3d2a8be
|
|
@ -0,0 +1,249 @@
|
|||
# $autorun-early
|
||||
# $priority: 1
|
||||
|
||||
require 'pathname'
|
||||
|
||||
module D25
|
||||
|
||||
class D25ZInfo
|
||||
|
||||
attr_accessor :layer, :zstart, :zstop, :display
|
||||
|
||||
def initialize(_layer, _zstart, _zstop, _display)
|
||||
self.layer = _layer
|
||||
self.zstart = _zstart
|
||||
self.zstop = _zstop
|
||||
self.display = _display
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class D25Display
|
||||
|
||||
attr_accessor :fill, :frame, :like
|
||||
|
||||
def initialize
|
||||
self.fill = nil
|
||||
self.frame = nil
|
||||
self.like = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# The D25 engine
|
||||
|
||||
class D25Engine < DRC::DRCEngine
|
||||
|
||||
def initialize
|
||||
|
||||
super
|
||||
|
||||
@current_z = 0.0
|
||||
@zstack = []
|
||||
|
||||
# clip to layout view
|
||||
if RBA::LayoutView::current
|
||||
self.clip(RBA::LayoutView::current.box)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def z(*args)
|
||||
|
||||
self._context("z") do
|
||||
|
||||
layer = nil
|
||||
zstart = nil
|
||||
zstop = nil
|
||||
height = nil
|
||||
|
||||
args.each do |a|
|
||||
|
||||
if a.is_a?(Range)
|
||||
|
||||
zstart = a.min
|
||||
zstop = a.max
|
||||
|
||||
elsif a.is_a?(DRC::DRCLayer)
|
||||
|
||||
if layer
|
||||
raise("Duplicate layer argument")
|
||||
end
|
||||
layer = a
|
||||
|
||||
elsif a.is_a?(1.class) || a.is_a?(1.0.class)
|
||||
|
||||
if height
|
||||
raise("Duplicate height specification")
|
||||
end
|
||||
height = a
|
||||
|
||||
elsif a.is_a?(Hash)
|
||||
|
||||
if a[:height]
|
||||
if height
|
||||
raise("Duplicate height specification")
|
||||
end
|
||||
height = a[:height]
|
||||
end
|
||||
if a[:zstart]
|
||||
if zstart
|
||||
raise("Duplicate zstart specification")
|
||||
end
|
||||
zstart = a[:zstart]
|
||||
end
|
||||
if a[:zstop]
|
||||
if zstop
|
||||
raise("Duplicate zstop specification")
|
||||
end
|
||||
zstop = a[:zstop]
|
||||
end
|
||||
invalid_keys = a.keys.select { |k| ![ :height, :zstart, :zstop ].member?(k) }
|
||||
if invalid_keys.size > 0
|
||||
raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}")
|
||||
end
|
||||
|
||||
else
|
||||
raise("Argument not understood: #{a.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ! zstart
|
||||
zstart = @current_z
|
||||
end
|
||||
if ! zstop && ! height
|
||||
raise("Either height or zstop must be specified")
|
||||
elsif zstop && height
|
||||
raise("Either height or zstop must be specified, not both")
|
||||
end
|
||||
if height
|
||||
zstop = zstart + height
|
||||
end
|
||||
@current_z = zstop
|
||||
|
||||
if ! layer
|
||||
raise("No layer specified")
|
||||
end
|
||||
|
||||
info = D25ZInfo::new(layer.data, zstart, zstop, @display || D25Display::new)
|
||||
@zstack << info
|
||||
|
||||
return info
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def display(*args, &block)
|
||||
|
||||
display = D25Display::new
|
||||
|
||||
args.each do |a|
|
||||
|
||||
if a.is_a?(D25ZInfo)
|
||||
|
||||
@zstack.each do |z|
|
||||
if z == a
|
||||
z.display = display
|
||||
end
|
||||
end
|
||||
|
||||
elsif a.is_a?(Hash)
|
||||
|
||||
hollow_fill = 0xffffffff
|
||||
|
||||
if a[:color]
|
||||
if !a[:color].is_a?(0xffffff.class)
|
||||
raise("'color' must be a color value (an integer)")
|
||||
end
|
||||
display.fill = a[:color]
|
||||
display.frame = a[:color]
|
||||
end
|
||||
if a[:frame]
|
||||
if !a[:frame].is_a?(0xffffff.class)
|
||||
raise("'frame' must be a color value (an integer)")
|
||||
end
|
||||
display.frame = a[:frame]
|
||||
end
|
||||
if a[:fill]
|
||||
if !a[:fill].is_a?(0xffffff.class)
|
||||
raise("'fill' must be a color value (an integer)")
|
||||
end
|
||||
display.fill = a[:fill]
|
||||
end
|
||||
if a[:hollow]
|
||||
if a[:hollow]
|
||||
display.fill = hollow_fill
|
||||
end
|
||||
end
|
||||
|
||||
if a[:like]
|
||||
li = nil
|
||||
if a[:like].is_a?(String)
|
||||
li = RBA::LayerInfo::from_string(a[:like])
|
||||
elsif a[:like].is_a?(RBA::LayerInfo)
|
||||
li = a[:like]
|
||||
else
|
||||
raise("'like' must be a string or LayerInfo object")
|
||||
end
|
||||
display.like = li
|
||||
end
|
||||
|
||||
invalid_keys = a.keys.select { |k| ![ :fill, :frame, :color, :hollow, :like ].member?(k) }
|
||||
if invalid_keys.size > 0
|
||||
raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}")
|
||||
end
|
||||
|
||||
else
|
||||
raise("Argument not understood: #{a.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def _finish(final = true)
|
||||
|
||||
if final && @zstack.empty?
|
||||
raise("No z calls made in 2.5d script")
|
||||
end
|
||||
|
||||
super(final)
|
||||
|
||||
if final
|
||||
|
||||
view = RBA::LayoutView::current.open_d25_view
|
||||
|
||||
begin
|
||||
|
||||
displays = {}
|
||||
|
||||
@zstack.each do |z|
|
||||
(displays[z.display.object_id] ||= []) << z
|
||||
end
|
||||
|
||||
displays.each do |k,zz|
|
||||
display = zz[0].display
|
||||
view.open_display(display.frame, display.fill, display.like)
|
||||
zz.each do |z|
|
||||
view.entry(z.layer, z.start, z.zstop)
|
||||
end
|
||||
view.close_display
|
||||
end
|
||||
|
||||
view.finish
|
||||
|
||||
rescue => ex
|
||||
view.close
|
||||
raise ex
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
module D25
|
||||
|
||||
# Installs the home menu entries (needs to be done on autorun, not autorun-early)
|
||||
|
||||
if RBA::Application::instance && RBA::Application::instance.main_window
|
||||
|
||||
cat = "d25"
|
||||
name = "2.5d"
|
||||
|
||||
mw = RBA::Application::instance.main_window
|
||||
mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View")
|
||||
|
||||
@new_action = RBA::Action::new
|
||||
@new_action.title = "New #{name} Script"
|
||||
@new_action.on_triggered do
|
||||
mw.show_macro_editor(cat, true)
|
||||
end
|
||||
|
||||
mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", @new_action)
|
||||
|
||||
@edit_action = RBA::Action::new
|
||||
@edit_action.title = "Edit #{name} Script"
|
||||
@edit_action.on_triggered do
|
||||
mw.show_macro_editor(cat, false)
|
||||
end
|
||||
|
||||
mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", @edit_action)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>true</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
module D25
|
||||
|
||||
class D25Executable < RBA::Executable
|
||||
|
||||
def initialize(macro, generator, rdb_index = nil)
|
||||
|
||||
@d25 = D25Engine::new
|
||||
@d25._rdb_index = rdb_index
|
||||
@d25._generator = generator
|
||||
|
||||
@macro = macro
|
||||
|
||||
end
|
||||
|
||||
def execute
|
||||
|
||||
@d25._start("D25: " + @macro.path)
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the D25's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
|
||||
|
||||
begin
|
||||
|
||||
# No verbosity set in d25 engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||
@d25.instance_eval(@macro.text, @macro.path)
|
||||
|
||||
rescue => ex
|
||||
|
||||
@d25.error("In #{@macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
@d25._finish
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A DSL implementation for a D25 language (XML format)
|
||||
class D25Interpreter < RBA::MacroInterpreter
|
||||
|
||||
# Constructor
|
||||
def initialize(recipe)
|
||||
|
||||
@recipe = recipe
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
self.syntax_scheme = "ruby"
|
||||
self.suffix = "lyd25"
|
||||
self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger
|
||||
self.storage_scheme = RBA::MacroInterpreter::MacroFormat
|
||||
self.description = "D25"
|
||||
|
||||
# Registers the new interpreter
|
||||
register("d25-dsl-xml")
|
||||
|
||||
# create a template for the macro editor:
|
||||
create_template(":/d25-templates/d25.lym")
|
||||
|
||||
# if available, create a menu branch
|
||||
if RBA::Application::instance && RBA::Application::instance.main_window
|
||||
mw = RBA::Application::instance.main_window
|
||||
mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
def executable(macro)
|
||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A DSL implementation for a D25 language (Plain text format)
|
||||
class D25PlainTextInterpreter < RBA::MacroInterpreter
|
||||
|
||||
# Constructor
|
||||
def initialize(recipe)
|
||||
|
||||
@recipe = recipe
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
self.syntax_scheme = "ruby"
|
||||
self.suffix = "d25"
|
||||
self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger
|
||||
self.storage_scheme = RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat
|
||||
self.description = "D25 (Text)"
|
||||
|
||||
# Registers the new interpreter
|
||||
register("d25-dsl")
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
def executable(macro)
|
||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A recipe implementation allowing the D25 run to be redone
|
||||
class D25Recipe < RBA::Recipe
|
||||
|
||||
def initialize
|
||||
super("d25", "D25 recipe")
|
||||
end
|
||||
|
||||
def executable(params)
|
||||
|
||||
script = params["script"]
|
||||
if ! script
|
||||
return
|
||||
end
|
||||
|
||||
macro = RBA::Macro::macro_by_path(script)
|
||||
macro || raise("Can't find D25 script #{script} - unable to re-run")
|
||||
|
||||
D25Executable::new(macro, self.generator("script" => script), params["rdb_index"])
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Register the recipe
|
||||
d25_recipe = D25Recipe::new
|
||||
|
||||
# Register the new interpreters
|
||||
D25Interpreter::new(d25_recipe)
|
||||
D25PlainTextInterpreter::new(d25_recipe)
|
||||
|
||||
# Creates a new macro category
|
||||
if RBA::Application::instance
|
||||
RBA::Application::instance.add_macro_category("d25", "2.5d view", [ "d25" ])
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<RCC>
|
||||
<qresource prefix="/built-in-macros">
|
||||
<file alias="_d25_engine.rb">built-in-macros/_d25_engine.rb</file>
|
||||
<file alias="d25_interpreters.lym">built-in-macros/d25_interpreters.lym</file>
|
||||
<file alias="d25_install.lym">built-in-macros/d25_install.lym</file>
|
||||
</qresource>
|
||||
<qresource prefix="/d25-templates">
|
||||
<file alias="d25.lym">templates/d25.lym</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -26,6 +26,9 @@ SOURCES = \
|
|||
FORMS = \
|
||||
D25View.ui \
|
||||
|
||||
RESOURCES = \
|
||||
layD25Resources.qrc \
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 5) {
|
||||
QT += openglwidgets
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>General;;2.5d view generator script (*.lyd25)\nA script generating a 2.5d view</description>
|
||||
<version/>
|
||||
<category>d25</category>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>true</show-in-menu>
|
||||
<group-name>d25_scripts</group-name>
|
||||
<menu-path>tools_menu.d25.end</menu-path>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
# Read about 2.5d generator scripts in the User Manual in "Various Topics/The 2.5d View"
|
||||
|
||||
# The script utilizes the DRC language with these two extensions
|
||||
#
|
||||
# z(layer, options ...):
|
||||
#
|
||||
# This function generates a extruded view from the given layer.
|
||||
# The "options" describe the z extension. Valid forms are:
|
||||
#
|
||||
# z(layer, 0.1 .. 0.2) extrude layer to z = 0.1 to 0.2 um
|
||||
# z(layer, zstart: 0.1, zstop: 0.2) same as above
|
||||
# z(layer, zstart: 0.1, height: 0.1) same as above, but with height instead of zstop
|
||||
# z(layer, height: 200.nm) extrude layer from last z position with a height of 200nm
|
||||
#
|
||||
# If layer is an original layer, the display options (colors, hollow) are taken
|
||||
# from the original layer's display style. Otherwise KLayout decides about the
|
||||
# initial display options. Use "display(...)" to control the display options.
|
||||
#
|
||||
# display(options) { block }
|
||||
# display(z(...), z(...), ..., options):
|
||||
#
|
||||
# Specify the display options to use for the layers generated inside the block
|
||||
# (which must contains at least one "z" call) or the given z calls:
|
||||
#
|
||||
# Options are:
|
||||
#
|
||||
# display(..., color: 0xff0000) use bright red for the material color (RGB)
|
||||
# display(..., frame: 0xff0000) use bright red for the frame color (combine with "color" for the fill)
|
||||
# display(..., hollow: true) use hollow style (only frame is drawn)
|
||||
# display(..., like: "7/0") borrow style from layout view's style for layer "7/0"
|
||||
#
|
||||
|
||||
z(input(1, 0), 0.1 .. 0.2)
|
||||
|
||||
display(like: 7/0) do
|
||||
z(input(7, 0), height: 100.nm)
|
||||
z(input(8, 0), height: 150.nm)
|
||||
end
|
||||
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
Loading…
Reference in New Issue