То В этом примере показано, как управлять генерацией помощника умножения, функционирует в сгенерированном коде.
В этом примере вы будете учиться:
При каких обстоятельствах эти помощники сгенерированы
Какие подходы доступны, чтобы устранить их
Следующая модель создает функции помощника для умножения, потому что область значений идеального продукта превышает область значений типа данных отдельного слова.
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 in0Hi; uint32_T in0Lo; uint32_T in1Hi; uint32_T in1Lo; uint32_T outBitsLo; 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; }
Умножение двух 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;
Следующая модель создает функции помощника для умножения, для того, чтобы реализовать насыщение.
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);
Внимание: Если при выполнении сгенерированного кода значения на сигналах превышают области значений проекта, неправильные результаты могут быть вычислены.
Можно настроить генерацию кода, заменив громоздкие операторы умножения на собственные макросы C или пользовательские функции. Можно хотеть сделать это, если, например, центральный процессор имеет ресурсы, чтобы реализовать широкое умножение более эффективно.
Ссылки:
Составьте заменяющие таблицы кода:
helpview([docroot '/ecoder/helptargets.map'], 'tfl_mapi')
Заменяющие библиотеки регистра кода:
helpview([docroot '/ecoder/helptargets.map'], 'tfl_registration')
clear ctext fid match clear ans