Hints and Tricks
This chapter provides a number of suggestions that can help when using the Graphical Cell Compiler to create PAMs. As with any new tool, as you become familiar with it you discover ways to do things that make life easier. The purpose of this chapter is to save you time by sharing a few of these tricks before you spend the time to discover them on your own.
Selection and Control Definition
Since most all the controls require shapes to be selected as part of their definition and many also require a control line construction line) being able to select the proper shapes for a given control is important. There are times when this can be difficult. Take for example the case of defining a multi-layer stack of shapes that all start the same size but must be stretched in different ways depending on the layer and user-supplied parameter values. You could find yourself with the Stretch dialog open and unable to accurately select the shape or shapes from the stack that must go with that stretch.
Traditionally, one would use the Option/Layers dialog to turn off and on various layers to make it possible to select the required shapes. But this process is rather tedious and slow. In this case there is an easier way.
At this point it is important to remember just when various actions take place in the define, compile, execute sequence. For a given control, the phases perform the following functions:
- Define phase - shapes to be operated on are picked by selection and associated with a given control.
- Compile phase - shape data (the actual (x,y) points) are collected.
- Execution phase - shape data is tested (for example to see if it is intersected by a control line) and modified by the control.
Given the above we can see that the location of the shapes does not matter during the definition of the control.
This means that the stack of shapes can be spread around the screen so they don't lie on top of one another. This makes the selection of particular shapes easy to do. Once all the controls for that stack of shapes are define, the shapes can be moved or undo can be used to put them back in their original location.
This technique can be used to solve a number of different selection problems during the definition of controls. As long as everything is in it's proper location before the compile step, moving shapes around will have no negative effects.
Controlling Pin Numbers
In general, the component pins inserted by a PAM will be created in the same order that the ports were found in the source layout. The search moves through the layers from 1 to N, and for each layer picks up the ports in order which will be from the first ports inserted up through the last ports inserted or modified/edited. That is, for a given layer, if the first port inserted is edited, it will be re-created at the end of the list and will now be the last port found on that layer.
Most of the time this order doesn't matter since the port numbers are saved in the PAM. This means that as the pins are inserted, the default pin numbering (next lowest available integer) will be modified with the saved port number. The one time where this may matter involves cases where a port is part of a repeat control. See Preferred pin with the same number exists in Chapter 11, Error Messages.
As discussed, if an un-copied pin is created after a copied pin there can be a pin number conflict. The easiest way to resolve this conflict is to change the port order in the source layout so that all the fixed (un-copied) pins will be inserted and numbered before any of the copied pins.
In order to control the pin creation order in the final component, you must insert the ports in the source layout in their desired order. If for any reason a port is edited, it will then be out of order. The easiest way to correct the order is to use the Edit Component Parameters (ports are treated as components) and select each port and then Apply. Going through the ports in the desired order will position them in the database in that order so the resulting PAM will insert them in the desired order.
By controlling this order you can make sure that all the fixed pins are inserted and numbered (with port numbers) before the copied pins. The copied pins will then be given the next available default number skipping over any numbers already is use by an un-copied pin.
Testing for Minimum and/or Maximum Values
It is often the case that a given physical model is only valid for a certain range of parameter values. While these constraints are often checked by the simulation model it is sometimes desirable to have the physical model do some checking also. This may be desired if an out-of-range parameter value (a zero for example) can cause an error in the macro or cause the macro to generate invalid graphics.
While there is no direct support for parameter range checking in ADS, there is a technique that can be used to at least constrain parameters to within certain ranges. This makes use of the ?: syntax supported by AEL.
Let's say for example you have a Repeat control that is using the parameter count for the repeat count field. So the dialog field would simply contain:
count
And let's say that count should never be less than one. If the user enters zero or a negative number, use one. This could be forced with:
count < 1 ? 1 : count
Which is sort of equivalent to a small function that does:
if (count < 1) return(1) else return(count);
If you further wanted to constrain count to be less than ten, you would add a second nested test:
count < 1 ? 1 : ( count > 9 ? 9 : count )
Which would be somewhat like:
if (count < 1) return(1) else if (count > 9) return(9) else return(count);
Now this is clearly not a general-purpose solution. For example, if the parameter count is used three different times then the range testing will need to be in place for each occurrence. But in cases where some range testing is very important (to prevent divide by zero errors for example) this method will work well.
Advanced Value Testing and Error Reporting
The above example is for simple bounds checking. It does not allow for more complex testing of parameter values nor does it provide for any sort of error/warning reporting to the user. By using the User-Defined control it is possible to do more extensive testing of the component parameters as well as provide messages to the user.
We start with the basic coupled-line model used elsewhere in this manual. To the existing two Stretch and one Repeat controls is has, we will add a User-Defined control. It will be set to Replace List (and end with a return (NULL) statement so that it's a no-op) and be passed all four of the component parameters: length, width, number and space. The function called will be named: check_couple_values() . Then using the View/Edit dialog and Cut/Paste the new control is moved to be the first control executed by the PAM. This last step is very important because if it's left at the end of the list of controls, the NULL return will remove the copies made by the repeat control.
There are two ways to pass the component parameters to the test function check_couple_values() . The first it by-value which is the way parameters are typically passed. If passed by-value the function can use the parameter values, but it can not modify them back in the calling code. The other way (used here) is by-reference which means that a pointer to the value is passed to the function rather than the value itself. The function can still access the value, but if it modifies the value it will be changed back in the calling procedure also. By passing the parameters by-reference, the testing function can check AND correct the parameter values before the rest of the PAM executes.
To pass a parameter by-reference, you use the C language syntax of:
&name
To access the value of a parameter passed by-reference, you use the C language syntax of:
*name
So the final control list for the coupled line model will be (the User-Defined control being the only new control):
| Control: | User-Defined |
| Returns: List Replace | |
| Function: check_couple_values(&length, &width, &number, &space); | |
| Control: | Stretch |
| Direction: Both | |
| Length: length | |
| Offset: 100.0 mil | |
| Control: | Stretch |
| Direction: Both | |
| Length: width | |
| Offset: 50.0 mil | |
| Control: | Repeat |
| Direction: Parallel | |
| Parallel | |
| Number: number | |
| Distance: width+space |
And the function called by the User-Defined control might look something like:
defun check_couple_values(lengthP, widthP, numberP, spaceP)
{
if (*lengthP < 100 mil) {
de_error_dialog("length must be >= 100 mil, reset",
NULL, TRUE); *lengthP = 100 mil;
}
if (*lengthP > 500 mil) {
de_error_dialog("length must be <= 500 mil, reset",
NULL, TRUE); *lengthP = 500 mil;
}
// Same type of test for width, and space
if (*numberP > 5) {
de_error_dialog("number must be <= 5, reset", NULL, TRUE);
*numberP = 5;
}
if (*lengthP < *widthP) {
de_warning_dialog("Warning, length < width", NULL, TRUE);
}
return(NULL);
}
You'll notice that all the parameter names have a P appended to their name. This acts as a reminder in the code that these have been passed by-reference and must use the *name syntax to access the value. A test for a minimum and maximum value for the length parameter has been included. In each case, if the value is out-of-range, a message is displayed to the user and the value is reset to be in range. Notice the use of units (mil) in the expressions. Similar tests could be added for the width and space parameters. A test has been added for number to show what a unitless value would look like.
Finally, a test has been added that goes beyond simple range checking. In this case it's checking to make sure that the length of the line is always greater than it's width. If the test fails, a warning (not an error) message is printed and the values are not changed. While this may not be a realistic constraint, it serves to demonstrate the types of error checking that can be performed in a User-Defined control.
When using this method for range checking, be aware of the limitations. First, it only works on components built with the GCC. Second, the testing is only performed during Layout component creation, which means that no testing would be done on the Schematic equivalent for this component. Finally, great care must be taken when creating the tests to make sure they are testing the right value (by-value, by-reference) in the right way (with or without units) to get the desired results.
Printing Shape Data
Sometimes when trying to debug a macro there is just no substitute for printing out the intermediate values for shape data. While it is possible to edit the PAM and add print statements in the code, it must be done manually and if you update and re-compile the macro all the added print statements will be lost.
But there is a creative way to use the User-Defined control to print shape data without actually making any changes to the data.
As discussed in the chapter on the User-Defined control the local variable _shape_data contains the current (x,y) data for the shape being operated on. If the Function returns field is set to Shape, and the x,y points field is simply set to _shape_data it has the effect of assigning the current shape data to itself, that is, a null-operation. No change is made to the data.
This gives us a hook into the AEL code where we can attach an additional AEL statement to print out some values. We will use the identify_value() function as defined in the AEL Guide. By using this with the fputs() function we can cause the values to be printed out to the terminal window where all the ADS startup messages are printed.
If we want to print out the current (x,y) shape data, then set the User-Defined control as:
_shape_data; fputs(stderr, identify_value(_shape_data));
You could even give it a label by doing:
_shape_data; fputs(stderr, strcat("after stretch: ",
identify_value(_shape_data)));
If multiple shapes are selected for this control, then each will be operated on and therefore each will have it's current data printed.
And while you would continue to use _shape_data as the function value, you could print the contents of any of the local variables defined in the User-Defined control, for example: _cline_data or _shape_list.
In some cases you may want to print out a number of values, but you don't want to clutter the output with labels.
An example might be to print out some of the variables for each step of a polar control. Similar to the example above, you'd have an expression for the radius length, followed by a semicolon, followed by something like this:
fputs (stderr, fmt_tokens(list(_angle_i, _angle, _radius)))
This would result in one line being printed per step, each line containing the step number, the computed angle, and the computed radius. This would be repeated for each shape operated on by this control.
Define Parameter Order
As previously noted, component parameters are collected from the expression strings in the various controls as they are processed. You have little or no control over the final order as they will appear in the component insertion dialog. But what if it's really important for component usability or understanding for the parameters to be in a specific order?
As we saw in the previous hint (Printing Shape Data) it's possible to use a User-Defined Control that performs no function as a hook to do other work. So if we make a User-Defined control the first control in the list, and specify all the parameters in that control, it will be the first control processed and we will have essentially defined the parameter order. All we need is a way to use all the parameters in an expression in such a way that it doesn't change any values or have any other side-effects.
One was to do this is to use the AEL list() function to make a list of the parameters that we then never use for anything else. Looking at the Multi-Coupled Line example used elsewhere in this manual, we might define the first control as a User-Defined control with the following function:
_shape_data; list(length, width, number, space)
By returning _shape_data for whatever shape we happened to select for this control, it performs no modifications. The list() function contains all the parameters in the desired order to be found during the compile step. But since we don't assign the returned list to anything it is simply discarded. Of course any parameters not listed in this way will be found as they appear by the compiler and added to the list.
The results of this technique is effective control over the component parameter order.
Center of Rotation
All shapes rotate about the origin (0,0). If the shape is setting ON the origin it will sort of spin in place. If the shape is some distance away from the origin the rotation will move it about the origin (it's location AND orientation will change).
So let's say there are a number of shapes (Ports for example) which must all be rotated to some angle. If they are in their final locations when the rotation is applied they will rotate about the origin and be moved away from their desired location.
One trick to deal with this problem is to place all the shapes needing to be rotated on the origin in the source design. Then you can define Rotate/Move/Mirror controls to act on each shape. Since the actions are performed in the order they appear in the dialog, the rotation is done first (about the origin) followed by the move which can place them in their final location.
Of course if the shapes are also part of a stretch or repeat then having them all start at the origin may make it impossible to place them in the current location with respect to a control's construction line. For this case one might use a more traditional translate, rotate, restore method.
You start with the shape at some known location in the source layout. You then use a Rotate/Move/Mirror control to translate it to the origin. You can then use a second Rotate/Move/Mirror to rotate it and restore it back to it's original location. It is then properly rotated and in position for any subsequent controls to operate on.
The key point to remember is that in developing a complex PAM you are free to start the shapes in any location and/or move them in any that positions them to allow you to perform the operations you need. Don't be limited by methods that would place a shape in it's final location and not move it during the execution of the PAM.
Deletion of shapes. There may be times when the inclusion of a particular shape should be optional. In other words, under specific condition you may wish to delete a shape or shapes so that they do not appear in the final layout. It's possible to do this using the User-Defined control.
As discussed in Chapter 8, User-Defined Control, it is valid to have a User-Defined function return NULL. This has the effect of deleting that particular shape. This means you could define a conditional expression that would either delete the shape or have no effect on it, for example:
(delete == TRUE) ? NULL : _shape_data
This same method could be used to delete the list of generated shapes (from a Repeat) by setting the return type to Replace List and doing:
(delete == TRUE) ? NULL : _shape_list
Be aware that if you delete the list, then the macro will act as if it was never there and will generate a shape from the current shape data array. So you may need to clear them both, or, you may want to delete the current shape data before the repeat so that it doesn't make the copies in the first place.
Disable Controls
There are times when one is debugging a PAM that it would be real nice to be able to turn off a control. You don't want to actually delete it (it's to much trouble to add it in again), you just want to disable it so you can eliminate its effects.
While there is no built-in way to disable a control, there is a method you can use to modify a control's action to cause it to do nothing. Most controls have a key parameter that if set to zero will cause the control to have no effect on its shapes. For example setting the stretch distance to zero will result in no stretch taking place.
But you don't want to simply change the control values to zero because you will then have to re-enter the correct equation to turn them on again. What you can do is preface the expression with a conditional expression that will result in the same thing. For example, if the Stretch control has a Distance equation of:
length
Then inserting the following in front of the expression will have the effect of turning it off:
TRUE ? 0.0 : length
Which basically says: If TRUE then return(0.0). Since TRUE is always true, then it will always use the value 0.0 for the Stretch Distance. The control has been disabled until you remove the conditional again (or change the TRUE to FALSE to enable it and leave it easy to disable in the future).
Here are some examples of how to disable some of the controls:
- Stretch: set Stretch Distance to: TRUE ? 0.0 : [expression]
- Repeat: set Number of items to: TRUE ? 0 : [expression]
- Width: the same thing can be done with the Width control IF the Width Change is Relative. A 0.0 would result in no change.
- Rotate/Move/Mirror: the same method will work here also although you will need to disable each of the three functions that is being used. If a given control is setup to do both a rotate and a move and you only disable the rotate it will still do the move.
- Polar: this one is a little more complicated. You need to set the Angle Start and Stop to the same value so that it doesn't make any iterations. For example, if Start was 0.0 and Stop was 2*PI, you might set the Stop to:
TRUE ? 0.0 : 2*PI - User-Defined: as previously discussed (in the section about deletion of shapes), having the function return the shape data unmodified will have the effect of doing nothing. So to disable a User-Defined control one could set the function as:
TRUE ? _shape_data : [ function call ]
Multi-Model Drivers
| Note This section is for very advanced library builders who are familiar with AEL and the procedures for building libraries of models for use by designers. |
While is should be possible to create a PAM that will support any physical model you can think of, sometimes the effort to design it is just to great and instead you create two or more simpler models. A multi-fingered fet might be an example of this. Due to the physical properties it may be just too hard to make one model that can handle the one finger case and the 2-n finger case. So, you build two models: the one finger model and the 2-n finger model.
The problem is that you would like to have just a single fet model in the library, not the two special-case models. What you would like is a single parameterized point-of-control that would call the correct special-case model as needed.
Again, this assumes you already understand how to create library elements for use in ADS. This section is not going to provide the details on the use of the create_item() , create_parm() , and function calls that are used to do this. We will assume you have defined the fet model for the library, and you have specified that the library element will call an artwork procedure named fet_artwork() with two parameters: number of fingers, and length (of the fingers).
You now need to create the fet_artwork ) procedure such that it can take the provided parameters and call the correct special-case model. Such a procedure might look something like this:
defun MWTD_FET_ARTWORK(finger, length)
{
if (is_string(finger))
finger = evaluate(finger));
if (!is_integer(finger))
finger = int(finger);
if ((finger < 1) || finger > MAX_FINGER) {
/* print an out-of-range error message */
return;
}
if (finger == 1)
pam_finger1(length);
else
pam_fingerN(finger, length);
Privacy
Statement
|
Terms of Use
|
Legal |
Contact Us
|
© Agilent 2000-2008 ![]()