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

Архитектура оптимизированна для языка С

Станет понятно, что, например, мсп430 - вполне себе оптимизированная, а вот АВР - как бы и вообще не оптимизированная.

Давайте от обратного: что эст архитектура, не оптимизированная под Ц???

Более чем уверен, что и при таком взгляде окажется, что разговоры про сабж не более чем треп.

PS выравнивания 8/16/32 за фичу не принимаем? :)

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


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

Давайте от обратного: что эст архитектура, не оптимизированная под Ц???

Не хочу выдумывать определений и наводить наукообразность. Своё субъективное мнение я высказал. И субъективный способ определения.

Более чем уверен, что и при таком взгляде окажется, что разговоры про сабж не более чем треп.

С моей стороны - почти что да, данный топик - трёп.

PS выравнивания 8/16/32 за фичу не принимаем? :)

Не понял намёка...

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


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

Не понял - о чем речь? Наличие команд с косвенной адресацией и постинкрементом/преддекрементом? Типа таких:

LD r26, X+

LD r26, -X

Если - да, то не замечал, чтобы транслятор языка С их использовал...

:biggrin:

Даже не знаю что сказать.

Так возьмите любой исходник и посмотрите. Например вход/выход пр работе с п/п.

Введение этих команд обусловлено не богатым набором способов адресации операндов в AVR. При этом ещё и на диапазон используемых регистров наложены ограничения в некоторых командах.

В целом набор команд AVR кажется мне каким-то нелогичным.

Правильнее будет сказать что ваш взгляд на это "обусловлен небогатым опытом". Приведу пример, что бы вы поняли, что ваш взгляд на вещи - не есть истина в последней инстанции.

 

Рассмотрим команду "LDD Rx,Y+n".

Как часто вы её применяете при программировании на ассемблере? Откровенно ведь бредовая команда! Есть же LDS и LD. А с этой одна морока. Особенно, как вы уже учли ограниченное смещение. Его же неудобно вручную контролировать!

 

А детали такие. Команда LDS занимает 2 слова. Для команды LD регистровых пар не напасёшься. Всё равно народ недоволен будет. В x51 был 1 указатель. В x52 - 2. В AVR - 3. Всё равно мало. Но есть команда LDD, которую вручную мало кто использует. А компилятор - повсеместно. Он единожды загружает указатель на начало группы данных и соответственно - смещение указывает на конкретную переменную. Команда занимает 1 слово. То что неудобно для человека - прекрасно подходит для компилятора. На смещения и ограничения ему наплевать - это его хлеб. Для него это цифры, которые очень удобны.

    407               Status.TekTime++;
   \   000000E4   01FD               MOVW    R31:R30, R27:R26
   \   000000E6   8D03               LDD     R16, Z+27
   \   000000E8   8D14               LDD     R17, Z+28
   \   000000EA   5F0F               SUBI    R16, 255
   \   000000EC   4F1F               SBCI    R17, 255
   \   000000EE   8F03               STD     Z+27, R16
   \   000000F0   8F14               STD     Z+28, R17

Второе применение - арифметика с большими значениями. Например 32 бита.

    551              }while(j<AdrProgEnd);
   \   00000110   ....               LDI     R30, LOW(AdrProgEnd)
   \   00000112   ....               LDI     R31, (AdrProgEnd) >> 8
   \   00000114   8100               LD      R16, Z
   \   00000116   8111               LDD     R17, Z+1
   \   00000118   8122               LDD     R18, Z+2
   \   0000011A   8133               LDD     R19, Z+3
   \   0000011C   16C0               CP      R12, R16
   \   0000011E   06D1               CPC     R13, R17
   \   00000120   06E2               CPC     R14, R18
   \   00000122   06F3               CPC     R15, R19
   \   00000124   F408               BRCC    $+2+2

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

 

Возьмите кусок типичной программы на Ц и откомпилируйте с выводом асмового сорца. И посмотрите. Глазами.

Станет понятно, что, например, мсп430 - вполне себе оптимизированная, а вот АВР - как бы и вообще не оптимизированная. На АРМ не довелось ещё смотреть, ничего не могу сказать.

А давайте попробуем без голословных утверждений. Приведите пример проги, которая плохо ложится на AVR и хорошо на MSP.

 

