Engee 文档
Notebook

Scrambler

在本示例中,我们将以扰频器模型为例,探讨使用 Engee 中的 C 函数验证生成代码的可能性。

加扰器是一种对数字流进行可逆变换的设备或算法,在不改变比特率的情况下使其具有随机序列的特性。本示例使用由长度为 15、初始值为 100101010000000 的 LFSR 生成的伪随机二进制序列 (PRBS) 进行加扰。

接下来,我们考虑已实施的加扰和解扰方案。下图显示了该算法的运行情况和比特比较。

image_3.png

让我们使用我们描述的运行函数运行这个模型,并保存比特误差结果。

In [ ]:
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
Out[0]:
run_model (generic function with 1 method)
In [ ]:
@time run_model("Scrambler_descrambler")
BER = simout["Scrambler_descrambler/Error Rate Calculation.Output_1"];
BER = collect(BER)
BER[end-3:end,:]
Building...
Progress 0%
Progress 18%
Progress 100%
Progress 100%
 10.704403 seconds (527.95 k allocations: 38.180 MiB, 5.61% compilation time)
Out[0]:
4×2 DataFrame
Rowtimevalue
Float64Array…
19.97[0.0, 0.0, 998.0]
29.98[0.0, 0.0, 999.0]
39.99[0.0, 0.0, 1000.0]
410.0[0.0, 0.0, 1001.0]

我们可以看到,算法运行正常。现在我们来看看代码生成器的设置。下面的截图显示了以下几点。目标平台选择为 Verilog,同时禁用生成代码中的注释(这样做是为了从视觉上简化代码的可读性),并启用 C 函数生成来验证生成的代码。 image.png

现在让我们运行代码生成和验证模型。

In [ ]:
engee.generate_code(
"$(@__DIR__)/Scrambler_descrambler.engee",
"$(@__DIR__)/V_Code",
subsystem_name="Scrambler_descrambler"
)
[ Info: Generated code and artifacts: /user/start/examples/codegen/scrambler_Verilog/V_Code

让我们分析一下生成的文件。 image.png 我们可以看到,除了 verilog 代码文件外,文件夹中还包括

  1. 可执行文件 .so
  2. 库文件 .h
  3. .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 功能块,稍后我们将把其操作与原始模型进行比较。

image_2.png

根据生成的 .jl 文件的执行结果,我们得到了一个访问库和可执行文件的程序块。现在,让我们根据这个程序块建立几个模型。让我们从一个与初始模型类似的模型开始。

image_3.png

让我们运行这个模型,比较一下模型的执行时间和整体表现。

In [ ]:
@time run_model("Scrambler_descrambler_verification")
BER = simout["Scrambler_descrambler_verification/Error Rate Calculation.Output_1"];
BER = collect(BER)
BER[end-3:end,:]
Building...
Progress 0%
Progress 18%
Progress 99%
Progress 100%
  5.424469 seconds (205.50 k allocations: 15.873 MiB)
Out[0]:
4×2 DataFrame
Rowtimevalue
Float64Array…
19.97[0.0, 0.0, 998.0]
29.98[0.0, 0.0, 999.0]
39.99[0.0, 0.0, 1000.0]
410.0[0.0, 0.0, 1001.0]

我们可以看到,该模型的运行速度快于原始模型,而且从误码率来看,与原始模型完全相同。现在让我们比较一下整体模型中的这些区块。 image.png

让我们运行这个模型,比较一下误差。

In [ ]:
run_model("Scrambler_add_verification")
err = simout["Scrambler_add_verification/err"];
println("Кол-во ошибок: $(sum(collect(err).value))")
Building...
Progress 0%
Progress 22%
Progress 100%
Progress 100%
Кол-во ошибок: 0

从结果中我们可以看到,区块是相同的,这说明代码生成是正确的。

结论

在本例中,我们演示了代码生成验证工具,并成功生成了扰频器模型的 verilog 代码。

image.png 代码本身如下所示。

模块 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
结束模块

示例中使用的块