Simatic Step 7. STL. Реверс бит

PLC
  Под операцией реверса битов понимается отображение содержимого регистра относительно середины слова, т.е. отображение битов в слове в обратном порядке.
  В языке 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;

  • 0
  • 10 декабря 2016, 18:28
  • anakost

Комментарии (0)

RSS свернуть / развернуть
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.