А пока я беру данную ссылку http://mcu.caxapa.ru/benchmarks/ и на первомже примере вижу что после компилирования проги компилятором одной и той же фирмы mega делает MSP в 2 раза по тактам, в 3 по производительности и почти вдвое по объёму кода. И как это согласуется с вашим утверждением?

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


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

Приведите пример проги, которая плохо ложится на AVR и хорошо на MSP.

 

16тибитная арифметика на MSP ляжет явно лучше. А 32хбитная - на ARM ;)

 

Кроме того, на AVR иногда не хватает указателей, что приводит к необходимости небанального кода.

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


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

16тибитная арифметика на MSP ляжет явно лучше. А 32хбитная - на ARM ;)

 

Кроме того, на AVR иногда не хватает указателей, что приводит к необходимости небанального кода.

Да кто же спорит.

Я просто говорю, что Atmel имел полное моральное право утверждать, что они пилили архитектуру под си. А уже насколько - это вопрос другого порядка.

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


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

...Рассмотрим команду "LDD Rx,Y+n".

Как часто вы её применяете при программировании на ассемблере? Откровенно ведь бредовая команда! Есть же LDS и LD. А с этой одна морока. Особенно, как вы уже учли ограниченное смещение. Его же неудобно вручную контролировать!

Зависит от ассемблера, нормальный сам подставит регистры и смещения взамен имен переменных: "mov loc_var, arg_n(sp)".

 

А пока я беру данную ссылку http://mcu.caxapa.ru/benchmarks/ и на первомже примере вижу что после компилирования проги компилятором одной и той же фирмы mega делает MSP в 2 раза по тактам, в 3 по производительности и почти вдвое по объёму кода. И как это согласуется с вашим утверждением?

Надо смотреть набор инструкций, не во всех MSP430 есть аппаратное умножение, а рассматриваемый тест его использует.

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


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

А пока я беру данную ссылку http://mcu.caxapa.ru/benchmarks/ и на первомже примере вижу что после компилирования проги компилятором одной и той же фирмы mega делает MSP в 2 раза по тактам, в 3 по производительности и почти вдвое по объёму кода. И как это согласуется с вашим утверждением?

А теперь смотрим другие тесты:

http://mcu.caxapa.ru/benchmarks/11.html

http://mcu.caxapa.ru/benchmarks/13.html

http://mcu.caxapa.ru/benchmarks/14.html

и видим что 16-битное АЛУ, ортогональная система команд и развитые методы адресации это вовсе не пустой звук.

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


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

Зависит от ассемблера, нормальный сам подставит регистры и смещения взамен имен переменных: "mov loc_var, arg_n(sp)".

 

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

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


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

Не понял - о чем речь? Наличие команд с косвенной адресацией и постинкрементом/преддекрементом? Типа таких:

LD r26, X+

LD r26, -X

Нет, это команды работы со памятью. А поддержка адресной арифметики - это возможность делать арифметические операции над регистрами-указателями. В AVR это уже упомянутые ADIW/SBIW. Заметьте, что эти команды работают только с регистровыми парами, кои у AVR покрывают далеко не все регистры. И прибавление/вычитание делается всего-то в пределах 64. И число это константно и задается на этапе компиляции. Да, убогая, но все-таки это она - поддержка адресной арифметики.

 

Если - да, то не замечал, чтобы транслятор языка С их использовал...

Использует, использует, не сомневайтесь. Только нечасто, т.к. применимость в виду убогости весьма ограничена.

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


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

Да, убогая, но все-таки это она - поддержка адресной арифметики.

Структуры длиной более 64 байт на 8-битниках - это редкое явление, посему все довольно гармонично.

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


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

Структуры длиной более 64 байт на 8-битниках - это редкое явление, посему все довольно гармонично.

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

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


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

А теперь смотрим другие тесты:

http://mcu.caxapa.ru/benchmarks/11.html

http://mcu.caxapa.ru/benchmarks/13.html

http://mcu.caxapa.ru/benchmarks/14.html

и видим что 16-битное АЛУ, ортогональная система команд и развитые методы адресации это вовсе не пустой звук.

 

