Gravel is an embedded DSL (within C++) for creating hardware.
Gravel::Symbol a(“A”);
Gravel::Symbol c(“C”);
Gravel::Expression b = a + a;
Defines an expression b
, which is a + a
Symbols and Expressions are referred to as ‘Actors’ in the library and each Actor is represented uniquely in an actor graph.
Gravel::Module module(“MyModule”);
Defines a module “MyModule”
And at any time, symbols can be added to the module as inputs or outputs using the syntax
module << a;
or
module >> b;
Modules ‘own’ actors in the actor graph and that ownership is transitive through expressions. The propagation of ownership must occur before symbols go out of scope (when they are orphaned) – propagation occurs automatically whenever an expression or an assignment is created.
Assignments are created using two functions
Gravel::Assign( c << b );
creates a continuous assignment to symbol c from the expression b
Gravel::Delay(c << b);
creates a clocked assignment to symbol c from the expression b
The reset value of a variables (such as ‘c’) which has a clocked assignment can be set using the function
Gravel::Reset(c, 2);
Which would assign the value ‘2’ to the variable c at reset.
Gravel::Mux mux(c) << b << d ;
Creates a multiplexer expression whose ‘select’ input is c and whose input values are b and d
The output of a mux expression can be assigned to a symbol using either Gravel::Assign() or Gravel::Delay() options
Foreign Modules are Verilog Modules (parsed from Verilog source)
Module a;
std::cin >> a;
parses a module description from an input stream.
A static pointer to a Gravel::Context singleton can be retrieved using
Gravel::Context::GetInstance();
This class contains various functions for querying the existing verilog model.
The final Verilog can be generated using
Gravel::emit(std::ostream&)
Modules can be instantiated using an instantiation map
Gravel::Symbol c = ctx->getSymbol(module, “a”);
Gravel::Symbol d = ctx->getSymbol(instantiated_module, “d”);
Gravel::Module::SymbolMap sm( c << d )( e << f )( g >> h ) ;
Gravel::Instantiate(instantiated_module, “my_module_instantiation”) << sm;
Every edge in the symbol map must cross an instantiation boundary.
You can edit the instantiation by retrieving the instantiated module using
Gravel::InstantiatedModule inst = ctx->getInstantiatedModule(module, “instantiated_module”);
Gravel::Module definition = Gravel::Module::ModuleDefinition(inst);
Then retrieve symbols from the module definition and call
inst(d << e);
to replaces the input mapping for the instantiated module.
Build upon the library are a number of useful helper classes. The function synthesize()
must be called on these classes to finalise their description.
Gravel::Memory
Gravel::Memory mem(addr);
Where addr is the symbol giving the address of the memory you want to address
This creates an instantiated memory module.
Gravel::Assign( mem >> read_symbol) ;
Gravel::Assign (mem << write_symbol) ;
while
Gravel::WriteEnable(mem << write_symbol, write_enable ) ;
Adds an annotation (and an entry to the symbol map ) specifying whether to perform a write (using write_enable);
Gravel::DualMemory(c,d) is a dual port memory
Gravel::Assign ( mem[0] >> read_symbol) ;
Gravel::Assign (mem[1] << write_symbol) ;
and
Gravel::WriteEnable(mem[1] << write_symbol, write_enable)
and
Gravel::WriteEnable(mem[2] << write_symbol, write_enable)
controls the write operations.
#### State Machines ####
These are created using the class
Gravel::StateMachine