Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос С
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3
zltigo
QUOTE (ViKo @ Jun 26 2010, 13:24) *
Для всех ядер - это вы уж слишком многого от меня хотите. smile.gif У меня и компиляторов таких нет.

Тем не менее, Вы уже второй раз утверждаете, что писали с оглядкой на Cortex? Лично я воспринял это, как то, что Вы знаете, что творите.
QUOTE
из ваших высказываний так и не понял, что бы такого можно было улучшить в моем коде.

Хорошо,не затрагивая, так сказать основ, только то, что сразу режет глаз.
CODE
void si16toad (int16_t Number, char * StrBuf)
{
  char Sign = ' '; // Зачем-то завели малополезную переменную 'Sign'
  if (Number > 0) Sign = '+';
  if (Number < 0) {
    Sign = '-';
    Number = -Number;
  }
  StrBuf[6] = '\0';
  signed char i = 5; // Cortex говорите? Тогда за не 32 bit переменные, где в этом нет
// небходимости по рукам надо давать. Да и сама переменная лишняя - только команд push/pop добавляет
// А за использование "массивов" вместо указателей - еще один раз
  do {
    StrBuf[i--] = Number % 10 + '0';
    Number /= 10; // 32 bit контроллер? Тогда зачем его беднягу опять без всякой надобности
// заставлять с 16bit 'Number' работать? Сразу несколько лишних команд в цикле
  } while (Number);
  StrBuf[i] = Sign;
// Цикл заполнения пробелами не более, чем 4x ,байтиков. А как это на 32битниках, тем более на
// Cortex это можно сделать одной командой?( ну ладно двумя - одна регистр пробелами заполняет)
  for (i--; i >= 0; i--) StrBuf[i] = ' ';
}

ssvSerge
Цитата(ViKo @ Jun 26 2010, 18:42) *
для меня оптимальность = Компактность кода. бывает, что компактный код и работает быстро.
о - вот теперь всё понятно. табличные методы в таких условиях, конечно, проигрывают.

я хотел сказатать только, что таблицу можно сделать на базе "2 в степени" и заниматься
BCD сложением. Значительно компактнее, чем десятичная таблица, и реализация на ASM
проста до смешного. Хотя в скорости, конечно, уступает десятичной.

Сергей.
aaarrr
Цитата(ViKo @ Jun 26 2010, 18:42) *
В данный момент меня занимает алгоритм от aaarrr, поискал по компу своему книжку по цифровые трюки, но не нашел. А ведь была. Нельзя ли его расширить, чтобы принимал все числа.

Да нет там никаких трюков, кроме обычной арифметики smile.gif Первым умножением число переводится в представление 4.28, дальше все понятно.
Расширить в каком направлении?
ViKo
Цитата(zltigo @ Jun 26 2010, 18:05) *
// Зачем-то завели малополезную переменную 'Sign'
// Cortex говорите? Тогда за не 32 bit переменные, где в этом нет
// небходимости по рукам надо давать. Да и сама переменная лишняя - только команд ush/pop добавляет
// А за использование "массивов" вместо указателей - еще один раз
// 32 bit контроллер? Тогда зачем его беднягу опять без всякой надобности
// заставлять с 16bit 'Number' работать? Сразу несколько лишних команд в цикле
// Цикл заполнения пробелами не более, чем 4x ,байтиков. А как это на 32битниках, тем более на
// Cortex это можно сделать одной командой?( ну ладно двумя - одна регистр пробелами заполняет)

Sign - а как же без него, он же потом используется, в пока не известном месте.
32 бита - согласен. Согласен понести наказание (вернее, уже понес smile.gif)
push/pop - разве они там есть?
Массивы вместо указателей - не уверен, не исключаю что в данном случае это одно и то же.
Заполнение пробелами - их может быть разное количество, здесь 32-битовые слова не помогут. Над этим подумаю...

Докладываю - создал тестовый проект, в котором только itoa, компилятор задействовал SDIV. Возрадуемся, братья! smile.gif

2 aaarrr
Про формат 4.28 - что это, где почитать?
zltigo
QUOTE (ViKo @ Jun 26 2010, 19:28) *
Sign - а как же без него, он же потом используется, в пока не известном месте.

Можно с большей пользой использовать регистр, например, взять и скопировать в него Ваш 'Number'. При этом
будете работать с этим 32bit, а не 16ише, а плюсики и прочее рисовать потом по 'Number'
QUOTE
push/pop - разве они там есть?

