Под операцией реверса битов понимается отображение содержимого регистра относительно середины слова, т.е. отображение битов в слове в обратном порядке.
В языке Simatic STL такой команды нет, имеющиеся CAW, CAD реверсируют байты в слове и двойном слове, т.е. преобразуют между форматами little-endian и big-endian. В стандартной библиотеке подобной функции так же нет. Для реализации был выбран алгоритм реверсирования на основе бинарного обмена из книги Генри Уорена «Алгоритмические трюки для программистов», 2014 г.
Его реализация на С для DWORD выглядит так:
x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
Это тот же алгоритм бинарного поиска (применялся для подсчета единичных бит), в котором операции сложения заменены на операции обмена. Его реализация на STL при расчетах использует только внутренние регистры:
FUNCTION FC12: VOID
TITLE = "Реверс двойного слова"
AUTHOR: Anakost //
FAMILY: SOHO //
NAME: RevrBits // Revers Bits
VERSION: 1.0 //
VAR_INPUT
INPUT: DWORD;
END_VAR
VAR_OUTPUT
OUTPUT: DWORD;
END_VAR
BEGIN
NETWORK
TITLE = Алгоритм бинарного обмена DWORD
L #INPUT;
// x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
PUSH; // копия ACCU1 в ACCU2
AD DW#16#55555555; // ACCU1 and 0x55555555
SLD 1; // ACCU1 << 1
TAK; // ACCU1 <-> ACCU2
AD DW#16#AAAAAAAA; // ACCU1 and 0xAAAAAAAA
SRD 1; // ACCU1 >> 1
OD; // ACCU1 <- ACCU1 or ACCU2
// x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
PUSH; //
AD DW#16#33333333; //
SLD 2; //
TAK; //
AD DW#16#CCCCCCCC; //
SRD 2; //
OD; //
// x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
PUSH; //
AD DW#16#0F0F0F0F; //
SLD 4; //
TAK; //
AD DW#16#F0F0F0F0; //
SRD 4; //
OD; //
// x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
PUSH; //
AD DW#16#00FF00FF; //
SLD 8; //
TAK; //
AD DW#16#FF00FF00; //
SRD 8; //
OD; //
// x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
PUSH; //
AD DW#16#0000FFFF; //
SLD 16; //
TAK; //
AD DW#16#FFFF0000; //
SRD 16; //
OD; //
//------------------
T #OUTPUT; //
END_FUNCTION
Алгоритм довольно быстрый, но используя вышеупомянутую команду CAD его можно значительно упростить и убыстрить. Достаточно только отреверсить отдельные байты, т.е. две последние строчки алгоритма будут не нужны.
NETWORK
TITLE = Алгоритм бинарного обмена FastDWORD
L #INPUT;
// x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
PUSH; // копия ACCU1 в ACCU2
AD DW#16#55555555; // ACCU1 and 0x55555555
SLD 1; // ACCU1 << 1
TAK; // ACCU1 <-> ACCU2
AD DW#16#AAAAAAAA; // ACCU1 and 0xAAAAAAAA
SRD 1; // ACCU1 >> 1
OD; // ACCU1 <- ACCU1 or ACCU2
// x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
PUSH; //
AD DW#16#33333333; //
SLD 2; //
TAK; //
AD DW#16#CCCCCCCC; //
SRD 2; //
OD; //
// x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
PUSH; //
AD DW#16#0F0F0F0F; //
SLD 4; //
TAK; //
AD DW#16#F0F0F0F0; //
SRD 4; //
OD; //
//-----------------------
CAD; // реверс байтов в DWORD
//-----------------------
T #OUTPUT; //
Реверс битов для WORD:
VAR_INPUT
INPUT: WORD;
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного обмена WORD
L #INPUT;
PUSH;
SRW 1;
AW W#16#5555;
TAK;
SLW 1;
AW W#16#AAAA;
OW;
PUSH;
SRW 2;
AW W#16#3333;
TAK;
SLW 2;
AW W#16#CCCC;
OW;
PUSH;
SRW 4;
AW W#16#0F0F;
TAK;
SLW 4;
AW W#16#F0F0;
OW;
CAW;
T #OUTPUT;
Реверс битов для BYTE:
VAR_INPUT
INPUT: BYTE;
END_VAR
...
NETWORK
TITLE = Алгоритм бинарного обмена BYTE
L #INPUT;
PUSH;
SRW 1;
AW B#16#55;
TAK;
SLW 1;
AW B#16#AA;
OW;
PUSH;
SRW 2;
AW B#16#33;
TAK;
SLW 2;
AW B#16#CC;
OW;
PUSH;
SRW 4;
AW B#16#0F;
TAK;
SLW 4;
AW B#16#F0;
OW;
T #OUTPUT;
Источник: http://we.easyelectronics.ru/plc/simatic-step-7-stl-revers-bit.html