Как указано в описании языка COLAMO, можно пользоваться условным оператором (IF) как внутри кадра, так и снаружи. При этом, однако, внутри кадра условный оператор срабатывает совсем не так, как в традиционных языках программирования: транслятор будет реализовать все альтернативные ветви. Поэтому программирующий на COLAMO может наткнуться на коллизию реализации всех ветвей с принципом однократного присваивания. Для мемориальных переменных этот принцип в COLAMO запрещает в одном кадре читать их значения и изменять их.
Например, конструкция вида
CADR IFWRONG;
IF C THEN A=f1(B);
ELSE B=f2(D);
ENDCADR;
недопустима (и транслятор, встретив её, выдаст ошибку), если B является мемориальной переменной, то есть такой, что её значения хранятся в памяти платы ПЛИС.
В описании языка предлагаются разные способы записи, когда алгоритм требует всё же выполнить одну из альтернатив. Если у переменной B в данном фрагменте нельзя поменять тип (на регистровый), то естественное решение - разбиение на 2 кадра:
IF C THEN
CADR IF1;
A= f1(B);
ENDCADR;
ELSE
CADR IF2;
B=f2(D);
ENDCADR;
Хотя уже в описании языка отмечается, что подобное написание замедляет вычисления, в нашем скалярном случае это замедление не такое большое. Однако ситуация становится прямо-таки катастрофической, если по алгоритму надо описать такую вот работу с мемориальным массивом (либо чтение, либо запись) в цикле.
CADR IFWRONG2;
FOR I=1 TO N BEGIN
IF C[I] THEN A[I]=f1(B[I]);
ELSE B[I]=f2(D[I]);
END;
ENDCADR;
Как и первый кадр, этот также синтаксически некорректен. Если теперь мы для получения синтаксически корректной программы применим к нему такой же приём, как к первому:
FOR I=1 TO N BEGIN
IF C[I] THEN
CADR IF3;
A[I]= f1(B[I]);
ENDCADR;
ELSE
CADR IF4;
B[I]=f2(D[I]);
ENDCADR;
END;
то получится, что цикл с большим N, который потенциально дал бы нам конвейеры и хорошую эффективность, здесь даёт многократное переиспользование кадров с маленькими потоками данных и, как следствие, - никаких конвейеров и очень плохие эффективность и скорость работы ПЛИСов. Спрашивается, как с этим бороться, как всё же организовать в ПЛИСах нормальные конвейеры и хорошо их заполнять?
Прежде чем дать решение (одно из возможных), нам необходимо чётко уяснить себе, с чем вообще связан этот самый принцип однократного присваивания в приложении к мемориальным переменным, чтобы у нас не создалось такое впечатление, что, мол, "злые разработчики языка запретили чтение и запись в одном кадре, чтобы осложнить программирование". На самом деле этот запрет языка COLAMO связан с особенностями программирования работы чипов ПЛИС с контроллером распределённой памяти (КРП). То есть в принципе, конечно, схемотехник может запрограммировать плату ПЛИС так, что КРП будет по выбору то записывать данные по каналу, то читать. Однако на такую перенастройку связи необходимо довольно приличное время, сопоставимое с временем настройки на отдельный кадр. Естественно, что разработчики языка эту перенастройку вытолкнули в промежутки между кадрами, поскольку её проведение в рамках кадра начисто загубило бы возможность конвейеризации операций в кадрах.
Исходя из конструктивных причин запрета на одновременное чтение и запись, понятно, что вряд ли вообще нам удастся совместить их в рамках одного конвейера (кадра). Поэтому естественным выходом является разбиение на 2 кадра с буферизацией, для которой нам понадобится дополнительный массив BB:
CADR IFRIGHT1;
FOR I=1 TO N
BB[I]=B[I];
ENDCADR;
CADR IFRIGHT2;
FOR I=1 TO N BEGIN
IF C[I] THEN A[I]=f1(BB[I]);
ELSE B[I]=f2(D[I]);
END;
ENDCADR;
Здесь мы можем ещё столкнуться с проблемой того, что нам не хватит каких-нибудь ресурсов, но это уже тема для отдельного рассмотрения. А оба кадра, как мы видим, вполне могут быть выполнены в конвейерном режиме, так что по быстродействию мы проиграли (по сравнению с, подчеркнём, чисто умозрительной возможностью выполнить конвейерно синтаксически некорректный кадр) не так уж и много - менее чем в 2 раза.
Данная страница написана по материалам рабочего семинара НИИ МВС ЮФУ по языку COLAMO.