In this article we explore the different aspects of a novel development environment, including hardware platform description, application development, as well as built-in runtime and trace facility.
Advanced systems are becoming increasingly complex, forcing manufacturers to spend correspondingly greater time developing and debugging each device—typically with little visibility into system-level interactions of multiple components. Visual System Integrator (VSI) is a unique tool that facilitates system design and integration by enabling designers to graphically describe their heterogeneous systems completely and accurately. Based on this description, the tool automatically generates drivers required for communication across standard interfaces. Consequently, architects and engineers can focus on their key differentiators rather than on designing and debugging standard data transport and device drivers. VSI is flexible enough to allow the user to extend or replace the implementation of any of the runtime components. In this article we explore the different aspects of this novel development environment, including hardware platform description, application development, as well as built-in runtime and trace facility.
Describing the hardware platform
The VSI Platform description environment accelerates platform creation and maintenance by providing an intuitive visual environment for the task, enabling system architects and even software developers to rapidly create and iterate on complex hardware platforms. Figure 1 below illustrates a platform composed of and FPGA board connected to an external host. Note that the user specifies which interfaces to elevate at system level.
Figure 1: VSI platform description.
A VSI platform description starts by defining "Execution Contexts", or entities that are capable of executing "code". In this example it consists of an x86 based host server and a Xilinx Virtex-7 FPGA. For the software execution contexts (x86), the user specifies the details such as the number of processors, cross compiler to use (if any). For the FPGA context the user specifies the part number of the FPGA being used along with the specifications of the board. The user then describes the connectivity between the execution contexts, in this example the FPGA board is connected to the x86 using PCI/e. The PCI/e driver as well as the FPGA PCI/e interface is configured using intuitive dialog boxes. The connection between "execution contexts" are termed "Platform Interfaces". The platform description contains the interfaces that allow the system to communicate with the external world. In this example, we use an Ethernet MAC in the FPGA. The interfaces of the Ethernet block that are exposed to the application system are marked in the platform description as "System Interfaces", denoted by the vertical lines on the Ethernet MAC in figure 1. The other parameters of the Ethernet MAC including clocking structures required for the interfaces are also described in the platform. The platform specification is packaged for use by by application systems by "Compiling Platform". This generates the meta data required for use by application systems. The Platform can be changed and recompiled during the lifetime of a project to accommodate changing hardware requirements.
Developing an application
The application development process begins by "Importing" the platform the application is going to use. Execution contexts and system interfaces are imported into the application development platform as shown in figure 2a.
Figure 2a: Execution contexts and system interfaces are imported into the application development platform.
Other details of the platform description are not shown in the application development "canvas", this allows the application developer to focus on "algorithms" and core differentiating features without having to worry about low level "platform issues" such clocking and I/O handling. Application development involves adding blocks of "code" to execution contexts. The "code" blocks can come from libraries provided for each "type" of execution context (x86/ARM has a different library from FPGAs), in figure 2a the "TCP Server" block comes from the "Software Library" and the "DSP Function" blocks comes from the FPGA library. The libraries are extensible (Users can add blocks into the libraries). Existing C/C++ code can also be imported into an execution context using an intuitive code import interface. HLS synthesizable C/C++ code can be imported into an FPGA execution context. Synthesizable C/C++ blocks can be moved between FPGA & Software contexts, as shown in figure 2b.
Figure 2b: Synthesizable C/C++ blocks can be moved between FPGA & Software contexts.
The block interfaces are connected to describe how the data flows between the different blocks, connections A through F in figures 2a and 2b shows the data flow graph for this example application. Once the connections are completed the user can "Generate the complete" system, which generates the outputs shown in figure 3.
Figure 3: Outputs.
The "System Compiler" takes both the "Platform description" and the "Application System" as inputs and generates: a. Complete software projects for "all" the software execution contexts, the software projects are generated using CMAKE which allows the user to import the project into an IDE of their choice (Visual Studio, Eclipse, Qt are some of the IDEs that are already supported). b. For the synthesizable C/C++ blocks that are present in the "Application system" the compiler generates "HLS wrappers" (including the #pragmas required for interface synthesis) and complete Vivado HLS projects, the compiler also generates the AXI infrastructure & connections to the handshaking & clocking signals as required to connect these HLS blocks to the rest of the System, c. The compiler generates complete and separate projects for all FPGA "execution contexts" specified. The compiler also generates all the code and scripts required to initialize the "Device Drivers".
Execution Model (Runtime) Blocks executing in Software contexts are executed on separate threads, this allows the blocks to execute asynchronously and in parallel. The "connection" between blocks are treated as non-blocking pipes. The threads for the block wake-up for execution when data arrives on inputs designated as "Execution Trigger". The blocks can also be configured to execute based on a timer, this is intended to be used for scenarios that required a timed event generation such as motor control. The interfaces crossing between Software & FPGA (interfaces C & F in Figure 2 (a), interfaces C & E in Figure 2(b)) are treated as "Device Descriptors". The "Common Device Driver" developed by System View converts "read" and "write" requests to these "descriptors" into DMA transfers or Register reads/writes depending on the device being accessed. The VSI runtime converts transfers on these interfaces to reads and writes to corresponding descriptors.
Software Import Wizard
Figure 4a shows a screen shot of the "Software import Wizard". The wizard allows an easy and intuitive method for importing existing C/C++ code into the Visual System integrator environment. The Import wizard consists of multiple panels the initial panel allows the user to specify the C/C++ function is to be called when the thread associated with the block is executed, the number of arguments the function accepts. The "Execution Criterion" for this block determines when the thread associated with this block will be executed the choices are "Argument Change" (wake up thread when new data arrives on selected input parameters) or "Timer Expiry" (wake up the thread whenever a timer with a specified period expires). The last parameter specifies the directory where the source resides for the function, this is used during project generation.
Figure 4a: Software import Wizard.
The second panel ("Arguments", figure 4b) is used to provide more specific information about each of the arguments of the function that will be called. For each argument the C/C++ name & type are required, the wizard allows any or all of the input arguments to be "Execution Triggers", this allows the user to choose which argument change will cause the block to execute. The "Access Type" attribute is important when the block is placed in a FPGA execution context, in this case "Sequential" will cause a streaming interface to be inferred, by specifying this access type the user also promises that this parameter (pointer or array) will be accessed sequentially both for reading and writing purposes.
Figure 4b: The second panel.
The last panel ("Advanced", figure 4c) is provided for users who want to provide extra control of High Level Synthesis. These parameters are passed to HLS when the project is created.
Figure 4c: The last panel.Trace
Each connection in Visual System Integrator regardless of the Execution Context can be designated to be traced. Trace can be turned on/off by selecting the connection, right clicking and choosing "Toggle Trace". When trace is enabled for an interface a "trace" icon appears on the interface. Figure 5 shows a screen shot of the VSI trace in action. It shows all the interfaces that were annotated with the trace attribute. When an event occurs on any a given interface, it is shown on the "timeline", selecting the event on the timeline view will display the relative time when the event occurred starting from the time the connection was established. Selecting two events simultaneously will display the details of each event as well as the difference in time between the two events. The trace view consolidates the events from all "Contexts" and displays them on a single console. This allows system bottlenecks and functional problems to be identified easily.
Figure 5: VSI trace in action.
VSI is unique in allowing users to describe their hardware platform and develop applications in a high level, intuitive and integrated environment. VSI automates the grunt work of platform design and system integration, and generates production ready code at the press of a button. In addition, it provides unprecedented visibility into the runtime without sacrificing performance.