Я уж не знаю, как господин Генерал на Сахаре получал эти результаты, но для 11го и 14го результаты - 26 тактов и 29 тактов соответственно, вместо заявленных 131 и 144.

 

Пример кода для 11го

       RSEG CODE:CODE:NOROOT(1)
//    9 UInt8 switch_case(UInt8 a)
switch_case:
//   10 {
//   11 UInt8 output;
//   12 switch (a)
       DEC     R16
       CPI     R16, 16
       BRCC    ??switch_case_0
       LDI     R31, 2
       MUL     R16, R31
       MOVW    R31:R30, R1:R0
       SUBI    R30, LOW((-(`?<Jumptable for switch_case>_0`) & 0xFFFF))
       SBCI    R31, (-(`?<Jumptable for switch_case>_0`) & 0xFFFF) >> 8
       LPM     R0, Z+
       LPM     R1, Z
       MOVW    R31:R30, R1:R0
       IJMP
//   13 {
//   14 case 0x01:
//   15 output = 0x01;
??switch_case_1:
       LDI     R17, 1
       RJMP    ??switch_case_0
//   16 break;
//   17 case 0x02:
//   18 output = 0x02;
??switch_case_2:
       LDI     R17, 2
       RJMP    ??switch_case_0
//   19 break;
//   20 case 0x03:
//   21 output = 0x03;
??switch_case_3:
       LDI     R17, 3
       RJMP    ??switch_case_0
//   22 break;
//   23 case 0x04:
//   24 output = 0x04;
??switch_case_4:
       LDI     R17, 4
       RJMP    ??switch_case_0
//   25 break;
//   26 case 0x05:
//   27 output = 0x05;
??switch_case_5:
       LDI     R17, 5
       RJMP    ??switch_case_0
//   28 break;
//   29 case 0x06:
//   30 output = 0x06;
??switch_case_6:
       LDI     R17, 6
       RJMP    ??switch_case_0
//   31 break;
//   32 case 0x07:
//   33 output = 0x07;
??switch_case_7:
       LDI     R17, 7
       RJMP    ??switch_case_0
//   34 break;
//   35 case 0x08:
//   36 output = 0x08;
??switch_case_8:
       LDI     R17, 8
       RJMP    ??switch_case_0
//   37 break;
//   38 case 0x09:
//   39 output = 0x09;
??switch_case_9:
       LDI     R17, 9
       RJMP    ??switch_case_0
//   40 break;
//   41 case 0x0a:
//   42 output = 0x0a;
??switch_case_10:
       LDI     R17, 10
       RJMP    ??switch_case_0
//   43 break;
//   44 case 0x0b:
//   45 output = 0x0b;
??switch_case_11:
       LDI     R17, 11
       RJMP    ??switch_case_0
//   46 break;
//   47 case 0x0c:
//   48 output = 0x0c;
??switch_case_12:
       LDI     R17, 12
       RJMP    ??switch_case_0
//   49 break;
//   50 case 0x0d:
//   51 output = 0x0d;
??switch_case_13:
       LDI     R17, 13
       RJMP    ??switch_case_0
//   52 break;
//   53 case 0x0e:
//   54 output = 0x0e;
??switch_case_14:
       LDI     R17, 14
       RJMP    ??switch_case_0
//   55 break;
//   56 case 0x0f:
//   57 output = 0x0f;
??switch_case_15:
       LDI     R17, 15
       RJMP    ??switch_case_0
//   58 break;
//   59 case 0x10:
//   60 output = 0x10;
??switch_case_16:
       LDI     R17, 16
//   61 break;
//   62 } /* end switch*/
//   63 return (output);
??switch_case_0:
       MOV     R16, R17
       RET
//   64 }
...
       RSEG SWITCH:CODE:NOROOT(1)
`?<Jumptable for switch_case>_0`:
       DW      (??switch_case_1) /2
       DW      (??switch_case_2) /2
       DW      (??switch_case_3) /2
       DW      (??switch_case_4) /2
       DW      (??switch_case_5) /2
       DW      (??switch_case_6) /2
       DW      (??switch_case_7) /2
       DW      (??switch_case_8) /2
       DW      (??switch_case_9) /2
       DW      (??switch_case_10) /2
       DW      (??switch_case_11) /2
       DW      (??switch_case_12) /2
       DW      (??switch_case_13) /2
       DW      (??switch_case_14) /2
       DW      (??switch_case_15) /2
       DW      (??switch_case_16) /2

 

