Документация Engee

Работа с параметрами сигналов для пользовательских шаблонов

Страница в процессе разработки.

В данной статье описывается подход к получению подробной информации о сигналах с помощью пользовательских шаблонов. Рекомендуется ознакомиться со статьей по пользовательским шаблонам генерации кода прежде, чем изучать текущую.

Генерируя код на основе пользовательских шаблонов, можно узнать полезную информацию о сигналах, такую как размер, тип данных, частота выборки и другие данные.

Далее рассмотрим ключевые структуры, поля и их применение в пользовательских шаблонах для получения информации о сигналах.

Структура signal

Структура signal описывает сигнал в пользовательских шаблонах и предоставляет доступ ко всем необходимым параметрам через поле ty. Эти сигналы представляются как элементы массивов ins (входные порты) и outs (выходные порты), либо как отдельные порты, например input(1) или output(1). Доступны следующие поля структуры signal:

  • expr :: Cstring — выражение, связанное с сигналом.

  • qual_name :: Cstring — полное квалифицированное имя сигнала.

  • pretty_name :: Cstring — читаемое (красивое) имя сигнала.

  • ieas_name :: Cstring — имя атомарной подсистемы, наиболее близкой к выбранному блоку.

  • indirect :: Cuchar — флаг косвенной ссылки на сигнал.

  • rows :: Csize_t — количество строк в сигнале.

  • cols :: Csize_t — количество столбцов в сигнале.

  • bits :: Cint — разрядность данных сигнала.

  • fractional_bits :: Cint — количество дробных битов.

  • is_unsigned :: Cuchar — флаг, определяющий, является ли сигнал беззнаковым.

  • is_floating :: Cuchar — флаг, определяющий, является ли сигнал числом с плавающей точкой.

  • is_complex :: Cuchar — флаг, определяющий, является ли сигнал комплексным.

Поле ty

Поле ty работает в структуре signal и предоставляет информацию о типе данных сигнала. Поле ty имеет следующие ключевые параметры для описания типа данных:

  • bits :: Cint — разрядность данных.

  • fractional_bits :: Cint — количество дробных битов.

  • is_unsigned :: Cuchar — флаг, определяющий, является ли тип беззнаковым.

  • is_floating :: Cuchar — флаг, определяющий, является ли тип числом с плавающей точкой.

  • is_complex :: Cuchar — флаг, определяющий, является ли тип комплексным.

Тогда пример использования через порты, включающий signal и ty будет выглядеть так:

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

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

В примере показывается применение структур signal и ty для получения информации о входном сигнале, представляемом как 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. Доступ к информации о сигнале осуществляется через его свойства (rows, cols, ty и другие). Например, rows и cols дают размеры сигнала, а поле ty предоставляет детализированную информацию о типе данных сигнала (например, разрядность, наличие дробной части, знаковость).


Важно помнить, что массивы ins и outs представляют входные и выходные порты соответственно. В случае, если блок автономно генерирует сигналы (например, блоки Sin или Constant), то массивы могут быть не нужны. Вместо этого применяются встроенные функции или параметры:

  • Пример для блока Sine Wave:

    //! BlockType = :Sin
    //! TargetLang = :C
    
    //! @Step
    $(output_datatype_name(1)) $(output(1)) = sin($(get_baserate()) * $(model_substep(1)));
  • Пример кода для блока Switch:

    //! BlockType = :Switch
    //! TargetLang = :Chisel
    
    //! @Definitions
    val $(output(1)) = Wire(FixedPoint($(output(1).ty.bits).W, $(output(1).ty.fractional_bits).BP))
    
    /*! @Step
    function get_operator()
        param.Criteria == "u2 > Threshold" ? "$(input(2)) > $(param.Threshold).U" : "$(input(2)) =/= 0.U"
    end
    function get_number_type(s::String)
        out = ".asTypeOf(FixedPoint($(output(1).ty.bits).W, $(output(1).ty.fractional_bits).BP))"
    end
    */
    when($(get_operator())) {
        $(output(1)) := $(input(1))$(get_number_type(input(1).full_qual_name))
    }
    .otherwise {
        $(output(1)) := $(input(3))$(get_number_type(input(3).full_qual_name))
    }

Применение в шаблонах

В пользовательских шаблонах можно обращаться к свойствам сигналов через массивы ins и outs. Например, определить тип данных выходного сигнала и обработать входной:

//! 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)))

В этом шаблоне для блока Relational Operator сигнал используется через порты input(1), input(2) и output(1). Поле ty обеспечивает доступ к информации о типе данных сигналов. Далее разберем основные части кода:

  • Определение типа выходного сигнала:

    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))))

    Здесь функция get_dec_type определяет тип данных для выходного сигнала output(1):

    • Если сигнал имеет 1 бит и не содержит дробной части (fractional_bits == 0), то его тип задается как ё.

    • Если сигнал целочисленный (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) и других характеристиках сигнала.

  • Порты input и output представляют собой экземпляры структуры signal, доступ к свойствам которой осуществляется через поле ty.

  • Основная задача кода — корректное определение типов данных для сигналов и их преобразование в зависимости от параметров блока.