Напихаете разных переменных - будут.
QUOTE
Массивы вместо указателей - не уверен

Ну-ну... Две переменных, вместо одной.
QUOTE
Заполнение пробелами - их может быть разное количество, здесь 32-битовые слова не помогут.

Помогут, помогут - заполняйте до того, как начнете цифирки заносить.


QUOTE (ViKo @ Jun 26 2010, 19:28) *
Возрадуемся, братья! smile.gif

Чему?
aaarrr
Цитата(ViKo @ Jun 26 2010, 20:28) *
2 aaarrr
Про формат 4.28 - что это, где почитать?

Не надо про него читать, просто 4 старших бита - целая часть, остальные - дробная. Довольно часто используется в виде 1.31 или 1.15
ViKo
Спасибо всем! На сегодня и завтра - умолкаю. "Работа над ошибками".
Возрадуемся - что в Cortex есть команда деления, которая иногда используется.
sonycman
Цитата(ViKo @ Jun 26 2010, 21:00) *
Возрадуемся - что в Cortex есть команда деления, которая иногда используется.

Ещё как используется.
На днях посмотрел, для интереса, как скомпилировались операции (dword / 10) и, следом за ней, (dword % 10).
В первом случае, естественно, UDIV.
А во втором - MLS (Multiply and Subtract) с использованием результата предыдущего вычисления.
Есть такая хитрая и полезная (как раз для этих целей) команда smile.gif

Так что даже не пришлось делать вычитание ручками, RealView сам всё оптимизирует правильно.
demiurg_spb
Цитата(ReAl @ Jun 26 2010, 13:04) *
Так что применение div и тут в два раза сокращает затраты времени на деление по сравнению с раздельной парой /, %. Оптимизатор сам не видит, что можно было бы вызвать еление один раз.
Я видел заплатку для этого случая. Сейчас gcc ИМХО это видит:-)
To ViKo:
Поделитесь насколько itoa будет медленнее Вашего самого лучшего варианта:-)
badik
Господа всем огромный привет, ни как не думал, что моя маленькая проблема вызовет такой мощный отклик. Вот уж точно 100 друзей намного лучше..
Тут уважаемые "Местный" и "воинствующий философ" подсказали простое решение sprintf, посмотрел С Шилдта с примером, у меня всё идеальо сработало.
Если не затруднил - осмелюсь ещё поспрашать столь почтенное сообщество. Я в начале ADSP-BF533, BF548



ViKo
Прежде, чем писать новое, изучил в отладчике работу обеих моих программ - начальной si16toad и измененной itoa, в которой операции % и / были заменены вызовом библиотечной функции div. Напомню: Keil uVision - RealView MDK-ARM 4.10, STM32F103. Результаты оказались интересными.

После компиляции в окне Build Ouitput для обеих программ выдаются одинаковые размеры для кода - 548 байтов при оптимизации O0 и 536 байтов при оптимизации O3. Почему они одинаковые, не понимаю (см. ниже)?! Размеры данных всех типов тоже одинаковые вообще всегда, но это, как раз, не удивляет.

Посчитал размер обеих функций по листингу C компилятора (есть галочка в настройках генерировать листинг). При O0 для si16toad насчитал 84 байта, для itoa 98 байтов (не считая 14 байтов в самой функции div, это уже в отладчике увидел). При O3 - 80 байтов и 94 байта, соответственно. Причем, при оптимизации O0 в si16toad команда деления использовалась дважды, а при O3 только один раз. В-общем, мой первый вариант оказался компактнее.

Посчитал в отладчике количество тактов. Счетчик тактов виден в окне регистров, засекал значение перед вызовом своей функции и после нее. При O0 si16toad выполнялась за 171 такт, itoa за 232 такта. При O3 - 121 такт и 210 тактов, соответственно. Мой первый вариант оказался еще и быстрее.

Увидел лишние знаковые и беззнаковые расширения для переменных меньше 32 байтов. Вот здесь буду совершенствовать программу. Массив или указатель - тоже проверю. Заносить пробелы сразу - их, к сожалению, максимум 5 (не 4). Над этим и др. пока думаю.


zltigo
QUOTE (ViKo @ Jun 29 2010, 00:09) *
Заносить пробелы сразу - их, к сожалению, максимум 5 (не 4). Над этим и др. пока думаю.