№13 - это тот самый случай, в котором не хватает регистровых пар, что приводит к оверхеду

...
//   32 {
//   33 for(j = 0; j < 4; j++)
??main_0:
       MOVW    R17:R16, R25:R24
       MOVW    R19:R18, R21:R20
       MOVW    R31:R30, R23:R22
       LDI     R26, 4
       MOV     R1, R26
//   34 {
//   35 m2[i][j] = m1[i][j];
??main_1:
       MOVW    R27:R26, R19:R18
       LD      R2, X+
       LD      R3, X+
       MOVW    R19:R18, R27:R26
       MOVW    R27:R26, R17:R16
       ST      X+, R2
       ST      X, R3
//   36 m3[i][j] = m2[i][j];
       MOVW    R27:R26, R17:R16
       LD      R2, X+
       LD      R3, X+
       MOVW    R17:R16, R27:R26
       ST      Z+, R2
       ST      Z+, R3
//   37 }
       DEC     R1
       BRNE    ??main_1
//   38 }
...

 

Привел только внутренний цикл. Как видите, даже с учетом копирования в индексные регистры все не так плохо - компилятор превратил программу на Фортране в программу на Си (заменив p[j] на *p++) и стало вполне ничего. Кстати, тактов там не заявленных 24426, а всего то 1773.

 

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

 

Короче, мораль сей басни такова - перед тем, как сделать ^C^V, проверьте, не увеличиваете ли Вы количество ахинеи на один мегабайт траффика, которую и так несут все кому ни лень :)

 

Использует, использует, не сомневайтесь. Только нечасто, т.к. применимость в виду убогости весьма ограничена.

 

См. выше про автоматическую трансляцию Фортран->Си :biggrin:

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


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

Давайте исходить из того, что идеального процессора пока ещё несуществует. Выбирается баланс м/у объёмом кремния, сложностью и идеальностью компилирования. Для тех задач, под которые данный МК создавался - результат неплохой. Хотя, безусловно, не лучший.

 

По поводу MSP. Красивый процессор, красиво построен. Но претензий тоже немало. И результат - какова стоимость при сопоставимых решаемых задачах. Интересно также, что апликэйшн от TI под MSP - очень часто на ASM идут.

 

И ещё мне кажется, что прогресс движется по многим направлениям. С одной стороны, камни пилятся под компиляторы, а с другой компиляторы значительно больше возможностей имеют учитывать особенности камней. Это не то что раньше, где вместо оператора подставлялась группа ASM команд. Теперь анализируются целые куски кода. Думаю дальше будет ещё круче. Ну и разрядность процов будет повышаться.

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


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

Структуры длиной более 64 байт на 8-битниках - это редкое явление, посему все довольно гармонично.

Убогость не в ограничении длины модификатора, а в том, что кроме этих +/- с литералом оно ничего не умеет. Например, код:

 

int array[N];
...
int f(int n)
{
    ...
    return *(array + n); // или так: return array[n]; кому как больше нравится :)
}

 

Тут понадобится умножить размер элемента на количество, чтобы вычислить смещение. Придется на AVR лабать обычную арифметику, потом копировать вычисленный адрес в регистровую пару - указатель. Где тут поддержка? Нету. Вот кабы вычисления прямо в регистре-указателе делались либо можно было бы вычисленное смещение прибавить к адресу.

 

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

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


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

Где тут поддержка? Нету. Вот кабы вычисления прямо в регистре-указателе делались либо можно было бы вычисленное смещение прибавить к адресу.

Это могла бы быть команда типа multiply-and-accumulate. Слишком шикарно :) Беззнаковое умножение двух произвольных регистров с прибавлением результата к регистровой паре. Оно уложилось бы в 3 такта, насколько я понял. Без этой команды получается 4 такта :)

; int f([b]char[/b] n)
;r24 это есть n

ldi   r25, sizeof_Elem_Array; без загрузки никак не обойтись

mul r24,r25;2
add r30,r0;1
adc r31,r1;1

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


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

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

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

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

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

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

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

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

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

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