Introduction

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):

About Synthesis

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:

ATTENTION: if an external function uses CLOCK | POSEDGE - it is mandatory to specify this for the synthesized function, otherwise it will not be considered as a function requiring states

Finite Deterministic Automaton (FSM)

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.

Directives

For each function, a list of directives affecting the synthesized module is available.

Directive NameAccepted ValuesDefaultDescription
CLOCKVariable NameclockAnalysis and state change in this function will occur at the specified frequency
POSEDGEtrue | falsetrueWorks on posedge or negedge
STARTVariable NamestartSignal to start the function logic (triggered on positive edge)
RESETVariable NameresetSignal to reset the state (reset on positive edge)
DONEVariable NamedoneIndicates completion of function operation
RETURNVariable NameresultName 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.

Memory Interface

Pointers in the C language are used as an interface to work with the RAM.

Signal NameDirectionDescription
mem_cmdoutputPresence (=1) of a command for memory operation, (=0) - no command
mem_is_writeoutputWrite (=1) or read (=0) from memory
mem_addressoutputAddress (byte) for which the action is performed
mem_sizeoutputSize of data being written or read
mem_is_readyinputCommand processed. Write or read commands will occur when this signal =1
mem_data_ininputData for reading
mem_data_outoutputData 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.

Optimization Questions

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.

Common Mistakes

DescriptionExamples
Remember the limitationsLimitations
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 breakcase 0: x = 5;
Arrays in function arguments are not pointersint 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 availablechar * x = malloc(10);

Supported Operations

Limitations

* Planned implementation in future versions

Author: Shchekoldin Sergey (Щеколдин Сергей)
shchekoldin@gmail.com