Скремблер¶
В данном примере рассмотрены возможности верификации сгенерированного кода при помощи C-функций в Engee на примере модели скремблера.
Скремблер — это устройство или алгоритм, выполняющий обратимое преобразование цифрового потока для придания ему свойств случайной последовательности без изменения скорости передачи. В данном примере используется скремблирование с псевдослучайной бинарной последовательностью (PRBS), генерируемой LFSR длины 15 с начальным значением 100101010000000.
Далее рассмотрим реализованную схему скремблирования и дескремблирования. Она и битовое сравнение работы данного алгоритма показаны на рисунке ниже.
Запустим данную модель при помощи описанной нами функции запуска и сохраним результаты битовой ошибки.
function run_model(name_model)
Path = string(@__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
return model_output
end
@time run_model("Scrambler_descrambler")
BER = simout["Scrambler_descrambler/Error Rate Calculation.Output_1"];
BER = collect(BER)
BER[end-3:end,:]
Как мы видим, алгоритм работает корректно. Теперь перейдём к настройкам генератора кода. На скриншоте ниже видны следующие моменты. Целевая платформа выбрана как Verilog, а также отключены коментарии в сгенерирированном коде (это сделано для визуального упрощения его читабельности), и включена генерация C Function для верификации сгенерированного кода.
Теперь запустим генерацию кода и валидационной модели.
engee.generate_code(
"$(@__DIR__)/Scrambler_descrambler.engee",
"$(@__DIR__)/V_Code",
subsystem_name="Scrambler_descrambler"
)
Проведём анализ сгенерированных файлов.
Как мы можем заметить, кроме файла с кодом verilog в папке также присутствуют:
- исполняемый фал .so
- библиотечный файл .h
- файл кода .jl
Начнём с последнего. Данный файл позволяет нам сгенерировать модель, содержащую C function для сравнения с оригинальной моделью.
# This is a verification script for the Scrambler_descrambler_Scrambler_descrambler generated code.
# Run this code in order to create a verification model with a CFunction block inside that behaves like the original model.
# CFunction variables
start_code = """
Scrambler_descrambler_Scrambler_descrambler_init();"""
output_code = """
Scrambler_descrambler_Scrambler_descrambler_eval(In1,
&Out1);
"""
terminate_code = """
Scrambler_descrambler_Scrambler_descrambler_final();"""
# Close
try engee.close("Scrambler_descrambler_Scrambler_descrambler_verification";force=true) catch end
# Create
engee.create("Scrambler_descrambler_Scrambler_descrambler_verification")
# Add Blocks
engee.add_block("/Basic/Ports & Subsystems/In1", "Scrambler_descrambler_Scrambler_descrambler_verification/In1")
engee.add_block("/Basic/User-Defined Functions/C Function", "Scrambler_descrambler_Scrambler_descrambler_verification/")
engee.add_block("/Basic/Ports & Subsystems/Out1", "Scrambler_descrambler_Scrambler_descrambler_verification/Out1")
# Edit block parameters
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/In1", "PortDimensions" => "()")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/In1", "SignalType" => "real")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/In1", "OutDataTypeStr" => "Bool")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "OutputCode" => output_code, "StartCode" => start_code, "TerminateCode" => terminate_code)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "Inputs" => 1)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "Outputs" => 1)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "InputPort1Label" => "In1")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "InputPort1VarName" => "In1")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "InputPort1Type" => "bool")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "InputPort1Size" => "()")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "SampleTime" => "0.01")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "Parameters" => 0)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "OutputPort1Label" => "Out1")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "OutputPort1VarName" => "Out1")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "OutputPort1Type" => "bool")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "OutputPort1Size" => "()")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "IncludeDirectories" => "/user/my_projects/Demo/Work/scrambler_Verilog/V_Code/obj_dir")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "LibraryDirectories" => "/user/my_projects/Demo/Work/scrambler_Verilog/V_Code/obj_dir")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "Headers" => "Scrambler_descrambler_Scrambler_descrambler_cfn_api.h ")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification/C Function", "Libraries" => "libScrambler_descrambler_Scrambler_descrambler.so ")
# Edit model parameters
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification", "FixedStep" => 0.01)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification", "StartTime" => 0.0)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification", "StopTime" => 10)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_verification", "EnableMultiTasking" => false)
# Add lines
engee.add_line("Scrambler_descrambler_Scrambler_descrambler_verification", "In1/1", "C Function/1")
engee.add_line("Scrambler_descrambler_Scrambler_descrambler_verification", "C Function/1", "Out1/1")
# Save
engee.save("Scrambler_descrambler_Scrambler_descrambler_verification.engee"; force=true)
Запустим этот файл и получим блок C function, работу которого впоследствии сравним с оригинальной моделью.
По результатам выполнения сгенерированного файла .jl мы получили блок, который обращается к библиотеке и исполняемому файлу. Теперь соберём на основе этого блока несколько моделей. Начнём с модели, аналогичной исходной.
Запустим эту модель и сравним время выполнения и общее поведения модели.
@time run_model("Scrambler_descrambler_verification")
BER = simout["Scrambler_descrambler_verification/Error Rate Calculation.Output_1"];
BER = collect(BER)
BER[end-3:end,:]
Как мы можем заметить, модель работает быстрее исходной модели и, судя по BER, идентична исходной модели. Теперь давайте сравним эти блоки в общей модели.
Запустим эту модель и сравним погрешность.
run_model("Scrambler_add_verification")
err = simout["Scrambler_add_verification/err"];
println("Кол-во ошибок: $(sum(collect(err).value))")
Как мы можем видеть из результатов, блоки идентичны, и это означает, что генерация кода выполнена корректно.
Вывод¶
В данном примере мы продемонстрировали инструмент верификации генерации кода, а также успешно сгенерировали verilog-код модели скремблера.
Сам код представлен ниже.
module Scrambler_descrambler_Scrambler_descrambler(
input clock,
reset,
io_In1,
output io_Out1
);
reg UnitDelay_13_state;
reg UnitDelay_2_state;
reg UnitDelay_13_1_state;
reg UnitDelay_2_1_state;
reg UnitDelay_14_state;
reg UnitDelay_14_1_state;
reg UnitDelay_3_state;
reg UnitDelay_3_1_state;
reg UnitDelay_4_state;
reg UnitDelay_4_1_state;
reg UnitDelay_state;
reg UnitDelay_1_state;
reg UnitDelay_5_state;
reg UnitDelay_5_1_state;
reg UnitDelay_6_state;
reg UnitDelay_1_1_state;
reg UnitDelay_1_2_state;
reg UnitDelay_6_1_state;
reg UnitDelay_7_state;
reg UnitDelay_7_1_state;
reg UnitDelay_8_state;
reg UnitDelay_8_1_state;
reg UnitDelay_9_state;
reg UnitDelay_9_1_state;
reg UnitDelay_10_state;
reg UnitDelay_10_1_state;
reg UnitDelay_11_state;
reg UnitDelay_11_1_state;
reg UnitDelay_12_state;
reg UnitDelay_12_1_state;
wire LogicalOperator = UnitDelay_13_state ^ UnitDelay_14_state;
wire LogicalOperator_1 = UnitDelay_13_1_state ^ UnitDelay_14_1_state;
always @(posedge clock) begin
if (reset) begin
UnitDelay_13_state <= 1'h0;
UnitDelay_2_state <= 1'h0;
UnitDelay_13_1_state <= 1'h0;
UnitDelay_2_1_state <= 1'h0;
UnitDelay_14_state <= 1'h0;
UnitDelay_14_1_state <= 1'h0;
UnitDelay_3_state <= 1'h0;
UnitDelay_3_1_state <= 1'h0;
UnitDelay_4_state <= 1'h0;
UnitDelay_4_1_state <= 1'h0;
UnitDelay_state <= 1'h0;
UnitDelay_1_state <= 1'h0;
UnitDelay_5_state <= 1'h0;
UnitDelay_5_1_state <= 1'h0;
UnitDelay_6_state <= 1'h0;
UnitDelay_1_1_state <= 1'h0;
UnitDelay_1_2_state <= 1'h0;
UnitDelay_6_1_state <= 1'h0;
UnitDelay_7_state <= 1'h0;
UnitDelay_7_1_state <= 1'h0;
UnitDelay_8_state <= 1'h0;
UnitDelay_8_1_state <= 1'h0;
UnitDelay_9_state <= 1'h0;
UnitDelay_9_1_state <= 1'h0;
UnitDelay_10_state <= 1'h0;
UnitDelay_10_1_state <= 1'h0;
UnitDelay_11_state <= 1'h0;
UnitDelay_11_1_state <= 1'h0;
UnitDelay_12_state <= 1'h0;
UnitDelay_12_1_state <= 1'h0;
end
else begin
UnitDelay_13_state <= UnitDelay_12_state;
UnitDelay_2_state <= UnitDelay_1_1_state;
UnitDelay_13_1_state <= UnitDelay_12_1_state;
UnitDelay_2_1_state <= UnitDelay_1_2_state;
UnitDelay_14_state <= UnitDelay_13_state;
UnitDelay_14_1_state <= UnitDelay_13_1_state;
UnitDelay_3_state <= UnitDelay_2_1_state;
UnitDelay_3_1_state <= UnitDelay_2_state;
UnitDelay_4_state <= UnitDelay_3_state;
UnitDelay_4_1_state <= UnitDelay_3_1_state;
UnitDelay_state <= LogicalOperator;
UnitDelay_1_state <= LogicalOperator_1;
UnitDelay_5_state <= UnitDelay_4_1_state;
UnitDelay_5_1_state <= UnitDelay_4_state;
UnitDelay_6_state <= UnitDelay_5_1_state;
UnitDelay_1_1_state <= UnitDelay_1_state;
UnitDelay_1_2_state <= UnitDelay_state;
UnitDelay_6_1_state <= UnitDelay_5_state;
UnitDelay_7_state <= UnitDelay_6_state;
UnitDelay_7_1_state <= UnitDelay_6_1_state;
UnitDelay_8_state <= UnitDelay_7_1_state;
UnitDelay_8_1_state <= UnitDelay_7_state;
UnitDelay_9_state <= UnitDelay_8_1_state;
UnitDelay_9_1_state <= UnitDelay_8_state;
UnitDelay_10_state <= UnitDelay_9_state;
UnitDelay_10_1_state <= UnitDelay_9_1_state;
UnitDelay_11_state <= UnitDelay_10_state;
UnitDelay_11_1_state <= UnitDelay_10_1_state;
UnitDelay_12_state <= UnitDelay_11_state;
UnitDelay_12_1_state <= UnitDelay_11_1_state;
end
end // always @(posedge)
assign io_Out1 = LogicalOperator_1 ^ LogicalOperator ^ io_In1;
endmodule