Distributed Hierarchical Simulation

An architectural overview


If there is a list of the properties that such a hierarchical simulation system should have, scalability will be on top of that list. By scalable I mean that mininum effort is required to add a new object into the original system. With that in mind, I would like to illustrate the working mechanism and some of implementation details of such a distributed hierarchical simulation system.

The proposed approach is "component based" and it is particularly appropriate to the construction of design for a  digital systems.  For each module in a digital system, we construct a corresponding computational object called "component" which encapsulates the behavior of that module, or in other words, a component is capable of "self-simulating".  Our hope in this approach  is that extending the model to accommodate new physical module will  require no strategic changes to the overall design, only the addition of  the new symbolic analogs of those modules— components. If we have been successful in our system organization, then to add a  new feature or debug an old one we will have work on only a localized part of the system.

According to our current model, there are two kinds of components in our simulation system: base components and high level components. Base components possess behavior corresponding to the function modules at the bottom level of the abstraction hierarchy of a physical system; they are indivisible entities and can be thought of as the "bricks" of the complete simulation system.  If we knit these "bricks", that is, we pack base components and regard the collective behavior of these base components as the behavior of a single entity, we then have high level components. However, such "abstracting" is not going to end here, obviously, we can keep building one level of abstraction on top of another, until we have an abstraction "pyramid". To complete the definition of the a high level components, we claim that except the bottom part of such a abstraction "pyramid"(certainly we call the bottom part "base component") , components at all other levels are high level components. In particular, the one at the peak which encapsulate the overall behavior represents the entire design.

Components "talk" with each other. One type of interaction occurs within the same abstraction level-- a component is "driving" and being "driven" by its neighbors. To illustrate this, let’s say component A, component B and component C are at the same level of abstraction, A gets input from somewhere and computes the output; B brings in this output and does the computation to drive C. We define the output from C as the output of the whole system consisted of A, B and C. It is important to point out that the topology of the system is simplistic and can be, in reality, much more sophisticated. Another type of interaction is  between two adjacent abstraction level. In the above system, if we wrap A, B and C into a high level component called SUPER, then SUPER must be able to define the computation sequence: it orchestrate A, B and C when to compute and where to look for inputs. So in every component we need a piece of data structure called "scheduler" to serve this purpose and because of that, every component only has the concept of "local time", where the local time of each component is determined solely by messages passed to it in the normal course of the simulation.

Based on the illustration of the previous example, a component must be able to perform certain functions. First, it must be able to describe its own behavior subject to external inputs. Second, it should be able to communicate with other components either locally or remotely (and such complication of communication mechanism should be isolated from the developers); there are also special cases to be taken care of, that is, one components might have to retrieve and return data from and to the high level component, in that case, a high level components is treated. Last, it should be able to validate its own status and be aware of the input source and output destination according to the the "component map", which will be clarified later in the artical.

In the case of a high level component, the scheduler is needed to specify relation between all the sub-components in the same way how the corresponding hardware modules be wired together. We design a scheduler to do the following: it must have the knowledge of where all the sub-components are and be able to validate that information; it also should be able to interact with users, for instance via GUI, because users are the ones that decide the formation of the design. The result of the final design is summarized in a "component map" by the scheduler. The component map will be distributed to all the sub-components and by looking up the component map, each sub-component gets accquaited with the address of the input sources and output destinations. All these procedures of users interacting with the scheduler happens at the so-called "set up" stage and the scheduler is not supposed to play any role during the "simulation" stage.The scheduler also represents the high level component which it was contained in the sense that the location of the scheduler is defined to be the location of the high level components.

This is how the system should work: first, the designer brings up the schematic editor and component library is shown up on the screen with a list of pre-build component (they could be at various level of abstraction level), then he selects all the components and wires them to form a higher level components and save it somewhere. If he wants to verify the work he has just done, he simply runs a push-button simulation and the output either at wave form or text form will show up. At the back end, the design is translated into a component map and distributed to all the subcomponents and that turns many different independent "unconscious" components into "siblings". When the "simulate" button is pushed on the screen, the top level component reads inputs and feed them to the adjacent level components. Such process will recurse until the based components have been reached and the computation is done and the result will merge back up until the top level is reached again and the output will get back to the user at the point.

Below are some of the pseudo code used to describe the functionality of a component and the scheduler.

}


The scheduler is special because it have the knowledge of where all its children are and be able to coordinate the data flow between the children. We should be able to interact with the scheduler, decide how the hardware will be stacked up and the process would be something like bringing up a schematic editor and grabbing components from the library and wiring them together. At the back end, it is the scheduler that is being edited. The scheduler should validate all the children by remotely invoking the "is_alive()" method of every child. It builds a component map in which the siblings are listed according to its network address and the component map should be sent to every child so that every child knows to whom it should relay the data to.The scheduler is also aware of the data type mismatches. It is important to point out that the scheduler only plays a role at the setup stage of the simulation system. The source code will be like follows:
class Scheduler {


A high level component is built on top of some base component and is also an instance of design object. It takes care of the I/O and dispatches data to its children . Its simulation method doesn't have real meat but just a stub.


Class Boss extends Design_Object {

2. implementation details

Jimmy Zhang zhengyu@ic.eecs.berkeley.edu