Programming | Other » Debugging tips

Datasheet

Year, pagecount:2001, 3 page(s)

Language:English

Downloads:12

Uploaded:November 18, 2012

Size:16 KB

Institution:
-

Comments:

Attachment:-

Download in PDF:Please log in!



Comments

No comments yet. You can be the first!


Content extract

Debugging Tips What is to be done when the flow breaks? When modification of the flow’s code is necessary, it is important to have some mechanism for verifying the new code before it is released to the users. This section describes the flow for debugging new code which was used to develop the prototype design flow. 1 Running Steps Interactively The API functions begingen and endgen were specially designed to make interactive debugging easy. For example, if you want to write a SKILL function that deletes an instance named “Dummy” and then saves the cell, all you need to write is procedure( deleteDummy( @key (src nil) (dest nil) (stepargs nil) ) prog( () begingen(“deleteDummy”) dbDeleteObject(dbFindAnyInstByName(cdb “Dummy”)) endgen(t) ) ) Of these 7 lines of code, the first and last three lines are a template. The only things we have had to think about were what to name this procedure (“deleteDummy”) and to create a line of code that references the standard cell-view

database handle cdb. The begingen function always sets the value of cdb. To execute this function, simply start Design Framework II (generally with the icfb executable), open any cell-view in edit mode, and type the following in the command interpreter window (CIW): deleteDummy In addition to seeing the instance disappear in the opened cell-view, you would also see the following messages appear in the CIW: Begin deleteDummy Finished deleteDummy (elapsed time: 0h 0m 0s actual) What’s nice about this is that you have written a step which can be plugged into the flow at any point. These messages were written to the CIW, but if this procedure had been invoked using ICMake, then they would have been printed to the common log file. You can print your own messages using the logf function. If you wanted to print out the x-y location of the instance before you deleted it, you could modify the function as follows: procedure( deleteDummy( @key (src nil) (dest nil) (stepargs nil) ) prog(

(inst) begingen(“deleteDummy”) inst = dbFindAnyInstByName(cdb “Dummy”) logf( LOG INFO “Dummy can be found at %L” inst~>xy ) dbDeleteObject(inst) endgen(t) ) ) Note that we have added the private variable “inst” in the prog statement. As a general rule, procedures should make all variables private unless they can somehow guarantee that setting a global variable will not disrupt a calling function. In addition to the common log file, another important benefit of writing functions in this way is that there is a common mechanism for error trapping. What happens if the dummy cell does not exist? If we run this step interactively, we see a cryptic message in the CIW: *Error dbDeleteObject: argument #1 should be dbobject (type template = "d") - nil This is because the dbFindAnyInstByName function returned nil, and dbDeleteObject halts with an error when passed nil. Worse yet, if someone was running this procedure as part of a larger flow with ICMake, all

they would see is that icfb crashed and would have to go digging through a different log file to find the reason. To make life easier for the user, we could re-write the function as follows: procedure( deleteDummy( @key (src nil) (dest nil) (stepargs nil) ) prog( (inst) begingen(“deleteDummy”) inst = dbFindAnyInstByName(cdb “Dummy”) if( !inst then dief(“ERROR: Could not find Dummy”) ) dbDeleteObject(inst) endgen(t) ) ) Here, the dief function writes an error message to the common log file. More importantly, it exits the procedure and bypasses the error so that the flow does not crash. This is because the “prog” structure can be exited at any time, generally with the “return” function. In our case, the dief function is a wrapper for “return” So, if the dummy instance is not found, we see the same messages, whether running interactively or in a larger flow: Begin deleteDummy ERROR: Could not find Dummy Terminated deleteDummy (elapsed time: 0h 0m 0s actual) 2

Developing code incrementally It can accelerate the development of code very much to have one window open with a reference cell and another cell opened with the code under development. What mechanism exists for quickly re-running a procedure when the source code is modified? The startup files for Design Framework II (“run/cds/.cdsinit”) and Design Planner (“run/dp/.hldLocal”) each define a function called reinit This function loads all of the code for the entire flow. By typing “reinit” in the CIW or “(reinit)” in the Design Planner command window, all code will be reloaded, and the procedure under test can be reexecuted interactively. If the procedure under test is defined in a new file, add the new file into the definition of the reinit procedure. This can either be added directly into the .cdsinit or hldLocal file or can be added into the template file referenced by the SSHAFT techfile. How can we easily test the new procedure in the complete flow? Once we modify

the reinit function in the global .cdsinit and hldLocal templates, we force all users of the flow to use our new code. Thus, if we introduce any errors as we develop new code, we can keep other group members from getting any work done. How do we shield users from the debugging process? We do this by creating a private source directory which contains all of the design flow’s SKILL or common-lisp code, including any new files we may have created. Then change the value of the SSHAFT SKILL or SSHAFT CLISP environment variable to be the private source directory path. The reinit function automatically prepends this path when loading files. Thus, when the debugging process is finished, the new code can be “checked in” to the global location and the code developer can simply change the value of the SSHAFT SKILL or SSHAFT CLISP environment variable back to its original value. 3 Modifying the ICMakefile