Их у Вас четыре. Можете попробовать на пальцах посчитать от X0 (раз-два) до X32768(раз-два-..шесть). Ну и размер должен быть на на уровне 60 байт, ну и тактов заметно менее.


ViKo
Цитата(zltigo @ Jun 29 2010, 00:33) *
Их у Вас четыре. Можете попробовать на пальцах посчитать от X0 (раз-два) до X32768(раз-два-..шесть). Ну и размер должен быть на на уровне 60 байт, ну и тактов заметно менее.

Перед "0" я символ + или - не ставлю (считаю, так "красивее" и "правильнее"), потому и обработка такая в начале программ. Итого _ _ _ _ _ 0 \0.
По поводу размеров и тактов - могу выдать весь проект в заархивированном виде.
В настройках есть какие-то "галочки", которых не трогал. Может, что-то и упустил...
zltigo
QUOTE (ViKo @ Jun 29 2010, 00:57) *
Перед "0" я символ + или - не ставлю

Вы ставите один из 3x символов. Вот и ставьте. Таки 4 smile.gif
QUOTE
По поводу размеров и тактов - могу выдать весь проект в заархивированном виде.

Я говорю об аккуратно написанном, посему про 80 байтов в Вашем варианте верю. Сделайте 60 smile.gif.
ViKo
2 zltigo
Непременно. smile.gif
Выставил две "галки" - Use Cross-Module Optimization и Use MicroLIB. Общий размер кода сократился до 212 и 324 байтов для первой и второй программ. Причем, такой размер получается со второго раза компиляции. "Все чудесатее и чудесатее." Что эти параметры делают? А на конкретный размер и состав кода пока не смотрел.
ViKo
Код
void  itoad(int number, uint8_t *string)
{
  uint8_t  sign;
  *(int32_t *) string =       ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24;
  *(int32_t *)(string + 4) =  ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24;  
  *(int32_t *)(string += 8) = ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24;
  if (!number) return;
  if (number > 0) sign = '+';
  else {
    number = -number;
    sign = '-';
  }
  string += 2;
  do {
    *string-- = number % 10 + '0';
  } while (number /= 10);
  *string = sign;
}

Работает с 32-битовыми числами со знаком.
string должна быть 12 байтов для 32-битового числа.
60 байтов (+ 4 байта хранят константу "_ _ 0").
~207 тактов.
Сергей Борщ
Цитата(ViKo @ Jun 29 2010, 16:48) *
Код
*(int32_t *) string =
Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.
ViKo
Цитата(Сергей Борщ @ Jun 29 2010, 17:18) *
Знатная грабля

А для Cortex-M3? А как надо по вашему мнению?
zltigo
QUOTE (Сергей Борщ @ Jun 29 2010, 17:18) *
Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.

Это гнулось под Cortex - такая вот игра.
QUOTE (ViKo @ Jun 29 2010, 16:48) *
60 байтов

Чуть симпатичнее и скорее всего еще короче:
CODE
void  itoad(int number, uint8_t *string)
{
  uint8_t  sign;
  *(uint32_t *) string =       '    ';
  *(uint32_t *)(string + 4) =  '    ';  
  *(uint32_t *)(string += 10) = (uint32_t )"  0";
  if (!number) return;
  if (number > 0) sign = '+';
  else {
    number = -number;
    sign = '-';
  }
//  string += 2;
  do {
    *string-- = number % 10 + '0';
  } while (number /= 10);
  *string = sign;
}

Осталось первоначальную 16bit оптимизировать.
ViKo
Цитата(zltigo @ Jun 29 2010, 17:34) *
*(uint32_t *) string = ' ';
*(uint32_t *)(string + 4) = ' ';
Осталось первоначальную 16bit оптимизировать.

Кавычки не двойные?
Из этой 16-битов автоматически получается, если малое число использовать и буфер соответствующий.
zltigo
QUOTE (ViKo @ Jun 29 2010, 17:39) *
Кавычки не двойные?

В первых двух - нет. Возможны warnings, правда, поскольку символ wide получается ИЗ 4x ПРОБЕЛОВ. А так нормально. В третьей - три символа в двойных.
QUOTE
Из этой 16-битов автоматически получается, если малое число использовать и буфер соответствующий.

Автоматически, не значит оптимально.
ViKo
Цитата(zltigo @ Jun 29 2010, 17:34) *
Код
  *(uint32_t *)(string += 10) = (uint32_t )"  0";

