Перейти к содержанию
    

Вот как написано, так пробуйте.

Во всех (!) перечисленнных вариантах делается одно и то же: +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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во всех (!) перечисленнных вариантах делается одно и то же: +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

Выложите-ка просто целиком и без редактирования ДВА листинга, как у Вас было и как я предложил. Тогда будет видно.

Пока "идеальный варинат" этого кусочка мог-бы быть такой:

STR      r2,[r1,#0]
STR      r2,[r1,#4]
ADR      r2,......
STR      r2,[r1,#8]
ADDS     r1,r1,#10

Все команды по 16бит и на два байта меньше относительно приведенного выше варианта.

Но компилятору чего-то у уму заклинило :(

А что будет если так:

*(uint32_t *)(string + 4) =  '    ';  
  *(uint32_t *)(string + 8 ) = (uint32_t )"  0";
  string += 10;

 

 

P.S.

Компильнул IAR-овским компилятором (слега еще подправив,но в общем, как в 73 посте) все, как задумывалось получилось и 54 байта размер кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выкладываю ваш вариант.

Последнее, что вы написали, тоже делал.

Пара вопросов, возникших в процессе... -

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

Вроде уже делал так.

keil_temp.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

"Шеф, все пропало!..."

По команде *(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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ведь они оба образуются при операции деления.

Зачем 2 раза проводить одну и ту же операцию, чтобы взять по очереди две половинки результата?

:laughing:

Тяжёлое наследие бейсика...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

В 51-й микроЭВМ была. А в Cortex заменяется двумя командами (upd. Вернее, тремя. Исправил код). Дважды не делается.

000022  4602              MOV      r2,r0
000024  fb90f0f3          SDIV     r0,r0,r3
000028  fb032210          MLS      r2,r3,r0,r2

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Напоследок - проверил вариант с преобразованием в 4.28, для int16, с той же формой выдачи результата. Получилось 100 байтов, 150 циклов, не лучший способ. В-общем, вариант itoa для Cortex для себя я уже выбрал :).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Получилось 100 байтов, 150 циклов, не лучший способ.

Ну, этот способ я выбирал с учетом специфики ARM7 - там картина должна быть противоположной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, этот способ я выбирал с учетом специфики ARM7 - там картина должна быть противоположной.

Я понял.

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

Идея интересная - поделить число на 10000 и умножить на 2^28 (для других размерностей можно использовать другие числа, например, для 8-битов - использовать форму 4.12, умножив на 41).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На всякий случай..

Ну если упорно не хотите нормальное сравнение следать, то вот:

     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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну если упорно не хотите нормальное сравнение сделать, то вот:

Вы имеете в виду сравнение кода, или операции сравнения внутри кода? Почему не хочу? Еще как! Листинг я же выдал, там, в файлике 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?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У вас в строке 63 должно быть число 0x20202020 или, как написано?

Следы экспериментов. Все 20

У вас метка itoad играет какую-то роль?

Не у меня, а у ASM - точка входа в эту подпрограмму.

Где-то рядом таблица?

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

Почему-то у меня запоминается в стеке LR

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

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тяжёлое наследие бейсика...

Это просто обязано быть отдано на откуп оптимизатору, иначе ломается синтаксис арифметического выражения. Тернарные операции с двумя значениями - это невозможно использовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.

Грабли можно избежать, если определить строку в виде объединения байтов и 4-байтовых слов.

2 all:

Как сделать в Keil то же, что и в IAR?

 

IAR Компилятор сделал все корректно и на 6 байт короче.

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

 

P.S. А тема-то, действительно, начинает соответствовать своему названию - "Вопрос C" :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...