使用自定义模板的信号参数
页面进行中。 |
本文介绍了使用自定义模板获取详细信号信息的方法。建议在学习本文之前先阅读自定义模板 代码生成的文章。 |
通过基于自定义模板生成代码,可以了解信号的有用信息,如大小、数据类型、采样率和其他数据。
接下来,让我们看看自定义模板中用于了解信号信息的关键结构、字段及其用途。
例如,在模板中嵌入 $(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
- 判断类型是否为复数的标志。
那么,使用包括 signal
和 ty
的 via 端口的示例将如下所示:
/* Получение информации о типе данных и размерах первого входного сигнала */
if $(ins[1].ty.is_floating) {
// Логика для чисел с плавающей точкой
}
if $(ins[1].rows) > 1 {
// Логика для многомерного массива
}
该示例展示了如何使用 signal
和 ty
结构来获取以 ins[1]
表示的输入信号的信息。让我们考虑一下要点:
-
通过
ty
访问数据类型信息:if $(ins[1].ty.is_floating) { // Логика для чисел с плавающей точкой }
-
ty
字段包含信号数据类型的特征。 -
在这种情况下,使用
is_floating
属性,它返回一个标志(true
或`false`),表示信号是否为浮点数。 -
条件检查信号是否为
float
类型。如果是(逻辑被执行),则该逻辑专门用于浮点数处理。
-
-
通过
rows
访问信号的维数:if $(ins[1].rows) > 1 { // Логика для многомерного массива }
-
rows
属性返回信号的行数。 -
在此,我们将检查信号是否为多维数组(行数大于 1)。如果满足条件,则应用处理多维信号的逻辑。
-
在示例中,ins[1]
表示输入信号,它是 signal
结构的一个实例。有关信号的信息可通过其属性(rows
、cols
、ty
等)访问。例如,"rows "和 "cols "给出信号的尺寸,"ty "字段提供信号数据类型的详细信息(如数字、小数部分、符号性)。
必须记住,"ins "和 "outs "数组分别代表输入和输出端口。如果程序块自主生成信号(如程序块 正弦波函数 或 常数 ),则可能不需要数组。相反,可以使用内置函数或参数:
|
模板中的应用
下面的模板实现了用于 Verilog 生成的关系运算符 模块。由于 Verilog 代码生成使用 Chisel,因此模板也使用 Chisel 编写(使用 Julia 元代码)。
-
关系运算符 块的模板示例 _
//! 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)`和其他信号特征的信息。 -
输入 "和 "输出 "端口代表 "信号 "结构的实例,其属性可通过 "类型 "字段访问。
-
代码的主要任务是正确定义信号的数据类型,并根据程序块参数进行转换。