Working with parameters of signals for custom templates
Page in progress. |
This article describes an approach to obtaining detailed signal information using custom templates. It is recommended to read the article on custom templates code generation before studying the current one. |
By generating code based on custom templates, it is possible to learn useful information about signals such as size, data type, sampling rate, and other data.
Next, let’s look at the key structures, fields, and their use in custom templates to learn information about signals.
Structure signal
The signal
structure describes the signal in custom templates and provides access to all necessary parameters through the ty
field. These signals are represented as elements of the ins
(input ports) and outs
(output ports) arrays, or as individual ports, such as input(1)
or output(1)
. The following fields of the signal
structure are available:
-
expr :: Cstring
- the expression associated with the signal. -
qual_name :: Cstring
- the fully qualified name of the signal. -
pretty_name :: Cstring
- the readable (pretty) name of the signal. -
ieas_name :: Cstring
- the name of the atomic subsystem closest to the selected block. -
indirect :: Cuchar
- flag of indirect reference to the signal. -
rows :: Csize_t
- number of lines in the signal. -
cols :: Csize_t
- number of columns in the signal. -
bits :: Cint
- data bitness of the signal. -
fractional_bits :: Cint
- number of fractional bits. -
is_unsigned :: Cuchar
- flag determining whether the signal is unsigned. -
is_floating :: Cuchar
- flag determining whether the signal is a floating point number. -
is_complex :: Cuchar
- flag defining whether the signal is complex.
Field ty
The ty
field operates in the signal
structure and provides information about the signal data type. The ty
field has the following key parameters to describe the data type:
-
bits :: Cint
- data digitisation. -
fractional_bits :: Cint
- the number of fractional bits. -
is_unsigned :: Cuchar
- flag determining whether the type is unsigned. -
is_floating :: Cuchar
- flag determining whether the type is a floating point number. -
is_complex :: Cuchar
- flag determining whether the type is complex.
Then the example of usage via ports including signal
and ty
will look like this:
/* Получение информации о типе данных и размерах первого входного сигнала */
if $(ins[1].ty.is_floating) {
// Логика для чисел с плавающей точкой
}
if $(ins[1].rows) > 1 {
// Логика для многомерного массива
}
The example shows the use of the signal
and ty
structures to obtain information about an input signal represented as ins[1]
. Let us consider the main points:
-
Accessing data type information via
ty
:if $(ins[1].ty.is_floating) { // Логика для чисел с плавающей точкой }
-
The
ty
field contains the characteristics of the signal’s data type. -
In this case, the
is_floating
property is used, which returns a flag (true
orfalse
) indicating whether the signal is a floating point number. -
The condition checks whether the signal is of type
float
. If yes (the logic is executed), then this logic is specific to floating point number processing.
-
-
Access to the dimensionality of the signal via
rows
:if $(ins[1].rows) > 1 { // Логика для многомерного массива }
-
The
rows
property returns the number of rows in the signal. -
Here we check if the signal is a multidimensional array (the number of rows is greater than 1). If the condition is fulfilled, the logic for processing multidimensional signals is applied.
-
In the example, ins[1]
represents the input signal, which is an instance of the signal
structure. Information about the signal is accessed through its properties (rows
, cols
, ty
and others). For example, rows
and cols
give the dimensions of the signal, and the ty
field provides detailed information about the signal data type (e.g., digit, fractional part, signability).
It is important to remember that the
|
Application in templates
In custom templates, you can refer to signal properties via the ins
and outs
arrays. For example, define the output signal type data and process the input signal:
//! BlockType = :RelationalOperator
//! TargetLang = :Chisel
/*! @Definitions
function get_dec_type(port)
if port.ty.fractional_bits == 0 && port.ty.bits == 1
out = "Bool()"
elseif port.ty.fractional_bits == 0
out = "UInt($(port.ty.bits).W)"
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)))
In this template for the Relational Operator block, the signal is used via the input(1)
, input(2)
, and output(1)
ports. The ty
field provides access to information about the type of these signals. Next, let’s analyse the main parts of the code:
-
Determining the output signal type:
function get_dec_type(port) if port.ty.fractional_bits == 0 && port.ty.bits == 1 out = "Bool()" elseif port.ty.fractional_bits == 0 out = "UInt($(port.ty.bits).W)" else out = "FixedPoint($(port.ty.bits).W,$(port.ty.fractional_bits).BP)" end out end val $(output(1)) = Wire($(get_dec_type(output(1))))
Here the
get_dec_type
function defines the data type for the output signal type output(1):-
If the signal has 1 bit and no fractional part
(fractional_bits == 0)
, then its type is set asBool()
. -
If the signal is integer
(fractional_bits == 0)
, then its type is set asUInt
with the specified number of bits(bits)
. -
In other cases usage of fixed point
(FixedPoint)
with specified digit capacity and number of fractional bits is assumed.
-
-
Obtain the data type for the input signal:
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
This function determines the conversion type for the input signal
input(1)
:-
If the signal is integer and unsigned
(is_unsigned == 1)
, it is converted to UInt type. -
In other cases the signal is converted to
FixedPoint
type.
-
-
Basic block logic:
$(output(1)):=$(input(1)) $(param.Operator) $(input(2))$(get_type(input(1)))
Signal comparison is performed here:
-
The comparison operator
($(param.Operator))
is passed through the template parameters. -
The left operand is the input signal
input(1)
and the right operand isinput(2)
. -
The type of conversion for operands is set using the
get_type
function.
-
Total, in this code of the custom template:
-
ty
is used to get information about the digit capacity(bits)
, the number of fractional bits(fractional_bits)
, the signability(is_unsigned)
, and other signal characteristics. -
The
input
andoutput
ports represent instances of thesignal
structure, the properties of which are accessed through thety
field. -
The main task of the code is correct definition of data types for signals and their transformation depending on the parameters of the block.