Scrambler¶
在本示例中,我们将以扰频器模型为例,探讨使用 Engee 中的 C 函数验证生成代码的可能性。
加扰器是一种对数字流进行可逆变换的设备或算法,在不改变比特率的情况下使其具有随机序列的特性。本示例使用由长度为 15、初始值为 100101010000000 的 LFSR 生成的伪随机二进制序列 (PRBS) 进行加扰。
接下来,我们考虑已实施的加扰和解扰方案。下图显示了该算法的运行情况和比特比较。
让我们使用我们描述的运行函数运行这个模型,并保存比特误差结果。
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 函数生成来验证生成的代码。
现在让我们运行代码生成和验证模型。
engee.generate_code(
"$(@__DIR__)/Scrambler_descrambler.engee",
"$(@__DIR__)/V_Code",
subsystem_name="Scrambler_descrambler"
)
让我们分析一下生成的文件。
我们可以看到,除了 verilog 代码文件外,文件夹中还包括
- 可执行文件 .so
- 库文件 .h
- .jl 代码文件
让我们从最后一个开始。该文件允许我们生成一个包含 C 函数的模型,以便与原始模型进行比较。
# 这是 Scrambler_descrambler_Scrambler_descrambler 生成代码的验证脚本。
# 运行此代码可创建一个内含 CFunction 块的验证模型,其行为与原始模型类似。
# CFunction 变量
start_code = """
Scrambler_descrambler_Scrambler_descrambler_init();"""""
output_code = """
Scrambler_descrambler_Scrambler_descrambler_eval(In1、
&Out1);
"""
terminate_code = """
Scrambler_descrambler_Scrambler_descrambler_final();""""
# 关闭
try engee.close("Scrambler_descrambler_Scrambler_descrambler_verification";force=true) catch end
# 创建
engee.create("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification")
# 添加块
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")
# 编辑程序块参数
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_descrambler_verification/C 功能","输出" => 1)
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification/C Function", "InputPort1Label" => "In1")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_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 功能","参数" => 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_descrambler_verification/C Function","IncludeDirectories" => "/user/my_projects/Demo/Work/scrambler_Verilog/V_Code/obj_dir")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification/C 函数", "LibraryDirectories" => "/user/my_projects/Demo/Work/scrambler_Verilog/V_Code/obj_dir")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification/C 函数", "Headers" => "Scrambler_descrambler_Scrambler_descrambler_cfn_api.h ")
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification/C Function","Libraries" => "libScrambler_descrambler_Scrambler_Scrambler_descrambler.so ")
# 编辑模型参数
engee.set_param!("Scrambler_descrambler_Scrambler_descrambler_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)
# 添加行
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")
# 保存
engee.save("Scrambler_descrambler_Scrambler_descrambler_descrambler_verification.engee"; force=true)
让我们运行该文件并获取 C 功能块,稍后我们将把其操作与原始模型进行比较。
根据生成的 .jl 文件的执行结果,我们得到了一个访问库和可执行文件的程序块。现在,让我们根据这个程序块建立几个模型。让我们从一个与初始模型类似的模型开始。
让我们运行这个模型,比较一下模型的执行时间和整体表现。
@time run_model("Scrambler_descrambler_verification")
BER = simout["Scrambler_descrambler_verification/Error Rate Calculation.Output_1"];
BER = collect(BER)
BER[end-3:end,:]
我们可以看到,该模型的运行速度快于原始模型,而且从误码率来看,与原始模型完全相同。现在让我们比较一下整体模型中的这些区块。
让我们运行这个模型,比较一下误差。
run_model("Scrambler_add_verification")
err = simout["Scrambler_add_verification/err"];
println("Кол-во ошибок: $(sum(collect(err).value))")
从结果中我们可以看到,区块是相同的,这说明代码生成是正确的。
结论¶
在本例中,我们演示了代码生成验证工具,并成功生成了扰频器模型的 verilog 代码。
代码本身如下所示。
模块 Scrambler_descrambler_Scrambler_descrambler(
输入时钟
复位、
io_In1、
输出 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;
注册 UnitDelay_3_state;
reg UnitDelay_3_1_state;
reg UnitDelay_4_state;
reg UnitDelay_4_1_state;
reg UnitDelay_state;
注册 UnitDelay_1_state;
注册 UnitDelay_5_state;
reg UnitDelay_5_1_state;
注册 UnitDelay_6_state;
注册 UnitDelay_1_1_state;
注册 UnitDelay_6_state; 注册 UnitDelay_1_1_state; 注册 UnitDelay_1_2_state;
注册 UnitDelay_5_1_state; 注册 UnitDelay_5_1_state
注册 UnitDelay_7_state;
注册 UnitDelay_7_1_state;
注册 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;
注册 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;
结束
否则开始
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 // always @(posedge)
赋值 io_Out1 = LogicalOperator_1 ^ LogicalOperator ^ io_In1;
结束模块