Engee 文档

使用自定义模板的信号参数

页面进行中。

本文介绍了使用自定义模板获取详细信号信息的方法。建议在学习本文之前先阅读自定义模板 代码生成的文章。

通过基于自定义模板生成代码,可以了解信号的有用信息,如大小、数据类型、采样率和其他数据。

接下来,让我们看看自定义模板中用于了解信号信息的关键结构、字段及其用途。

例如,在模板中嵌入 $(sprint(dump, input(1))) 后,就可以找出第一个输入信号所有字段的全部内容。

信号 "的结构

信号 "结构描述了用户自定义模板中的信号,并可通过 "类型 "字段访问所有必要参数。这些信号可以表示为 ins(输入端口)和 outs(输出端口)数组的元素,也可以表示为单独的端口,如 input(1)output(1) 。信号 "结构的以下字段可用:

  • expr::String - 常量或可配置参数的表达式,如果信号是常量或可配置参数的话;

  • full_qual_name::String - 信号的全称;

  • name::String - 信号的可读(美观)名称;

  • ieas::String - 与所选块最接近的原子子系统的名称;

  • indirect::Bool - 间接引用信号的标志;

  • rows::UInt64 - 信号的行数;

  • cols::UInt64` - 信号中的列数;

  • ty::typ - 信号类型(见下文);

  • sample_time::Float64 - 信号的采样频率。

字段 `ty

ty 字段用于 signal 结构,提供有关信号数据类型的信息。ty 字段有以下描述数据类型的关键参数:

  • bits::Int - 数据位(宽度);

  • fractional_bits::Int - 小数位数;

  • is_unsigned::Bool - 决定类型是否无符号的标志;

  • is_floating::Bool - 判断类型是否为浮点数的标志;

  • is_complex::Bool - 判断类型是否为复数的标志。

那么,使用包括 signalty 的 via 端口的示例将如下所示:

/* Получение информации о типе данных и размерах первого входного сигнала */
if $(ins[1].ty.is_floating) {
    // Логика для чисел с плавающей точкой
}

if $(ins[1].rows) > 1 {
    // Логика для многомерного массива
}

该示例展示了如何使用 signalty 结构来获取以 ins[1] 表示的输入信号的信息。让我们考虑一下要点:

  1. 通过 ty 访问数据类型信息:

    if $(ins[1].ty.is_floating) {
        // Логика для чисел с плавающей точкой
    }
    • ty 字段包含信号数据类型的特征。

    • 在这种情况下,使用 is_floating 属性,它返回一个标志(true 或`false`),表示信号是否为浮点数。

    • 条件检查信号是否为 float 类型。如果是(逻辑被执行),则该逻辑专门用于浮点数处理。

  2. 通过 rows 访问信号的维数:

    if $(ins[1].rows) > 1 {
        // Логика для многомерного массива
    }
    • rows 属性返回信号的行数。

    • 在此,我们将检查信号是否为多维数组(行数大于 1)。如果满足条件,则应用处理多维信号的逻辑。

在示例中,ins[1] 表示输入信号,它是 signal 结构的一个实例。有关信号的信息可通过其属性(rowscolsty 等)访问。例如,"rows "和 "cols "给出信号的尺寸,"ty "字段提供信号数据类型的详细信息(如数字、小数部分、符号性)。


必须记住,"ins "和 "outs "数组分别代表输入和输出端口。如果程序块自主生成信号(如程序块 正弦波函数常数 ),则可能不需要数组。相反,可以使用内置函数或参数:

//! BlockType = :Sin
//! TargetLang = :C

//! @Step
$(output_datatype_name(1)) $(output(1)) = sin($(get_baserate()) * $(model_substep(1)));

模板中的应用

下面的模板实现了用于 Verilog 生成的关系运算符 模块。由于 Verilog 代码生成使用 Chisel,因此模板也使用 Chisel 编写(使用 Julia 元代码)。

  1. 关系运算符 块的模板示例 _

//! BlockType = :RelationalOperator
//! TargetLang = :Chisel

/*!#----------------------------------------------------# */
//! @Definitions
val $(output(1)) = Wire($(show_chisel_type(output(1))))
/*!#----------------------------------------------------# */
/*!@Step
函数 patch_op(op)
    op == "==" ?"===" : op == "~=" ?"=/=" : op
结束
函数 get_idx(len, blen)
    如果 len == 1
        返回""
    elseif len == blen
        返回 "(i)"
    else
        out = "FixedPoint($(port.ty.bits).W,$(port.ty.fractional_bits).BP)"
    end
    out
end
*/
val $(output(1)) = Wire($(get_dec_type(output(1))))

/*! @Step
function get_type(port)
    if port.ty.fractional_bits == 0 && port.ty.is_unsigned == 1
        out = ".asTypeOf(UInt($(port.ty.bits).W))"
    else
        out = ".asTypeOf(FixedPoint($(port.ty.bits).W,$(port.ty.fractional_bits).BP))"
    end
    out
end
*/

$(output(1)):=$(input(1)) $(param.Operator) $(input(2))$(get_type(input(1)))

关系运算符 块的模板中,信号通过 input(1), input(2)output(1) 端口使用。类型 "字段提供了有关这些信号类型的信息。接下来,让我们分析一下代码的主要部分:

  • 定义输出信号类型:

    function show_chisel_type(x::typ) :: 字符串
      if x.bits == 1 && x.fractional_bits == 0
        out = "Bool()"
      elseif x.fractional_bits == 0
        out = (x.is_unsigned ? "U" : "S") * "Int($(x.bits).W)"
      否则
        out = "FixedPoint($(x.bits).W,$(x.fractional_bits).BP)"
        end
        out
    end
    val $(output(1)) = Wire($(get_dec_type(output(1))))

    这里的 get_dec_type 函数定义了输出信号 output(1) 的数据类型:

    • 如果信号只有 1 位且没有小数部分`(fractional_bits == 0),则其类型设为`Bool()

    • 如果信号是整数`(fractional_bits == 0),则其类型设为`UInt,并指定位数`(bits)`。

    • 在其他情况下,则假定使用定点`(FixedPoint)`,并指定数位容量和小数位数。


  • 获取输入信号的数据类型:

    function get_type(port)
        if port.ty.fractional_bits == 0 && port.ty.is_unsigned == 1
            out = ".asTypeOf(UInt($(port.ty.bits).W))"
        else
            out = ".asTypeOf(FixedPoint($(port.ty.bits).W,$(port.ty.fractional_bits).BP))"
        end
        out
    end

    该函数用于确定输入信号 input(1) 的转换类型:

    • 如果信号是整数且无符号 (is_unsigned == 1),则转换为 UInt 类型。

    • 在其他情况下,信号将转换为 FixedPoint 类型。


  • 基本块逻辑:

    $(output(1)):=$(input(1)) $(param.Operator) $(input(2))$(get_type(input(1)))

    信号比较在此进行:

    • 比较运算符 ($(param.Operator)) 通过模板参数传递。

    • 左操作数是输入信号 input(1),右操作数是 input(2)

    • 操作数的转换类型使用 get_type 函数设置。

在自定义模板的这段代码中,共有

  • ty`用于获取数字容量`(bits)、小数位数(fractional_bits)、符号性(is_unsigned)`和其他信号特征的信息。

  • 输入 "和 "输出 "端口代表 "信号 "结构的实例,其属性可通过 "类型 "字段访问。

  • 代码的主要任务是正确定义信号的数据类型,并根据程序块参数进行转换。