Так - нельзя, пропускается два байта.
С кавычками - понял, но варнинги... как бы удовлетворить требованиям компилятора?
Код
#define  FOUR_SPACES  0x20202020
*(uint32_t *) string = FOUR_SPACES;

Нормально?
zltigo
QUOTE (ViKo @ Jun 29 2010, 20:23) *
Так - нельзя, пропускается два байта.

А, да. Что-то ошибся.
Тогда так:
CODE
  *(uint32_t *)(string += sizeof(int32_t)) =  '    ';  
  *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )"  0";
  string += 2;

Есть шанс на экономию пары байт.

QUOTE
С кавычками - понятно, но варнинги... как бы удовлетворить требованиям компилятора?

Ну, например, отключить их локально прагмой, либо таки (long)" ", но константа займет 8 байт.



QUOTE (ViKo @ Jun 29 2010, 20:23) *
Нормально?

Да.
ViKo
Цитата(zltigo @ Jun 29 2010, 20:40) *
Код
  *(uint32_t *)(string += sizeof(int32_t)) =  '    ';  
  *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )"  0";
  string += 2;

Есть шанс на экономию пары байт.

В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель? А, заменить +8 +2 на +4 +4 +2?
upd. Попробовал и так, и сяк, и +10, лучше не становится.

16-битовую хочу попробовать с применением формата 4.28, как у aaarrr. А с тем, что сделал для 32 битов, и не знаю, куда уж дальше "копать" для 16 битов. Я, собственно, с 16-битовой и возился, пока не увидел, что 32-битовая из нее получается практически "даром":)
zltigo
QUOTE (ViKo @ Jun 29 2010, 21:29) *
В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель?

Вот как написано, так пробуйте.
QUOTE
что 32-битовая из нее получается практически "даром":)

Полагаю, что там есть как минимум один нюанс - не ухудшить шестнадцатибитовостью ну и чуть поджать за счет меньшего буфера.
ViKo
Цитата(zltigo @ Jun 29 2010, 21:38) *
Вот как написано, так пробуйте.

