Programming languages C and Verilog describe completely different processes of algorithm operation, so a direct transfer between them is not possible. However, despite this, support for is provided.Vsyn forms a state machine in exact accordance with C code. To maximize algorithm optimization, the developer should understand the essence, necessity, and principles of forming FSM.
The generated Verilog code is a synthesizable module and can be easily integrated into any project.The module interface (input\output) is defined by arguments in functions, as well as special directives. It is recommended to use a combination of manually written modules and those generated using Vsyn. Some algorithms (typically those requiring only one clock cycle) are more convenient to represent as a standard pipeline, but for describing algorithms with multiple states or complex interactions, it is advisable to use Vsyn (examples).
Main differences from Xilinx Vivado High-Level Synthesis (HLS):
Module synthesis is based on functions. Parameters in functions are incoming signals of the synthesized module (input), and the return value of the function is the module's output signals (output). To create multiple output signals, it is advisable to use a structure in the return type of the function.
All called functions are synthesized as inline functions (no separate file will be created for them). It is also possible to use external modules (including those written in other languages), but for this, the interface must be coordinated:
When the synthesized Verilog logic cannot be represented as sequential logic, Vsyn creates a finite deterministic automaton. A Finite State Machine (FSM) is an abstract machine whose number of possible states is finite. At any given time, the machine has one current state. The current state of the automaton changes from one state to another, depending on initial conditions, logic/conditions in each state. The result of the automaton's operation is determined by its output data in the final state.
Function invocation - occurs on a positive value of START, a function can only be called when it has returned DONE. The beginning of the function corresponds to the entry point into the synthesized automaton (1st state), and the exit from the function to the final state (0th state). Transition from one state to another signifies the completion of necessary operations in the current state and the ability to continue executing further logic of the function in another state. Examples of such situations may include:
As a result, for a complete description of the function's operation, additional auxiliary signals will be synthesized:
State optimization - reducing the number of states by replacing a state reference with its contents. This allows reducing the number of intermediate states but may lead to an increase in the number of working lines.
For each function, a list of directives affecting the synthesized module is available.
Directive Name | Accepted Values | Default | Description |
---|---|---|---|
CLOCK | Variable Name | clock | Analysis and state change in this function will occur at the specified frequency |
POSEDGE | true | false | true | Works on posedge or negedge |
START | Variable Name | start | Signal to start the function logic (triggered on positive edge) |
RESET | Variable Name | reset | Signal to reset the state (reset on positive edge) |
DONE | Variable Name | done | Indicates completion of function operation |
RETURN | Variable Name | result | Name of the returned signal |
When multiple functions are detected in the code, by default, only the last function will be synthesized. Otherwise, using the TOP directive (without parameters), you can specify the name of the function for synthesis.
Pointers in the C language are used as an interface to work with the RAM.
Signal Name | Direction | Description |
---|---|---|
mem_cmd | output | Presence (=1) of a command for memory operation, (=0) - no command |
mem_is_write | output | Write (=1) or read (=0) from memory |
mem_address | output | Address (byte) for which the action is performed |
mem_size | output | Size of data being written or read |
mem_is_ready | input | Command processed. Write or read commands will occur when this signal =1 |
mem_data_in | input | Data for reading |
mem_data_out | output | Data for writing |
The maximum size of data for reading and writing (mem_data_in and mem_data_out) can be configured (default is 16 bytes). When reading/writing data larger than the size of the signals, the memory access operation will be split into iterations (in chunks of 16 bytes), required for complete reading/writing of data.
The synthesized code from C to Verilog unambiguously reflects all logical operations written in the C language. In the synthesized code, blocking operators (=) are always used because they are always synthesized as 'latches'. Further optimization is entirely dependent on the Verilog to RTL synthesizer, meaning constructions in Verilog code that may seem non-optimal at first glance. will be efficiently implemented in RTL. In general, it is recommended to optimize the C code and try to minimize the number of intermediate states in the FSM. Currently, it is possible to instruct the Vsyn compiler to automatically unroll all loops (not selectively!) to reduce intermediate states. In the future, there are plans to selectively specify the number of iterations to be unrolled for each loop.
Description | Examples |
---|---|
Remember the limitations | Limitations |
Including standard libraries is not possible (because they don't exist, but can be written manually) | include "stdio.h" or include "stdlib.h" |
Each case (default) in a switch statement must end with a break | case 0: x = 5; |
Arrays in function arguments are not pointers | int example(int x[5]) // x - array, not a pointer |
Array initialization should contain only one number\constant (without operators) | int x[123+321]; |
Functions like malloc|free and others are not available | char * x = malloc(10); |