There are a number of factors that determine the size and complexity of circuits that can be designed. One major factor is the quality and power of the design tools. Generators can produce large arrays, routers and compacters can manipulate large layouts in special-purpose ways, and silicon compilers can produce great amounts of layout from small, high-level specifications. Another factor in the production of large circuits is the use of good design techniques such as hierarchy and modularity. However, there comes a point in many large design efforts where something more is needed to help with special-purpose tasks.
To go beyond the limitations of standard circuit production facilities, it is necessary to develop custom tools and techniques. Occasionally, this can be done by combining existing facilities, for example by using array constructs to aid in repetitive tasks. More often it can be accomplished through command macros that allow complex operations to be built from simpler commands. This still leaves several unresolved issues. For example, how can an ordinary set of editing commands be used to design correctly a cell with proper pullup and pulldown ratios? How can they be used to adjust the spacing of an entire hierarchy when a low-level cell changes size? These issues and many others can be resolved only when the available commands provide the expressiveness and power of a programming language--when they are able to examine circuits and to react appropriately. Since the parallels between VLSI design and computer programming are strong, it should come as no surprise that programming is actually a design technique.
Programmability can be found in two forms in a design system: imperative or declarative. Imperative programming is the usual form: an explicit set of commands that are sequentially executed when invoked by the designer. Declarative programming is the implicit execution of commands that result as a side effect of other design activity. Dataflow programming is declarative, because execution is determined by the data and not by the code order. Declarative programming in a design environment is often viewed as constraints or daemons because the commands reside on pieces of the circuit. Figure 8.1 illustrates the imperative and declarative ways of expressing a relationship between two values.
| |
FIGURE 8.1 Imperative versus declarative code. |
In addition to there being two forms of programming in a design system, there are two ways that these programs can be expressed. Some languages are purely textual, such that a page of code defines a circuit. Others are graphic in nature, using an interactive display to build the circuit. Textual design languages tend to be primarily imperative in their sequencing, with a few declarative options, whereas graphic languages reverse this tendency, being mostly declarative with occasional imperative sections. Figure 8.2 shows graphic ways of expressing the relationships in Fig. 8.1.
FIGURE 8.2 Graphical imperative and declarative code: (a) Imperative (b) Declarative. |
The unfortunate aspect of computer programming is that it is often so complicated that designers do not learn to do it. This is especially true in graphic design systems, which allow the designer to build an entire circuit without needing to write any code. The solution to this problem is to present programming in a restricted sense that is tailored to the design task and thus is easier to learn. For example, if the command interface allows macros, variables, algebraic expressions, conditionals, and other language features, then it is powerful enough to express any algorithm. Although the use of these features constitutes textual imperative programming, it is merely an extension of commands that are already familiar to the designer. This makes design programming easier to learn because it can be done only when it is needed.
Another way to add programmability is to provide constraining structures as part of the layout. A simple example is the constraint that a wire must remain connected to its components, and not change length. Constraints react to changes in the circuit by invoking other changes. In this example, a change to one component fires a constraint that changes the wire, which then fires a reverse constraint that affects the other component. This declarative programming is more intuitive than are conventional languages because the commands fit into the circuit being designed and are a natural extension of the layout.
The most obvious method of adding programmability is to provide a full programming language. Many systems begin with known languages and add macros or subroutines to make them handle circuitry [Batali and Hartheimer; Weste]. The resulting programming languages are called embedded languages because they have added design constructs. There are also design languages that have been created exclusively for the design task but still resemble full programming languages [Sastry and Klein]. Embedded languages have the advantage that there is already a body of knowledge and experience about the language in which the new constructs are embedded. Although the original language is usually imperative, the added design constructs can be declarative, with constraint statements that affect the circuit structure.
Another issue that must be addressed in programmability is the use of hierarchy. Textual programming languages can be confusing because they may have a code hierarchy that is different from the design hierarchy. A clean design language will equate subroutines with cells so that each code routine generates exactly one layout routine. Of course, exceptions must be made for auxiliary code routines that have no corresponding cells.
The nature of information flow through the design hierarchy is a major issue that must be addressed when providing programmability. If the programming of each cell is dependent on its surrounding circuitry where it is instantiated higher in the hierarchy, then the programming works in a standard subroutine fashion: Parameters passed at the call (the cell instance) affect that particular version of the subroutine (the cell definition). Just as each different call to a subroutine results in a different execution sequence, so each different instance of a cell will yield a different layout at that point in the circuit. This facility, called parameterized cells, results in top-down programmability because information is passed down the design hierarchy to affect all lower levels. It is commonly found in textual design systems.
The opposite type of design programmability is bottom-up, in which a change to a cell definition affects all the instances and thus causes specification information to be passed up the hierarchy. In such a language, cells are not parameterizable and all instances of a cell are identical. This kind of hierarchy management is found in graphic systems and in those systems without programmability in which changes to a cell definition merely result in equivalent changes to every instance. Bottom-up schemes can be made programmable by having cell-definition changes react properly and make correct alterations to the circuitry surrounding their instances at higher levels of the hierarchy.
The rest of this chapter discusses the three issues of programmability introduced here: imperative programming, declarative programming, and hierarchy. Although many VLSI designers have been trained first as programmers, there will always be those who dislike programming and do not want to deal with it explicitly. Nevertheless, programming tasks exist to a certain degree in all design systems and most people find this programming very useful. The enhancement of programming provides powerful possibilities for productivity.
Previous | Table of Contents | Next | Electric Editor, Inc. |