Помощник умножения фиксированной точки функционирует в сгенерированном коде

Этот пример показывает, как управлять генерацией функций помощника умножения в сгенерированном коде.

В этом примере вы будете учиться:

  • При каких обстоятельствах эти помощники сгенерированы

  • Какие подходы доступны, чтобы устранить их

Пример 1 - функция помощника из-за области значений Вывода

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

open_system('fxpdemo_mulhelpers_example1');
set_param('fxpdemo_mulhelpers_example1', 'SimulationCommand', 'Update');

Сгенерируйте код для модели и рассмотрите его:

evalc('slbuild(''fxpdemo_mulhelpers_example1'');'); % Suppress output
fid = fopen('fxpdemo_mulhelpers_example1_grt_rtw/fxpdemo_mulhelpers_example1.c') ; ctext = fread(fid, '*char')'; fclose(fid);

Были сгенерированы две функции помощника: mul_wide_u32 () и mul_u32_loSR ().

Ступенчатая функция вызывает внешнюю функцию помощника mul_u32_loSR ():

match = regexp(ctext, 'void fxpdemo_mulhelpers_example1_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_mulhelpers_example1_step(void)
{
  /* Product: '<Root>/MulHelper1' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  Y = mul_u32_loSR(U1, U2, 5U);
}

Внешние вызовы функции помощника внутренний помощник функционируют mul_wide_u32 ():

match = regexp(ctext, 'uint32_T mul_u32_loSR.*?\n\}', 'match'); disp(match{1});
uint32_T mul_u32_loSR(uint32_T a, uint32_T b, uint32_T aShift)
{
  uint32_T result;
  uint32_T u32_chi;
  mul_wide_u32(a, b, &u32_chi, &result);
  return u32_chi << (32U - aShift) | result >> aShift;
}

Внутренняя функция помощника mul_wide_u32 () также сгенерирована в файле:

match = regexp(ctext, 'void mul_wide_u32.*?\n\}', 'match'); disp(match{1});
void mul_wide_u32(uint32_T in0, uint32_T in1, uint32_T *ptrOutBitsHi, uint32_T
                  *ptrOutBitsLo)
{
  uint32_T outBitsLo;
  uint32_T in0Lo;
  uint32_T in0Hi;
  uint32_T in1Lo;
  uint32_T in1Hi;
  uint32_T productHiLo;
  uint32_T productLoHi;
  in0Hi = in0 >> 16U;
  in0Lo = in0 & 65535U;
  in1Hi = in1 >> 16U;
  in1Lo = in1 & 65535U;
  productHiLo = in0Hi * in1Lo;
  productLoHi = in0Lo * in1Hi;
  in0Lo *= in1Lo;
  in1Lo = 0U;
  outBitsLo = (productLoHi << 16U) + in0Lo;
  if (outBitsLo < in0Lo) {
    in1Lo = 1U;
  }

  in0Lo = outBitsLo;
  outBitsLo += productHiLo << 16U;
  if (outBitsLo < in0Lo) {
    in1Lo++;
  }

  *ptrOutBitsHi = (((productLoHi >> 16U) + (productHiLo >> 16U)) + in0Hi * in1Hi)
    + in1Lo;
  *ptrOutBitsLo = outBitsLo;
}

Почему функция помощника была сгенерирована, например, 1?

Умножение двух 32-битных чисел приводит к 64-битному идеальному результату. В example1 тип идеального результата является uint64.

Фактический выходной тип ufix32_E5 использует только биты 5 - 36 от этих 64 битов.

bits = 0:63;
ideal_product_bits = ones(1,64);
most_significant_word = [ones(1,32) NaN*ones(1,32)];
least_significant_word = [NaN*ones(1,32) ones(1,32)];
output_bits = [NaN*ones(1, 27) ones(1,32) NaN*ones(1,5)];

plot(bits, ideal_product_bits, '.r');
set(gca, 'YLim', [-1 5]);
set(gca, 'YTick', 1:3);
set(gca, 'YTickLabel', {'ideal result', 'MSB | LSB', 'output data type'});
set(gca, 'XTick', 1:64);

% "Move" interesting tick labels so they're readable and show
set(gca, 'xTickLabel', {'63','','','','','','','',  '','','','','','','','', ...
                          '','','','','','','','',  '','','','','','','32','', ...
                          '31','','','','','','','',  '','','','','','','','', ...
                          '','','','','','','','',  '','','','','','','','0'});
set(get(gca,'XLabel'),'String','Bit positions')
hold on
plot(bits, most_significant_word*2, '.b');
plot(bits, least_significant_word*2, '.m');
plot(bits, output_bits*3, '.g');
legend('ideal result', 'most significant word', 'least significant word', 'output ufix32\_E5') % Escape _ to avoid subscripting the E
plot([31.5 31.5], [0 4]); % MSB-LSB boundary
clear bits ideal_product_bits most_significant_word least_significant_word output_bits

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

Почему там две функции помощника?

Комбинация умножения двойного слова и броска закодирована в двух функциях помощника. Внутренняя функция, mul_wide_u32 () выполняет долгое умножение двух 32-битных операндов в 64-битный результат. Внешняя функция mul_u32_loSR () выполняет преобразование типа данных от сырых данных uint64 результат к желаемому типу выходных данных.

close_system('fxpdemo_mulhelpers_example1', 0);
close all;

Пример 2: помощник функционирует из-за насыщения

Следующая модель создает функции помощника для умножения в порядке реализовать насыщение.

open_system('fxpdemo_mulhelpers_example2');
set_param('fxpdemo_mulhelpers_example2', 'SimulationCommand', 'Update');

evalc('slbuild(''fxpdemo_mulhelpers_example2'');'); % Suppress output
fid = fopen('fxpdemo_mulhelpers_example2_grt_rtw/fxpdemo_mulhelpers_example2.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_mulhelpers_example2_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_mulhelpers_example2_step(void)
{
  /* Product: '<Root>/MulHelper1' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  Y = mul_us32_sat(U1, U2);
}

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

В этой модели идеальный тип может быть отрицательным, но вывод без знака. Чтобы насыщать отрицательные величины к 0, знаковый бит должен быть вычислен. Этот знаковый бит находится в старшем значащем слове идеального результата. Кодер снова генерирует двух помощников, один, чтобы вычислить необработанный 64-битный результат, и один, чтобы выполнить бросок насыщения.

close_system('fxpdemo_mulhelpers_example2', 0);

Предотвращение функций помощника путем изменения числовых свойств

Возможно постараться не генерировать помощников умножения:

  • Используя переносящееся умножение

  • Используя выходные типы, которые не превышают область значений младшего значащего слова

  • Умножение меньших типов данных с продуктом идеала отдельного слова

open_system('fxpdemo_mulhelpers_example3');
set_param('fxpdemo_mulhelpers_example3', 'SimulationCommand', 'Update');

evalc('slbuild(''fxpdemo_mulhelpers_example3'');'); % Suppress output
fid = fopen('fxpdemo_mulhelpers_example3_grt_rtw/fxpdemo_mulhelpers_example3.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_mulhelpers_example3_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_mulhelpers_example3_step(void)
{
  /* Product: '<Root>/Mul1' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  Y1 = (U1 * U2) << 3;

  /* Product: '<Root>/Mul2' incorporates:
   *  Inport: '<Root>/In3'
   *  Inport: '<Root>/In4'
   */
  Y2 = (uint16_T)(((uint32_T)U3 * U4) >> 5);
}
close_system('fxpdemo_mulhelpers_example3', 0);

Предотвращение функций помощника путем определения областей значений проекта

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

Примечание: Эта функция требует лицензии Embedded Coder.

Давайте рассмотрим модель, подобную той в примере 1:

open_system('fxpdemo_mulhelpers_example4');
set_param('fxpdemo_mulhelpers_example4', 'SimulationCommand', 'Update');

Обратите внимание на то, что мы установили флажок 'Optimize using the specified minimum and maximum values' на панели оптимизации образцового диалогового окна настройки.

get_param(bdroot, 'UseSpecifiedMinMax')
ans =

    'on'

Исследуйте ступенчатую функцию в сгенерированном коде:

evalc('slbuild(''fxpdemo_mulhelpers_example4'');'); % Suppress output
fid = fopen('fxpdemo_mulhelpers_example4_ert_rtw/fxpdemo_mulhelpers_example4.c') ; ctext = fread(fid, '*char')'; fclose(fid);
match = regexp(ctext, 'void fxpdemo_mulhelpers_example4_step.*?\n\}', 'match'); disp(match{1});
void fxpdemo_mulhelpers_example4_step(void)
{
  /* Product: '<Root>/Mul1' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   */
  Y = (U1 * U2) >> 5;
}

Область значений возможных значений идеального продукта от 0 до 500. Тип данных отдельного слова достаточен, чтобы выразить этот продукт.

close_system('fxpdemo_mulhelpers_example4', 0);

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

Предотвращение функций помощника Используя замену оператора CRL

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

Ссылки:

  • Составьте заменяющие таблицы кода:

helpview([docroot '/ecoder/helptargets.map'], 'tfl_mapi')
  • Заменяющие библиотеки регистра кода:

helpview([docroot '/ecoder/helptargets.map'], 'tfl_registration')
clear ctext fid match
clear ans