It looks like you're new here. If you want to get involved, click one of these buttons!
To make building PCell variants from Ruby scripts easier, I found that a lot of the boilerplate code could be factored out to make the actual generator code more compact and easy to read. It also calls the coerce_parameters
callback to make sure the given parameters are always consistent.
Here is the code:
##
# Creates a variant of a PCell based on the given parameters.
#
# @param lib_cell_name [String] Name of the PCell, with its library, of which a variant is being made.
# @param params [{various}] Parameters for the PCell in a hash.
# @param layout [RBA::Layout] Layout to which the new PCell variant will be added.
def self.pcell_variant(lib_cell_name, params, layout)
libname, cellname = lib_cell_name.split(".")
# first try to get the pcell from the current layout (see http://klayout.de/forum/comments.php?DiscussionID=404&page=1#Item_7)
pcell_decl = layout.pcell_declaration(cellname)
if pcell_decl.nil? # ...and if it doesn't exist, get the library first.
lib = RBA::Library.library_by_name(libname)
lib || raise("Unknown PCell library '#{libname}'")
# find the pcell within the lib
pcell_decl = lib.layout.pcell_declaration(cellname)
pcell_decl || raise("Unknown PCell '#{cellname}'")
end
unused_params = params.dup
pv_indices = {}
# build a param array from the defaults
pv = pcell_decl.get_parameters.collect do |p|
pv_indices[p.name.to_sym] = pv_indices.size # also record the index for each name
p.default
end
# call coerce_parameters to make sure the parameters are consistent
pv = pcell_decl.coerce_parameters(layout, pv)
# now update, step-by-step, the pv with the given parameters and
# call coerce_parameters for each change to remain consistent
params.each do |k, v|
raise("PCell #{lib_cell_name}: Encountered unsupported parameter #{k}") if !pv_indices.include? k
pv[pv_indices[k]] = v
pv = pcell_decl.coerce_parameters(layout, pv)
end
# create a PCell variant cell
if lib.nil?
pcell_var = layout.add_pcell_variant(pcell_decl.id, pv)
else
pcell_var = layout.add_pcell_variant(lib, pcell_decl.id, pv)
end
end
Here is an example of how it can be used:
ly = RBA::Application.instance.main_window.create_layout(1).layout
top = ly.add_cell("top")
layer = RBA::LayerInfo.new(2, 0)
pcv = pcell_variant('Basic.TEXT', {text: "PCELL_VARIANT", layer: layer}, ly)
trans = RBA::Trans::new(2000, 1000)
ly.cell(top).insert(RBA::CellInstArray::new(pcv, trans))
For some reason it doesn't seem to work properly with the Basic.CIRCLE
PCell (I believe it is a problem of the example code rather than the pcell_variant
method itself), so any ideas for improvements are more than welcome!
Regards, Chris
Comments
Hi Chris,
thanks for providing this code.
As I mentioned in the [http://klayout.de/forum/comments.php?DiscussionID=630&page=1#Item_6](other entry), there will be a very similar method in 0.24.
I used the following sample code:
The last four lines just configure the view to shown all layers and select the top cell. Th "pcell_variant" method also works with Basic.CIRCLE. But the required radius parameter is "actual_radius". "radius" and "handle" provide alternative inputs for the dialog and the handle which can be moved to adjust the radius graphically. Basic.CIRCLE was not really designed for programmatic instantiation, so that is somewhat special with this cell.
Matthias
Hi Matthias,
Thanks for the hint regarding the
actual_radius
, that got theBasic.CIRCLE
working. Also good to know about theadd_missing_layers
method, I guess it is good practice to always call it at the end of a layout generating script?Regards, Chris
Hi Chris,
I'd recommend putting these lines at the end of the generation script. Specifically "add_missing_layers" is a good idea. That scheme saves some mouse clicks and doesn't scare away inexperienced users :-)
Matthias