Показано с 1 по 10 из 688

Тема: Программирование ПЛК110 [М02] для задач реального времени

Комбинированный просмотр

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #1

    По умолчанию

    Цитата Сообщение от Дмитрий Артюховский Посмотреть сообщение
    Это не правда. Транслятор с фбд вполне себе разбирается с высвобождением и переиспользованием регистров.
    Вердикт: эксперимент показывает, что регистры _не_ переиспользуются. Тут всё ровно так, как и говорил Владислав.

    Дмитрий, я требую извинений.



    Вот пример: test_add.zip, pru_register_reuse.png

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

    Компилируем и видим такое (в конце):
    Код:
    #defFB PRU_AND2_64 PRU_AND2 
    R8.b2 
    R8.b3 
    R9.b0 
    
    #defFB PRU_AND2_59 PRU_AND2 
    R7.b1 
    R9.b0 
    R9.b1 
    
    #defFB PRU_AND2_65 PRU_AND2 
    R5.b2 
    R9.b1 
    R9.b2
    Видно, что номера регистров только растут. Т.е. регистры с меньшими номерами не переиспользуются.

    Пойдём в target.trg файл, и уменьшим значение REG_END=28 до 8-и. Ну, сделаем вид, что в нашем PRU всего-навсего 8 регистров.

    Что нам скажет компилятор?
    Он нам скажет "unknown ID 0 in element", и вообще не сможет скомпилировать такое FBD.

    Т.е. по факту, компилятору не хватило R2..R8 регистров (7 штук по 4 байта каждый, т.е. 28 байт!).
    А по факту, видно, что регистры для "AND" блоков очень быстро становятся ненужными.

    По факту, тут 4 "FROM_HOST" блока. Да, 16 байт действительно нужно постоянно хранить (информация с HOST'а обновляется далеко не в каждом PRU цикле). Но остаётся целых 12 байт == 28-16, и линкер всё равно не смог выполнить несколько AND'ов? Что за ерунда?

    Поэтому я и говорю, что мой подход и подход ОВЕН в части компиляции существенно отличаются.
    Ну это я к чему, не к тому, что "инструмент beta PRU плохой", а к тому, что это моя аргументация почему я не могу просто взять и оформить свою ШД программу "по правилам ОВЕН". Тут не только моё субъективное "не хочу тратить время", но и вполне конкретная техническая проблема.
    Последний раз редактировалось Владимир Ситников; 04.10.2016 в 16:15.

  2. #2

    По умолчанию

    Цитата Сообщение от Владимир Ситников Посмотреть сообщение
    Вердикт: эксперимент показывает, что регистры _не_ переиспользуются. Тут всё ровно так, как и говорил Владислав.

    Дмитрий, я требую извинений.



    Вот пример: test_add.zip, pru_register_reuse.png

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

    Компилируем и видим такое (в конце):
    Код:
    #defFB PRU_AND2_64 PRU_AND2 
    R8.b2 
    R8.b3 
    R9.b0 
    
    #defFB PRU_AND2_59 PRU_AND2 
    R7.b1 
    R9.b0 
    R9.b1 
    
    #defFB PRU_AND2_65 PRU_AND2 
    R5.b2 
    R9.b1 
    R9.b2
    Видно, что номера регистров только растут. Т.е. регистры с меньшими номерами не переиспользуются.

    Пойдём в target.trg файл, и уменьшим значение REG_END=28 до 8-и. Ну, сделаем вид, что в нашем PRU всего-навсего 8 регистров.

    Что нам скажет компилятор?
    Он нам скажет "unknown ID 0 in element", и вообще не сможет скомпилировать такое FBD.

    Т.е. по факту, компилятору не хватило R2..R8 регистров (7 штук по 4 байта каждый, т.е. 28 байт!).
    А по факту, видно, что регистры для "AND" блоков очень быстро становятся ненужными.

    По факту, тут 4 "FROM_HOST" блока. Да, 16 байт действительно нужно постоянно хранить (информация с HOST'а обновляется далеко не в каждом PRU цикле). Но остаётся целых 12 байт == 28-16, и линкер всё равно не смог выполнить несколько AND'ов? Что за ерунда?

    Поэтому я и говорю, что мой подход и подход ОВЕН в части компиляции существенно отличаются.
    Ну это я к чему, не к тому, что "инструмент beta PRU плохой", а к тому, что это моя аргументация почему я не могу просто взять и оформить свою ШД программу "по правилам ОВЕН". Тут не только моё субъективное "не хочу тратить время", но и вполне конкретная техническая проблема.
    в этом примере дело не в "анд"-ах а в 4-х кратном размещении "pru_host". в том виде как он сделан в библиотеке - он читает 1 фиксированный регистр

    кстати, продам наблюдение - "подход овена" - это по сути локализация (русификация с извращениями) соответствующего инструмента TI, т.е. достаточно широко используемого инструмента.... Ну конечно "черепаха" круче всего мирового опыта программирования - тут без сомнений. Керниган, Ричи и Кнут плачут горькими слезами ))))
    Последний раз редактировалось Дмитрий Артюховский; 04.10.2016 в 17:47.

  3. #3

    По умолчанию

    Цитата Сообщение от Дмитрий Артюховский Посмотреть сообщение
    в этом примере дело не в "анд"-ах а в 4-х кратном размещении "pru_host". в том виде как он сделан в библиотеке - он читает 1 фиксированный регистр
    Вот вариант с 1 PRU_FROM_HOST.
    Всё равно не работает с параметрами REG_START=2, REG_END=6. В прошлый раз я не учёл, что "последний" регистр линкер не использует, т.е. по факту REG_START=2, REG_END=6 это не 4, а 3 регистра для манёвров, но на такую схему 3 регистра вполне должно хватать?
    Т.е. регистров R2, R3, R4, R5 ему оказывается мало для того, чтобы сделать AND'ы от одного-единственного PRU_FROM_HOST.

    В чём проблема на этот раз?
    linker_and_limitation.png

  4. #4

    По умолчанию

    Цитата Сообщение от Владимир Ситников Посмотреть сообщение
    В чём проблема на этот раз?
    linker_and_limitation.png
    Забавы ради сделал такую же программу в черепахе.
    Выглядит, конечно, не супер, но я сделал так, чтобы было сравнение 1 в 1. Точно такой же ФБ PRU_AND.

    Если кратко, то черепахе оказалось достаточно 4 байт для "FROM HOST" и 5 временных байт (т.е. хватило всего 9 байт регистровой памяти)
    "линкер от ОВЕН" не смог скомпилировать эту программу и с помощью 20-и байт регистровой памяти.



    Само по себе использование ФБ для компилятора сложнее (чем "встроенные" функции AND), т.к. у ФБ значения выходов нельзя терять. Например, если они на каком-то цикле значения не передавались (а был просто вызов ФБ), то нужно использовать "прошлые" значения входов.
    Т.е. самый простой вариант -- всегда выделять отдельные регистры для каждого входа и выхода, но это порождает "потенциально лишнее копирование из одной переменной в другую" и потенциальный перерасход регистров. Я так понял, Владислав пропагандирует именно такой способ.
    Как видим, 15 AND'ов скомпилировать таким подходом уже проблема. По-моему, это слишком высокая плата за мнимую "надёжность".

    Снимок экрана 2016-10-04 в 18.28.36.png

    Я сделал PRU_AND2 как "полноценный блок".
    Блок-то он отдельный, но компилятор "видит его насквозь" и понимает суть происходящего. Мой компилятор понимает, что ассемблерная инструкция AND всегда записывает выходную переменную, т.е. компилятор догадывается, что для этого блока статичный выходной регистр не нужен.

    Результирующий код использует следующие регистры:
    R1 -- 4 байта для PRU_FROM_HOST
    R2 и R3.b0 -- 5 временных байт.

    Да, сама программа получилась не супер -- 31 инструкция (если отбросить HOST/OUT и т.п. обёртку), т.к. осталась часть команд "присвоения входов-выходов" для блоков PRU_AND2.
    Снимок экрана 2016-10-04 в 18.33.24.png

    Под конец только AND'ы идут, т.е. прямо "идеальный код":
    Снимок экрана 2016-10-04 в 19.07.09.png


    Но мы же на ST пишем?
    Что мешает сделать IF (AND AND) THEN?
    Ничего. Немного копипасты и получается такое:
    Снимок экрана 2016-10-04 в 19.11.58.png

    Тут ассемблерный код получается куда лаконичнее. Компилятор просто использует "условные переходы" и прерывает выполнение на первом же FALSE.
    Снимок экрана 2016-10-04 в 19.13.28.png
    Тут вообще ни одного дополнительного регистра не понадобилось. Просто кучка условных переходов.

    Ценность вышеобозначенных примеров, конечно, невелика, но если компилятор без проблем работает с "упоротым" кодом, то и нормально написанный он нормально будет компилировать.
    Последний раз редактировалось Владимир Ситников; 21.10.2016 в 10:16. Причина: добавил ссылку на hardella

  5. #5

    По умолчанию

    Цитата Сообщение от Владимир Ситников Посмотреть сообщение
    Вердикт: эксперимент показывает, что регистры _не_ переиспользуются. Тут всё ровно так, как и говорил Владислав.
    Регистры не переиспользуются и не должны.
    Исключения т.н. макросы (сборки из блоков без внутренней памяти с однозначным потоком исполнения без циклов, например комплексный 4ANDNOT из 3-х AND и NOT).

    Концепция сверхжёсткого реального времени с 100% гарантией исполнения алгоритма не позволяет переиспользовать ресурсы. Результаты промежуточных вычислений (с т.з. процедурного подхода) не являются промежуточными.
    По аналогии, если бы некая цифровая схема по мере прохождения сигнала по лог. элементам переставляла бы проводники (регистры) с входов лог. элемента на выходы. Для экономии меди в стране.
    Пока у нас однозначный поток данных - так делать можно (теоретически).
    Как только есть кольца, ячейки памяти, линии задержки и пр. - такой подход бы приводил к неопределённости поведения и часть линий пришлось бы сделать "запретными".

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

    На самом деле при байтовом I/O PRU уже имеет до 28*4 только регистровых переменых. А битовых в 8 раз больше. + куча ОЗУ.
    Для логики RT управления дискретными I/O этого более чем достаточно.
    А вот если всякие S-кривые в плавающей точке вычислять 1000000 раз в секунду - тут надо подход изменять, а не brute forсe-ом ломится.
    Тролль-наседка, добрый, нежный и ласковый

  6. #6

    По умолчанию

    Цитата Сообщение от Филоненко Владислав Посмотреть сообщение
    Концепция сверхжёсткого реального времени с 100% гарантией исполнения алгоритма не позволяет переиспользовать ресурсы
    1) На самом деле, позволяет. Например, для умножения WORD'ов достаточно сделать 16 итераций цикла. На этих итерациях можно переиспользовать переменные. Никто не пострадает. Можно всегда крутить все 16 итераций и время выполнения вообще константным будет. А можно и выходить из цикла пораньше (если числа маленькие) -- тогда останется время на другие задачи.
    2) Для большинства типичных случаев сверхжёсткий realtime и не нужен. Ну на кой нужен этот самый realtime, если мы ШД крутим?


    Цитата Сообщение от Филоненко Владислав Посмотреть сообщение
    Например в Овен Лоджик блок расчёта таких "запретных" линий, где надо делать промежуточную ячейку памяти занимает немалую часть логики среды разработки и даже после годов отладки иногда бывают "особые ситуации".
    Раз говорите, что "обратную связь" (линию задержки) сделать сложно, то не буду голословным, а просто возьму и сделаю.

    Вот ФБ для "линии задержки":
    Снимок экрана 2016-10-04 в 20.29.51.png

    Вот программа с его использованием. Надеюсь, вы понимаете, что FBD программы в такой ST код переводятся в режиме "что вижу, то пою"?
    Для преобразования FBD в такой ST код нужно лишь объявить переменные с ФБ и присвоить входные-выходные значения.
    Да, топологическую сортировку FBD, конечно, сделать придётся, но это вовсе не вопрос "где нужна доп ячейка, а где не нужна".

    И, да, я ни строчки кода в компиляторе не менял. Просто добавил ФБ и создал программу с его участием.
    Снимок экрана 2016-10-04 в 20.38.11.png

    Вот результирующий ассемблер:

    Снимок экрана 2016-10-04 в 20.38.49.png

    "промежуточная" ячейка образовалась сама собой. R1.b1 (для первой обратной связи) и R1.b2 (для второй).

    Ну, я, конечно, понимаю, что "с первого раза никогда ни одна программа не получается", но не вижу никаких сложностей с обратными связями. Честное слово не вижу.
    Вот я написал простой ST, и он сразу заработал. В чём реально проблема?

    Мой план -- FBD программы преобразовывать в ST, а потом обрабатывать уже имеющимся ST компилятором.
    И наглядность FBD сохранится, и всегда можно будет проверить "во что оно превратилось" / "на каком этапе косяк".

    На всякий случай, я использую следующие ключевые слова: dataflow analysis, live variable analysis, linear scan register allocation. Первые два алгоритма реализовывал не я, а они встроены в среду, на которой я пишу Hardella.


    И, да, сейчас в ОЛ поведение "если есть цикл в программе, то разрывать его и где-то автоматически делать обратную связь", но, на мой взгляд, это нехорошее поведение. Если делать FBD в Hadrella, то я хотел запретить явные циклы, и всегда требовать от пользователя указания где именно связь с задержкой на такт.
    Последний раз редактировалось Владимир Ситников; 05.10.2016 в 11:55.

Похожие темы

  1. Ответов: 38
    Последнее сообщение: 24.01.2022, 11:56
  2. Ответов: 10
    Последнее сообщение: 11.06.2021, 14:55
  3. часы реального времени
    от vetaly в разделе ПЛК1хх
    Ответов: 4
    Последнее сообщение: 28.08.2015, 16:21
  4. Таймер реального времени УТ1-РiС
    от ser10 в разделе Трёп (Курилка)
    Ответов: 0
    Последнее сообщение: 16.09.2010, 12:24

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •