Connectal Project Structure¶
The set of files composing the input to the Connectal toolchain is referred to as a project. A collection of out-of-tree example projects is available at https://github.com/connectal-examples. To illustrate the structure of a project, this chapter uses the example https://github.com/connectal-examples/leds, which can be executed on the Bluesim or Zynq target platforms.
Project Makefile¶
The top-level Makefile in the project (in our example, https://github.com/connectal-examples/leds/blob/master/Makefile) defines parameters building and executing the project. In its simplest form, it specifies the hardware and software source files, which Bluespec interfaces to use as interfaces (portals) between them, and the libraries to use for the hardware and software compilation:
INTERFACES = LedControllerRequest
BSVFILES = LedController.bsv Top.bsv
CPPFILES= testleds.cpp
include \$(CONNECTALDIR)/Makefile.connectal
BSVFILES
is a list of bsv files containing interface
definitions used to generate portals and module definitions used to
generate HW components. Connectal bsv libraries can be used without
being listed explicitly.
CPPFILES
is a list of C/C++ files containing software
components and main
. The Connectal C/C++ libraries can be
used without being listed explicitly.
INTERFACES
is a list of names of BSV interfaces which may be
used to communicate between the HW and SW componentsy. In addition to
user-defined interfaces, there are a wide variety of interfaces
defined in Connectal libraries which may be included in this list.
NUMBER_OF_MASTERS
is used to designate the number of host
bus masters the hardware components will instantiate. For PCIe-based
platforms, this value can be set to 1, while on Zynq-based
platforms values from 1 to 4 are valid.
CONNECTALDIR
must be set so that the top-level Connectal
makefile can be included, defining the makefile build targets for the project.
This brings in the default definitions of
all project build parameters as well as the Connectal hardware and
software libraries. When running the toolchain on AWS, this varible
is set automatically in the build environment.
(See Compiling and Running Connectal Project)
Project Source¶
Interface Definitions¶
label{interface_definitions}
When generating portals, the Connectal interface compiler searches the
Connectal bsv libraries and the files listed in BSVFILES
for
definitions of the interfaces listed in INTERFACES
. If
the definition of a listed interfaces is not found, an error is
reported and the compilation aborts. The interfaces in this list must
be composed exclusively of Action
methods. Supported method
argument types are Bit\#(n)
, Bool
,
Int\#(32)
, UInt\#(32)
, Float
,
Vector\#(t)
, enum
, and struct
.
Software¶
The software in a Connectal project consists of at least one C++ file
which instantiates the generated portal wrappers and proxies and
implements main()
. The following source defines the SW
component of the example, which simply toggles LEDs on the Zedboard
(url{https://github.com/connectal-examples/leds/blob/master/testleds.cpp}):
#include <unistd.h>
#include "LedControllerRequest.h"
#include "GeneratedTypes.h"
int main(int argc, const char **argv)
{
LedControllerRequestProxy *device =
new LedControllerRequestProxy(IfcNames_LedControllerRequest);
for (int i = 0; i < 20; i++) {
device->setLeds(10, 10000);
sleep(1);
device->setLeds(5, 10000);
sleep(1);
}
}
The makefile listed LedControllerRequest
as the only communication
interface. The generated proxies and wrappers for this interface are
in LedControllerRequest.h
which is included, along with C++
implementations of all additional interface types in
GeneratedTypes.h
. Line 9 instantiates the proxy through which
the software invokes the hardware methods
(See also Flow Control)
To support projects that will execute software inside the linux kernel (for example, to work in conjunction with filesystems or the network stack), connectal project software can also be written in C.
Hardware¶
Connectal projects typically have at least one BSV file containing interface declarations and module definitions. The implementation of the interfaces and all supporting infrastructure is standard BSV. Interfaces being used as portals are subject to the type restrictions described earlier (See also Interface Declarations)
Top.bsv¶
In Top.bsv (https://github.com/connectal-examples/leds/blob/master/Top.bsv), the developer instantiates all hardware modules explicitly. Interfaces which can be invoked through portals need to be connected to the generated wrappers and proxies. To connect to the host processor bus, a parameterized standard interface is used, making it easy to synthesize the application for different CPUs or for simulation:
// Connectal Libraries
import CtrlMux::*;
import Portal::*;
import Leds::*;
import MemTypes::*;
import MemPortal::*;
import HostInterface::*;
import LedControllerRequest::*;
import LedController::*;
typedef enum {LedControllerRequestPortal} IfcNames deriving (Eq,Bits);
module mkConnectalTop(StdConnectalTop#(PhysAddrWidth));
LedController ledController <- mkLedControllerRequest();
LedControllerRequestWrapper ledControllerRequestWrapper <-
mkLedControllerRequestWrapper(LedControllerRequestPortal,
ledController.request);
Vector#(1,StdPortal) portals;
portals[0] = ledControllerRequestWrapper.portalIfc;
let ctrl_mux <- mkSlaveMux(portals);
interface interrupt = getInterruptVector(portals);
interface slave = ctrl_mux;
interface masters = nil;
interface leds = ledController.leds;
endmodule
Like the SW components, the HW begins by importing the generated
wrappers and proxies corresponding to the interfaces listed in the
project Makefile. The user-defined implementation of the
LedControllerRequest interface is instantiated on line 14, and wrapped
on line 15. This wrapped interface is connected to the bus using the
library module mkSlaveMux
on line 21 so it can be invoked
from the software. At the end of the module definition, the top-level
interface elements must be connected. A board-specific top-level
module will include this file, instantiate mkConnectalTop
and
connect the interfaces to the actual peripherals. The module
mkConnectalTop
must be defined in a file named
Top.bsv
in the user project.
The Bluespec compiler generates a Verilog module from the top level
BSV module, in which the methods of exposed interfaces are implemented
as Verilog ports. Those ports are bound to physical pins on the
FPGA using a physical constraints file. If CPU specific interface
signals are needed by the design (for example, extra clocks that are
generated by the PCIe core), then an optional CPU-specific HostInterface
parameter to mkConnectalTop
can also be used. If the design uses
external pins on the FPGA, those connections are also made here by
exporting a ‘Pins’ interface
(hyperref[host_interface]{Section~ref{host_interface}})
and providing bindings in the constraints file.