С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
В описании ВП1-128 написано, что CRC вычисляется по формуле: 1 + x^5 + x^12 + x^16.
Но по такой формуле работают несколько разных алгоритмов CRC-16, дающих разные результаты, например:
Есть ли возможность уточнить, какой именно алгоритм у генератора CRC ВП1-128 ?Код:KERMIT ( CCITT ) width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 XMODEM width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31C3 CRC-16 width=16 poly=0x1021 init=0xFFFF refin=false refout=false xorout=0x0000 check=0x29B1 X-25 width=16 poly=0x1021 init=0xFFFF refin=true refout=true xorout=0xFFFF check=0x906E
По идее - он должен перебирать биты каждого записываемого слова от старшего к младшему ( в порядке их расположения на диске ).
Контроллеры DEC и IBM ( если верить документации ) вычисляют CRC так:
1. Начальное значение CRC = 0xFFFF ;
2. Старший бит идёт первым ;
3. Запись вычисленной суммы без инверсии.
Т.е. по сути - это одно и то же, только инверсия результата выполняется до начала вычисления CRC, а не после.
...
Вычисление CRC начинается в момент записи маркера, поэтому возникают два вопроса:
1. Что именно запускает генератор CRC при записи:
1.1. Установка бита WM (9) ;
1.2. То же + байт 0xA1 в сдвиговом регистре.
2. Если генератор CRC в ходе записи не был запущен - будет ли выполнена запись CRC ( 0xFFFF ) в момент пропуска требования ?
---------- Post added at 13:08 ---------- Previous post was at 12:16 ----------
Похоже, что алгоритм такой. Байтовый вариант выглядит так:
Код:unsigned short crc16( unsigned char byte, int step ) { static unsigned short crc = 0; if( step == 0 ) { crc = 0; } crc ^= unsigned short ( byte ) << 8; for( int i = 0 ; i < 8 ; i++ ) { if( crc & 0x8000 ) crc = (crc << 1) ^ 0x1021; else crc = crc << 1; } return crc; }
---------- Post added at 13:27 ---------- Previous post was at 13:08 ----------
Также ( если я правильно понял ) при чтении CRC проверяется так - если требование выполнено, то содержимое регистра данных интерпретируется как данные и включается в расчёт CRC, если же требование не выполнено - содержимое регистра данных интерпретируется как инверсное значение CRC, прибавляется к рассчитанному значению CRC и результат проверяется на равенство 0xFFFF.
Но тогда получается, что если продолжать забирать данные из регистра данных - инверсное значение CRC будет прочитано как обычные данные и чтение пойдёт дальше.
А что в таком случае произойдёт при считывании маркера:
1. Чтение продолжится, но произойдёт сброс генератора CRC и расчёт CRC начнётся заново со считанного байта 0xA1 ;
2. Произойдёт что-то ещё..
Последний раз редактировалось Patron; 14.12.2013 в 12:14.
Update:
Я тут начал моделировать запись сектора, выявил еще один косяк ВП1-128, она оказывается бит готовности данных ставит сильно заранее (до момента перенесения старшего байта из регистра данных в сдвиговый регистр), и если быстрая шина МПИ (как в используемой сейчас модели процессора - он пишет-читает максимально быстро), то она успевает переписать регистр данных быстрее чем из него успевает переписаться старший байт в сдвиговый регистр (потому что увидела раннюю готовность). Сейчас ввел в транзакции МПИ задержки, будут результаты - отпишу.
Последний раз редактировалось Vslav; 13.12.2013 в 13:50.
Уж для того, чтобы разобраться какой алгоритм используется для подсчета CRC, в архиве "сырые данные" с нулевой дорожки нижней стороны отформатированной на УКНЦ дискеты. Там все - и межсекторные промежутки, и маркеры, и заголовки, и данные, ну и соответственно CRC.
Чтобы далеко не ходить - возьмём заголовок первого сектора:Запустим эти байты в стандартный алгоритм CRC-16:Код:A1 A1 A1 FE 00 00 01 02 CA 6FРезультат запуска:Код:printf("Write:"); crc = 0xFFFF; crc = crc16(crc, 0xA1); crc = crc16(crc, 0xA1); crc = crc16(crc, 0xA1); crc = crc16(crc, 0xFE); crc = crc16(crc, 0x00); crc = crc16(crc, 0x00); crc = crc16(crc, 0x01); crc = crc16(crc, 0x02); tmp = crc; printf("\nCRC: %04X", tmp); printf("\n\nRead:"); crc = 0xFFFF; crc = crc16(crc, 0xA1); crc = crc16(crc, 0xA1); crc = crc16(crc, 0xA1); crc = crc16(crc, 0xFE); crc = crc16(crc, 0x00); crc = crc16(crc, 0x00); crc = crc16(crc, 0x01); crc = crc16(crc, 0x02); crc = crc16(crc, 0xCA); crc = crc16(crc, 0x6F); printf("\nTMP: %04X", crc); if ( crc == 0x0000 ) printf(" CRC OK");ВП1-128 "внутри себя" использует инверсный вариант CRC-16, но перед записью на диск инвертирует CRC, поэтому на диск пишется в точности то же, что генерит стандартный алгоритм CRC-16:Код:Write: A1 ( FFFF, 443B ) A1 ( 443B, 968B ) A1 ( 968B, CDB4 ) FE ( CDB4, B230 ) 00 ( B230, B799 ) 00 ( B799, 4E3C ) 01 ( 4E3C, 852B ) 02 ( 852B, CA6F ) CRC: CA6F Read: A1 ( FFFF, 443B ) A1 ( 443B, 968B ) A1 ( 968B, CDB4 ) FE ( CDB4, B230 ) 00 ( B230, B799 ) 00 ( B799, 4E3C ) 01 ( 4E3C, 852B ) 02 ( 852B, CA6F ) CA ( CA6F, 6F00 ) 6F ( 6F00, 0000 ) TMP: 0000 CRC OK
Код:CRC-16 width=16 poly=0x1021 init=0xFFFF refin=false refout=false xorout=0x0000 check=0x29B1
Последний раз редактировалось Patron; 14.12.2013 в 00:57.
Все, привел я к обычному делению на полином. Нужно просто было понять что же реально делится и подавать фактическую последовательность делимого:
где - crc16_m2() - обычное деление на полином, с вдвиганием бита данных в младший разряд. Контрольные суммы совпадают, все выкладки полностью подтвердились.Код:crc = 0; crc = crc16_m2(crc, 0xA1 ^ 0xFF); crc = crc16_m2(crc, 0xA1 ^ 0xFF); crc = crc16_m2(crc, 0x30); crc = crc16_m2(crc, 0x31); crc = crc16_m2(crc, 0x32); crc = crc16_m2(crc, 0x33); crc = crc16_m2(crc, 0x00); crc = crc16_m2(crc, 0x00);
Код:unsigned short int crc16_m2(unsigned short crc, unsigned char data) { int i; printf("\n %02X ( %04X,", data, crc); for(i=0; i<8; i++) { if (crc & 0x8000) { crc <<= 1; crc |= (data >> 7) & 1; crc ^= 0x1021; } else { crc <<= 1; crc |= (data >> 7) & 1; } data <<= 1; } printf(" %04X )", crc ); return crc; }
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)