MetroC: introduction
The key elements of the library are depicted in the picture above along with their
relationships:
- core-lib: a C++ library and simulation kernel that extends C++ using the
semantics of the metropolis metamodel;
- types-lib: an xml based encapsulation mechanism to allow interchange among
different domains of data according to well-established interfaces;
- hw_cosim: a C++ library based on the adapter design pattern that provides the necessary layer that
allows two different domains communicate and simulate according to a pre-defined
schema. This schema is implemented in the adapter. Since the communication among
different domains is an ill problem the implementation has to provide some rules
to resolve it.
The core library uses the semantics of the metropolis metamodel. The core of the
infrastructure is a meta model of computation, which allows one to model various
communication and computation semantics in a uniform way. By defining different
communication primitives and different ways of resolving concurrency, the user can,
in effect, specify different models of computation (MOCs). At a high level of abstraction,
the designer may want to use an MOC that is convenient to describe the functionality.
The functional model just represents what a system is supposed to do. On the other
hand, metropolis allows the description of architectures and finally the mapping
of the former to the latter. The result of a mapping is another model whose level
of abstraction is lower that the original functional model.
The word platform is used to refer to three different kind of platforms:
- the hardware platform, a family of architectures that satisfy a set of architectural
constraints that are imposed to allow the re-use of hardware and software components;
- the software platform, a layer that wraps the essential parts of the hardware platform
in order to allow application software "sees" a high level interface to the hardware
(the Application Program Interface or API);
- the system platform, the combination of hardware and software platform.
In figure the term platform-stack is used to refer to the combination of two platforms
(software and hardware) and the tools that map one abstraction into the other. The
platform-stack can be seen as a "single" layer obtained by gluing together the top
platform and the bottom platform whereby the upper view is the API platform and
the lower view is the collection of components that comprise the architecture platform.
When the upper part is mapped on the bottom part, a system platform instance is
chosen for that particular stack at a certain level of abstraction. In order to
abstract the definition of the hardware platform the use of different models of
computation are allowed at different abstraction levels.
The goal of the MetroC core library is to provide the necessary infrastructure to
build software and hardware platforms in such a way that each platform stack can
be easily explored and connected with other platform stacks.
The key articulation points around which the metropolis framework is built are:
- the basic components that glued together give birth to the final system (netlists,
mediums, processes, ports, etc);
- a very light, generic and extendible simulation core capable of accommodating different
models of computation (MOC). Each MOC may be developed as a library extension on
top of the core library. An example of such extension is the xGiotto library.
- a generic co-simulation framework that allows different platform stacks talk together.
The way the different platform stacks are developed depends on the abstraction level:
at top levels C++ code based on Metropolis framework may be more suitable, whereas
at the bottom levels VHDL/Prolog models of hardware IP blocks may be used. In order
to provide an unified framework that allows different stacks exchange data and use
services (API) two libraries have been developed:
- a co-simulation library that abstract the services by providing a single common
API;
- a library of basic types to handle generic data exchange.
The type library is developed as a set of C++ classes with the same interfaces as
C++ basic types. The common operations have been overloaded (plus, minus, etc...)
thus using C++ basic types or the corresponding type library classes is exactly
the same. The power of the type library classes is exploited during data exchange
among different and enterogenous domains where they offer a marshalling mechanism
(typeslib)
to the co-simulation library.
The methodology is based on defining Platforms at the different key articulation
points in the design flow. Each platform represents a layer in the design flow for
which the underlying, subsequent design-flow steps are abstracted.
The proposed design flow is shown in figure.
At the top level of abstraction the main functionalities are captured throughout
different processes. Once the functionalities are established, these functionalities
are tested on a simulation platform (step 1). This platform is purely functional
and does not correspond to the target platform. It may have a completely different
architecture in terms of cpu, memory, storage, etc. This design process is iterated
(step 1-2) until the overall functional model is working.
The design flow of the functional model follows the standard software design cycle.
Software life cycle deals with the all activities and work products necessary to
develop a software system.
Four fundamental process activities are usually necessary
- software specification (requirements, functionality and constraints)
- software development (design and implementation)
- software validation (ensure that the software meets the customer needs)
- software evolution (evolve to meet changing customer needs)
The idea of platform based design is to extend software design patterns to hardware
platforms moving from left side of the figure to right side of the figure.
Each platform stack can be seen as merging together a chosen software platform instance
with a chosen hardware platform instance. According to the level of abstraction
step 2 may be realized in the same semantic domain of Metropolis framework or in
another domain. Consider for example the task of developing an embedded system,
from the low level RTOS up to the applications. The API provided by the OS may be
developed in metropolis itself. When the platform stack (step 4,5 and 6) considered
is the one that glues together the RTOS and the hardware components of the embedded
system it may be more suitable a description in VHDL or verilog of the very same
IP blocks.
In order to mingle together different heterogenous subsystems a high level interface
along with a predefined set of API to access it have been defined. Each component
(either software or hardware) provides a set of services throughout this interface.
In the implementation this interface is an unique and generic function called
execute().
This execute() is the connecting point between the upper part of the ASV triangle
and the lower part. For example, in the Linux OS the execute() function role is
carried out by int 0x80.
In a cpu model the call to execute() means fetching from memory one or more instructions,
execute them and return the results. At all level of abstraction one can find that
this paradigm is true. Since the interfaces are different (int 0x80 in Linux, fetch,
decode and execute in a CPU model) according to the type of services offered, the
only possibility is to abstract the concept of service. A service is like a
black box with inputs and outputs. Once the inputs and outputs are
standardized and the internal behavior of the black box is known (the implementor
of the black box has captured a feasible behavior to resolve the co-simulation problem)
then the user of the black box may just call the execute() function that a feasible
execution trace is ensured by construction.
The execute() function role is carried out by the atom in the core-lib.
An atom abstracts all the events between the begin and end event of the atom. For
instance, an atom cannot contain a request to a quantity because the events in an
atom are not visible. An atom is the smallest execution unit that is executed without
interruption (by the simulator core) from the begin up to the end. In core-lib compositions
of atoms are allowed. One very natural composition is the sequential one that, if
things are well architected, will make it possible to map Metamodel processes to
MetroC processes. Another one is the parallel composition, that will allow many
Metamodel processes to be mapped to one MetroC process.
An atom can be refined in the same core-lib domain or mapped to another domain.
Another domain may be an external tool (i.e. an instruction set simulator, a VHDL
simulator, etc ...) or another core-lib based block (i.e. a network of nodes developed
in Metroc that communicate among them, a discrete domain and a continuous domain,
etc ...).