Во всех (!) перечисленнных вариантах делается одно и то же: +8 +2
Код
;;;34       *(uint32_t *)(string += sizeof(int32_t)) =  '    ';  
000006  600a              STR      r2,[r1,#0]
;;;35       *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )"  0";
000008  604a              STR      r2,[r1,#4]
00000a  a23b              ADR      r2,|L1.248|
00000c  f8412f08          STR      r2,[r1,#8]!
;;;36       string += 2;
000010  1c89              ADDS     r1,r1,#2
;;;37
zltigo
QUOTE (ViKo @ Jun 29 2010, 22:52) *
Во всех (!) перечисленнных вариантах делается одно и то же: +8 +2
CODE
;;;34       *(uint32_t *)(string += sizeof(int32_t)) =  '    ';  
000006  600a              STR      r2,[r1,#0]
;;;35       *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )"  0";
000008  604a              STR      r2,[r1,#4]
00000a  a23b              ADR      r2,|L1.248|
00000c  f8412f08          STR      r2,[r1,#8]!
;;;36       string += 2;
000010  1c89              ADDS     r1,r1,#2
;;;37

Выложите-ка просто целиком и без редактирования ДВА листинга, как у Вас было и как я предложил. Тогда будет видно.
Пока "идеальный варинат" этого кусочка мог-бы быть такой:
CODE
STR      r2,[r1,#0]
STR      r2,[r1,#4]
ADR      r2,......
STR      r2,[r1,#8]
ADDS     r1,r1,#10

Все команды по 16бит и на два байта меньше относительно приведенного выше варианта.
Но компилятору чего-то у уму заклинило sad.gif
А что будет если так:
CODE
*(uint32_t *)(string + 4) =  '    ';  
  *(uint32_t *)(string + 8 ) = (uint32_t )"  0";
  string += 10;



P.S.
Компильнул IAR-овским компилятором (слега еще подправив,но в общем, как в 73 посте) все, как задумывалось получилось и 54 байта размер кода.
ViKo
Выкладываю ваш вариант.
Последнее, что вы написали, тоже делал.
Пара вопросов, возникших в процессе... -
1. Можно ли "заинлайнить" библиотечную функцию, ту же div, например?
2. Есть ли способ задать массив, выровненный по 4-байтовой границе?

upd.
Вах, получилось!
Код
void  itoad(int number, uint8_t *string)
{
  #define  FOUR_SPACES  ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24
  uint8_t  sign;
  
  *(uint32_t *)(string) = FOUR_SPACES;
  *(uint32_t *)(string + 4) = FOUR_SPACES;    
  *(uint32_t *)(string + 8) = (uint32_t)"  0";
  string += 10;
//  *(uint32_t *)(string += sizeof(int32_t)) =  '    ';  
//  *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )"  0";
//  string += 2;
      
  if (!number) return;
  if (number > 0) sign = '+';
  else {
    number = -number;
    sign = '-';
  }
  do {
    *string-- = number % 10 + '0';
  } while (number /= 10);
  *string = sign;
}

58 байтов
Код
;;;31       *(uint32_t *)(string) = FOUR_SPACES;
000002  f04f3220          MOV      r2,#0x20202020
;;;32       *(uint32_t *)(string + 4) = FOUR_SPACES;    
000006  600a              STR      r2,[r1,#0]
;;;33       *(uint32_t *)(string + 8) = (uint32_t)"  0";
000008  604a              STR      r2,[r1,#4]
00000a  a23a              ADR      r2,|L1.244|
;;;34       string += 10;
00000c  608a              STR      r2,[r1,#8]
00000e  310a              ADDS     r1,r1,#0xa

Вроде уже делал так.
ViKo
"Шеф, все пропало!..."
По команде *(uint32_t *)(string + 8) = (uint32_t)" 0";
заносится адрес строки, а не сама строка!

На всякий случай, если кто-то заинтересуется, выдаю работающий код.
Код
void  itoad(int number, uint8_t *string)
{
  #define  TETRASPACE  ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24
  #define  TETRATAIL   ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24
  uint8_t  sign;
  *(uint32_t *)(string) = TETRASPACE;
  *(uint32_t *)(string + 4) = TETRASPACE;    
  *(uint32_t *)(string + 8) = TETRATAIL;
  string += 10;
  if (!number) return;
  if (number > 0) sign = '+';
  else {
    number = -number;
    sign = '-';
  }
  do {
    *string-- = number % 10 + '0';
  } while (number /= 10);
  *string = sign;
}


Часть листинга, обратите внимание, стоит команда LDR, а не ADR, как раньше
Код
;;;31       *(uint32_t *)(string) = TETRASPACE;
000002  f04f3220          MOV      r2,#0x20202020
;;;32       *(uint32_t *)(string + 4) = TETRASPACE;    
000006  600a              STR      r2,[r1,#0]
;;;33       *(uint32_t *)(string + 8) = TETRATAIL;
000008  604a              STR      r2,[r1,#4]
00000a  4a3a              LDR      r2,|L1.244|
;;;34       string += 10;
00000c  608a              STR      r2,[r1,#8]
00000e  310a              ADDS     r1,r1,#0xa
ViKo
16-битовая версия (на основе 32-битовой)
Код
void  i16toad(int16_t number, uint8_t *string)
{
  #define  TETRASPACE  ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24
  #define  TETRATAIL   ' ' | '0' << 8 | '\0'<< 16 | '\0'<< 24
  uint8_t sign;
  int32_t num = (int32_t)number;
  *(uint32_t *)string = TETRASPACE;
  *(uint32_t *)(string + 4) = TETRATAIL;
  string += 5;
  if (!num) return;
  else
    if (num > 0) sign = '+';
    else {
      sign = '-';
      num = -num;
    }
  do {
    *string-- = num % 10 + '0';
  } while (num /= 10);
  *string = sign;  
}

Те же 58 байтов, но нет константы 4-байтовой. 105 тактов для -32767.
MrYuran
Вот никак не могу понять, почему никто до сих пор не придумал оператор, который возвращает сразу и частное, и остаток.
Ведь они оба образуются при операции деления.
Зачем 2 раза проводить одну и ту же операцию, чтобы взять по очереди две половинки результата?
laughing.gif
Тяжёлое наследие бейсика...
ViKo
Цитата(MrYuran @ Jun 30 2010, 14:31) *
Вот никак не могу понять, почему никто до сих пор не придумал оператор, который возвращает сразу и частное, и остаток.

В 51-й микроЭВМ была. А в Cortex заменяется двумя командами (upd. Вернее, тремя. Исправил код). Дважды не делается.
Код
000022  4602              MOV      r2,r0
000024  fb90f0f3          SDIV     r0,r0,r3
000028  fb032210          MLS      r2,r3,r0,r2
ViKo
Напоследок - проверил вариант с преобразованием в 4.28, для int16, с той же формой выдачи результата. Получилось 100 байтов, 150 циклов, не лучший способ. В-общем, вариант itoa для Cortex для себя я уже выбрал smile.gif.
aaarrr
Цитата(ViKo @ Jun 30 2010, 17:12) *
Получилось 100 байтов, 150 циклов, не лучший способ.

Ну, этот способ я выбирал с учетом специфики ARM7 - там картина должна быть противоположной.
ViKo
Цитата(aaarrr @ Jun 30 2010, 15:34) *
Ну, этот способ я выбирал с учетом специфики ARM7 - там картина должна быть противоположной.

Я понял.
Сложнее поставить знак в нужное место, и для гашения лидирующих нулей нужна переменная. Зато вместо деления - умножение. В-общем, все наоборот.
Идея интересная - поделить число на 10000 и умножить на 2^28 (для других размерностей можно использовать другие числа, например, для 8-битов - использовать форму 4.12, умножив на 41).
zltigo
QUOTE (ViKo @ Jun 30 2010, 11:22) *
На всякий случай..

Ну если упорно не хотите нормальное сравнение следать, то вот:
CODE
     59          void  itoad(int number, uint8_t *string)
     60          {
   \                     itoad:
   \   00000000   10B4               PUSH     {R4}
     61            int  sign;
     62            *(int32_t *) string =        0x20202020;
   \   00000002   ....               LDR.N    R2,??DataTable1_1;; 0x20202020
   \   00000004   0A60               STR      R2,[R1, #+0]
     63            *(int32_t *)(string += 4) =  0x20202020;  
   \   00000006   4A60               STR      R2,[R1, #+4]
     64            *(int32_t *)(string += 4) =  0x00302020;
   \   00000008   ....               LDR.N    R2,??DataTable1_2;; 0x302020
   \   0000000A   8A60               STR      R2,[R1, #+8]
     65            string += 2;
   \   0000000C   0A31               ADDS     R1,R1,#+10
     66            if (!number) return;
   \   0000000E   78B1               CBZ.N    R0,??itoad_0
     67            if (number > 0) sign = '+';
   \   00000010   0128               CMP      R0,#+1
   \   00000012   AEBF               ITEE     GE
   \   00000014   2B22               MOVGE    R2,#+43
   \   00000016   4042               RSBLT    R0,R0,#+0
   \   00000018   2D22               MOVLT    R2,#+45
     68            else {
     69              number = -number;
     70              sign = '-';
     71            }
     72            do {
     73              *string-- = number % 10 + '0';
   \                     ??itoad_1:
   \   0000001A   0A23               MOVS     R3,#+10
   \   0000001C   90FBF3F4           SDIV     R4,R0,R3
   \   00000020   03FB1400           MLS      R0,R3,R4,R0
   \   00000024   3030               ADDS     R0,R0,#+48
   \   00000026   01F80109           STRB     R0,[R1], #-1
     74            } while (number /= 10);
   \   0000002A   2000               MOVS     R0,R4
   \   0000002C   F5D1               BNE.N    ??itoad_1
     75            *string = sign;
   \   0000002E   0A70               STRB     R2,[R1, #+0]
     76          }
   \                     ??itoad_0:
   \   00000030   10BC               POP      {R4}
   \   00000032   7047               BX       LR             ;; return
ViKo
Цитата(zltigo @ Jun 30 2010, 22:02) *
Ну если упорно не хотите нормальное сравнение сделать, то вот:

Вы имеете в виду сравнение кода, или операции сравнения внутри кода? Почему не хочу? Еще как! Листинг я же выдал, там, в файлике keil_temp.txt (он и создается Keil-ом именно в таком виде, с расширением txt). Вот еще раз, после замены типа переменной sign (думал, может в ней дело). С недоумением разглядываю ваш и свой листинги, ничего путного на ум не приходит.
Код
                  itoad PROC
;;;27      ***************************************************************************
****/
;;;28     void  itoad(int number, uint8_t *string)
000000  b510              PUSH     {r4,lr}
;;;29     {
;;;30       #define  TETRASPACE  ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24
;;;31       #define  TETRATAIL   ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24
;;;32     //  uint8_t  sign;
;;;33       int  sign;
;;;34       *(uint32_t *)(string) = TETRASPACE;
000002  f04f3220          MOV      r2,#0x20202020
;;;35       *(uint32_t *)(string + 4) = TETRASPACE;    
000006  600a              STR      r2,[r1,#0]
;;;36       *(uint32_t *)(string + 8) = TETRATAIL;
000008  604a              STR      r2,[r1,#4]
00000a  4a62              LDR      r2,|L1.404|
;;;37       string += 10;
00000c  608a              STR      r2,[r1,#8]
00000e  310a              ADDS     r1,r1,#0xa
;;;38       if (!number) return;
000010  2800              CMP      r0,#0
000012  d011              BEQ      |L1.56|
;;;39       if (number > 0) sign = '+';
000014  dd02              BLE      |L1.28|
000016  f04f042b          MOV      r4,#0x2b
00001a  e001              B        |L1.32|
                  |L1.28|
;;;40       else {
;;;41         number = -number;
00001c  4240              RSBS     r0,r0,#0
;;;42         sign = '-';
00001e  242d              MOVS     r4,#0x2d
                  |L1.32|
;;;43       }
;;;44       do {
;;;45         *string-- = number % 10 + '0';
000020  230a              MOVS     r3,#0xa
                  |L1.34|
000022  4602              MOV      r2,r0
000024  fb90f0f3          SDIV     r0,r0,r3
000028  fb032210          MLS      r2,r3,r0,r2
00002c  3230              ADDS     r2,r2,#0x30
00002e  f8012901          STRB     r2,[r1],#-1
;;;46       } while (number /= 10);
000032  2800              CMP      r0,#0
000034  d1f5              BNE      |L1.34|
;;;47       *string = sign;
000036  700c              STRB     r4,[r1,#0]
                  |L1.56|
;;;48     }
000038  bd10              POP      {r4,pc}
;;;49    
                          ENDP

У вас метка itoad играет какую-то роль? Почему-то у меня запоминается в стеке LR, а у вас нет.
У вас в строке 63 должно быть число 0x20202020 или, как написано?
Сравнение number производится по-разному, но я не вижу в исходниках разницы.
И это LDR.N - там действительно будет по 2 байта? Где-то рядом таблица?
Забавно, что байты в машинных кодах в IAR и Keil написаны по-разному. Где младший, где старший?
Еще один прикол - у меня '+' заносится в регистр 4-байтовой командой (потому что не имеет повторяющейся последовательности?), а '-' 2-байтовой. У вас все 2-байтовые.

Неужели IAR настолько лучше Keil?
zltigo
QUOTE (ViKo @ Jun 30 2010, 22:29) *
У вас в строке 63 должно быть число 0x20202020 или, как написано?

Следы экспериментов. Все 20
QUOTE
У вас метка itoad играет какую-то роль?

Не у меня, а у ASM - точка входа в эту подпрограмму.
QUOTE
Где-то рядом таблица?

А зачем ей быть далеко? IAR Компилятор сделал все корректно и на 6 байт короче.
QUOTE
Почему-то у меня запоминается в стеке LR

Keil решил сэкономить на BX LR



_Pasha
Цитата(MrYuran @ Jun 30 2010, 14:31) *
Тяжёлое наследие бейсика...

Это просто обязано быть отдано на откуп оптимизатору, иначе ломается синтаксис арифметического выражения. Тернарные операции с двумя значениями - это невозможно использовать.
ViKo
Цитата(Сергей Борщ @ Jun 29 2010, 17:18) *
Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.

Грабли можно избежать, если определить строку в виде объединения байтов и 4-байтовых слов.
2 all:
Как сделать в Keil то же, что и в IAR?

Цитата(zltigo @ Jul 1 2010, 00:14) *
IAR Компилятор сделал все корректно и на 6 байт короче.

Только в таблице у него 8 байтов, а у Keil-а 4. Итого, с учетом таблицы, 60 байтов против 62 байтов.

P.S. А тема-то, действительно, начинает соответствовать своему названию - "Вопрос C" smile.gif
zltigo
QUOTE (ViKo @ Jul 1 2010, 10:55) *
Только в таблице у него 8 байтов

Это дело даже не второе, а третье, ибо байты кода это еще команды которые еще исполняются, а некоторые, типа PUSH/POP нескольких регистров, еще и не за один такт.


QUOTE (ViKo @ Jul 1 2010, 10:55) *
Как сделать в Keil то же, что и в IAR?

Написать на ASM smile.gif
ViKo
Цитата(zltigo @ Jul 1 2010, 14:57) *
Это дело даже не второе, а третье, ибо байты кода это еще команды которые еще исполняются, а некоторые, типа PUSH/POP нескольких регистров, еще и не за один такт.

Давайте проверим. Число -2147483647 (т.е. -(2^31 - 1), максимально допустимое для функции) Keil преобразовал за 207 тактов (сравнивал счетчик тактов перед вызовом itoad и после нее). Сколько у IAR?
zltigo
QUOTE (ViKo @ Jul 1 2010, 14:34) *
Давайте проверим.

smile.gif Думаете дополнительные команды ускорят процесс?
ViKo
Цитата(zltigo @ Jul 1 2010, 15:38) *
smile.gif Думаете дополнительные команды ускорят процесс?

Хочу знать, насколько замедлят.
MOV r2,#0x20202020 выполняется за 1 такт.
zltigo
QUOTE (ViKo @ Jul 1 2010, 14:52) *
Хочу знать, насколько замедлят.

Посчитайте на пальцах.
ViKo
Цитата(zltigo @ Jul 1 2010, 15:55) *
Посчитайте на пальцах.

На пальцах до 200? У меня столько пальцев нет smile.gif
Я лучше на бумаге smile.gif и калькуляторе.
А SDIV r0,r0,r3 выполняется за 11 тактов... upd. Не всегда! - обнаружил и 10 тактов, и 9 тактов, похоже, от чисел зависит. О! чем меньше делимое, тем меньше тактов. Видел 4 такта.
... а MLS r2,r3,r0,r2 всего за 2.

Так что на пальцах, извините, никак не посчитать.
Максимальное количество тактов для SDIV заметил 12. Где про такты написано?

2 zltigo
Ну если упорно не хотите нормальное сравнение сделать... smile.gif
zltigo
QUOTE (ViKo @ Jul 1 2010, 15:59) *
2 zltigo
Ну если упорно не хотите нормальное сравнение сделать... smile.gif

Меня интересует результат компиляции - уже четко видна и разница и порядок отличия. А заниматься попугаемерами в симуляторах и иже с ним не собираюсь. Тем более, что железо с его ограничениями отдельная песня.
sonycman
Цитата(ViKo @ Jul 1 2010, 17:59) *
А SDIV r0,r0,r3 выполняется за 11 тактов... upd. Не всегда! - обнаружил и 10 тактов, и 9 тактов, похоже, от чисел зависит. О! чем меньше делимое, тем меньше тактов. Видел 4 такта.
...
Максимальное количество тактов для SDIV заметил 12. Где про такты написано?

Cortex-M3 Technical Reference Manual
Divide: 2-12 Cycles
DIV timings depend on dividend and divisor. DIV is interruptible (abandoned/restarted), with worst case latency of one cycle.
When dividend and divisor are similar in size, divide terminates quickly. Minimum time is for cases of divisor larger than
dividend and divisor of zero. A divisor of zero returns zero (not a fault), although a debug trap is available to catch this case.
ViKo
Перепробовал все "извращения" со сравнениями и др. в надежде уменьшить количество байтов.
Кто бы мне объяснил, почему в некоторых местах команда MOV r2,... кодируется двумя байтами, а в некоторых четырьмя? И не только эта команда.
Код
;;;63       uint8_t  sign = '+';
000010  222b              MOVS     r2,#0x2b
;;;64       if (!number) return;
000012  2800              CMP      r0,#0
000014  d010              BEQ      |L1.56|
;;;65       if (number < 0) {
000016  da03              BGE      |L1.32|
;;;66         number = -number;
000018  f1c00000          RSB      r0,r0,#0
;;;67         sign = '-';
00001c  f04f022d          MOV      r2,#0x2d
                  |L1.32|
;;;68       }

Как-то связано с операторами перехода по результатам сравнения. Как будто учитывается конвейер.
ViKo
Думаю, хуже не станет, если я доложу, что уменьшил количество тактов для преобразования -2147483647 в строку до 195. Жаль, что не байтов.
Код
void  itoad(int32_t number, uint8_t *string)
{
  *(uint32_t *)(string) = 0x20202020;
  *(uint32_t *)(string + 4) = 0x20202020;
  *(uint32_t *)(string + 8) = 0x00302020;
  string += 10;
  uint8_t  sign = '+';
  if (!number) return;
  if (number < 0) {
    number = -number;
    sign = '-';
  }
  do {
    *string-- = number % 10 + '0';
  } while (number /= 10);
  *string = sign;
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.