Verilog generation for 4-FSK modulator¶
Here we will look at working with 4-FSK (Frequency Shift Keying) in Engee.
Frequency modulation is a type of modulation in which information is encoded by changing the frequency of a signal. 4-FSK, Four Level Frequency Shift Keying, is the type of modulation used in DMR (Digital Mobile Radio) and is optimal for use in PMR (Professional Mobile Radio) systems.
We will also generate Verilog code from this model and verify that it works in Vivado.
Verilog is a hardware description language used to develop electronic systems.
Verilog is needed in the design, verification and implementation of analogue, digital and mixed electronic systems at different levels of abstraction.
Let's declare the auxiliary functions¶
function run_model( name_model)
Path = (@__DIR__) * "/" * name_model * ".engee"
if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
model = engee.open( name_model ) # Открыть модель
model_output = engee.run( model, verbose=true ); # Запустить модель
else
model = engee.load( Path, force=true ) # Загрузить модель
model_output = engee.run( model, verbose=true ); # Запустить модель
engee.close( name_model, force=true ); # Закрыть модель
end
sleep(0.01)
return model_output
end
Analysing the model¶
We study two variants of the model. One uses standard selection logic implemented by switching. The second variant of the block is implemented using a mathematical formula. Such methods are often used to change algorithms beyond recognition when developing systems in order to optimise their performance in terms of speed or resources.
Below is the table on the basis of which the model was developed.
symbol = [-3, -1, 1, 3]
bits = [[0, 0], [0, 1], [1, 0], [1, 1]]
println(join(["bits: $bit, symbol: $f" for (f, bit) in zip(symbol, bits)], "\n"))
The screenshots below show the developed model.
Source block 4-FSK.
The block implemented using the formula, as we can see, has much less logic than the original block. Besides, all multiplication blocks in it use multiplication by 2, and, accordingly, when generating the code, such logic will represent a shift by one bit.
We can also notice that this case uses shorter data types than the original block where Int8 was used.
Let's briefly touch upon the topic of fixed-point data types. This data type is specified by the command fi(X, 1, 16, 5), where from left to right the parameters are:
- number values;
- sign (1-sign, 0-unsigned);
- the full bit size of the word;
- the size of the fractional part.
Next, let's consider a simple example.
x = fi(7.5, 1, 7, 5)
y = fi(7.5, 1, 7, 3)
println("x: $x")
println("y: $y")
As we can see, in the first case the number 7.5 overflowed.
x+y
We can also see that when adding these two numbers, more memory is allocated for them than was originally allocated.
Checking the performance of the model¶
Now let's analyse the consistency of the two implementations with each other. First of all, let's run the model.
bit_1 = 1; bit_2 = 1;
println("Inp_bit: $([bit_1, bit_2])")
println()
@time run_model("FSK_V") # Запуск модели.
Now let's compare the results. As we can see, both results correspond to the initial table.
Symbol_math = collect(Symbol_sim).value[end]
println("Symbol_math: $Symbol_math")
Symbol_switch = collect(Symbol_sim_switch).value[end]
println("Symbol_switch: $Symbol_switch")
To verify the final project, we can represent the block from which we are going to generate the code in the form of a formula. Let's make sure that the formula is identical to the model.
Symbol_ref = 2 * (2 * bit_1 + bit_2) - 3
println("Symbol_ref: $Symbol_ref")
println("Symbol_sim: $Symbol_math")
Let's perform code generation from the 4-FSK modulator block¶
Let's start with the command for code generation. Below is information about the possibilities of using the generator.
? engee.generate_code
Now let's set the target platform in the model.
Let's perform code generation. Since the target platform is explicitly set in the model settings, we won't need the targeting string.
engee.generate_code(
"$(@__DIR__)/FSK_V.engee",
"$(@__DIR__)/V_Code",
subsystem_name="4-FSK modulator math",
# target="verilog"
)
Working with Vivado¶
Now let's test the obtained code in Vivado and download the obtained files.
Let's create an empty project.
Let's add the generated file.
Let's define the target platform for our project.
Now we can look at the final schematic of our project. It turned out to be very simple.
Let us synthesise and implement the project. As we can see, the timings are not defined. This is due to the fact that the input ports of our block are empty, nothing is fed to them.
We can verify this by looking at the simulation results as well. All inputs and outputs are undefined.
Let's fix this and add pipelining to our block by setting the input ports as constants.
Now let's repeat the simulation.
The result of the simulation may seem incorrect, but let's analyse the generated logic point by point, provided that a pair of bits [0,1] is input. Let's start by analysing the results using the formula we have developed.
Symbol_ref = 2*(2*0+1)-3 #[0,1]
println("Ожидаемый результат: $Symbol_ref")
Now let's move on to our code:
(io_Symbol = {{1'h0, io_Bit_1, 1'h0} + {2'h0, io_Bit_2}, 1'h0} - 4'h3)
- {1'h0, 0, 1'h0}: 000.
- {2'h0, 1}: 001
- {0,0,0} + {0,0,1}: 001
- {001, 0}: 0010
- 4'h3: 0011
Now let's move on to the answer. If we take bitwise subtraction, the result is: [1111].
- 0010 - 0011 = -1
- *Take the modulus: 1: 0001.
- Invert the bits: 0001: 1110.
- Add 1: 1110 + 1: 1111
Based on the above theses, we can say that our simplified implementation of the 4-FSK modulator works correctly.
Conclusion¶
In this example we have analysed the possibilities of Verilog code generation and verification in Engee, we have seen that this approach to FPGA system development is applicable and relevant. Moreover, it can significantly speed up the development process due to the ability to instantly edit and test the model.