Предлагаю немного освежить тему - Цифровая археология 1801: неудержимое диско 128
Кстати, Alex_K, спасибо Вам за посты в этой теме - они мне очень помогли при реверсе, и очень много из сказанного Вами подтвердилось полностью.
Вид для печати
Предлагаю немного освежить тему - Цифровая археология 1801: неудержимое диско 128
Кстати, Alex_K, спасибо Вам за посты в этой теме - они мне очень помогли при реверсе, и очень много из сказанного Вами подтвердилось полностью.
В описании ВП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
По идее - он должен перебирать биты каждого записываемого слова от старшего к младшему ( в порядке их расположения на диске ).
Update:
Я тут начал моделировать запись сектора, выявил еще один косяк ВП1-128, она оказывается бит готовности данных ставит сильно заранее (до момента перенесения старшего байта из регистра данных в сдвиговый регистр), и если быстрая шина МПИ (как в используемой сейчас модели процессора - он пишет-читает максимально быстро), то она успевает переписать регистр данных быстрее чем из него успевает переписаться старший байт в сдвиговый регистр (потому что увидела раннюю готовность). Сейчас ввел в транзакции МПИ задержки, будут результаты - отпишу.
Контроллеры 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. Произойдёт что-то ещё..
Установка бита WM игнорируется, достаточно обнаружения 0xA1 в сдвиговом регистре.
Я сейчас выполил такое моделирование:
На выходе записываемых данных получилось:Код:qbus_write(16'O177130, 16'O000000);
qbus_write(16'O177132, 16'H0000);
qbus_waitr();
qbus_write(16'O177132, 16'H0000);
qbus_waitr();
qbus_write(16'O177132, 16'HA1A1);
qbus_waitr();
qbus_write(16'O177132, 16'H3130);
qbus_waitr();
qbus_write(16'O177132, 16'H3332);
qbus_waitr();
Вот текст программки которая соответствует извлеченному алгоритму:Код:0x00
0x00
0x00
0x00
0xA1 (в этот момент обнулился регистр CRC и началось вычисление с этого маркера, еще я пробовал писать снова 0xA1A1 но сброса боьлше не было - это однократный процесс после перехода от чтения к записи)
0xA1
0x30 (то есть, сначала МЛАДШИЙ байт, старший бит первым)
0x31 (то есть, потом СТАРШИЙ байт, старший бит первым)
0x32
0x33 (после этого байта содержимое регистра CRC = 0x6EE9)
0x91 (инвертированное 0x6E. Сначала пишется СТАРШИЙ байт инвертированной суммы)
0x16 (инвертированное 0xE9. Потом пишется МЛАДШИЙ байт инвертированной суммы)
(она отличается от канонического вида - на инверсию влияет XOR входного бита и выдвигаемого):
Код:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
unsigned short int crc16(unsigned short crc, unsigned char data)
{
int i, bit;
printf("\r\n %02X(%04X,", data, crc);
for(i=0; i<8; i++)
{
bit = (data >> 7) & 1;
if (crc & 0x8000)
{
bit ^= 1;
}
crc <<= 1;
crc |= bit;
if (bit == 0)
{
crc ^= 0x1020;
}
data <<= 1;
}
printf("%04X)", crc);
return crc;
}
int main(int argc, char *argv[])
{
unsigned short crc, tmp;
crc = 0;
crc = crc16(crc, 0xA1);
crc = crc16(crc, 0xA1);
crc = crc16(crc, 0x30);
crc = crc16(crc, 0x31);
crc = crc16(crc, 0x32);
crc = crc16(crc, 0x33);
tmp = ~crc;
printf("\r\nCRC: %04X", tmp);
crc = 0;
crc = crc16(crc, 0xA1);
crc = crc16(crc, 0xA1);
crc = crc16(crc, 0x30);
crc = crc16(crc, 0x31);
crc = crc16(crc, 0x32);
crc = crc16(crc, 0x33);
crc = crc16(crc, (tmp >> 8) & 0xFF);
crc = crc16(crc, (tmp >> 0) & 0xFF);
printf("\r\nTMP: %04X", crc);
if (crc == 0xFFFF) printf(" CRC OK");
printf("\r\n");
return 0;
}
Да (промоделировал, заменил в примере выше A1 на A2), будет выполнена запись, но поскольку регистр CRC не был правильно проинициализирован нулем, запишется два мусорных байта (взависимости что там в регистре CRC было при начале записи)Цитата:
2. Если генератор CRC в ходе записи не был запущен - будет ли выполнена запись CRC ( 0xFFFF ) в момент пропуска требования ?
Похоже что тут ситуация такая - CRC читается как обычные данные, и после того как они прочитаны просто проверяется регистра CRC на 0xFFFF. Невыполнение требования (чтения) просто приводит к защелкиванию признака CRC_VALID и дальнейшее вычисление СRC на потоке вычисляемых данных уже никак на этот признак не влияет. То есть - просто идет поток данных чтения, без разбора - CRC/данные. Как только прекратили выполнять требование чтения - защелкнулся признак VALID (триггер J34) и дальше хранится, а поток продолжает обрабатываться, регистр CRC изменяется итд.Цитата:
Также ( если я правильно понял ) при чтении CRC проверяется так - если требование выполнено, то содержимое регистра данных интерпретируется как данные и включается в расчёт CRC, если же требование не выполнено - содержимое регистра данных интерпретируется как CRC, прибавляется к рассчитанному значению CRC и результат проверяется на равенство 0xFFFF.
Т.е. запуск генератора CRC в режиме записи происходит после первого байта 0xA1 в сдвиговом регистре, перезапуск не происходит никогда, а остановка ( и запись инверсного значения CRC на диск ) происходит при пропуске требования.
---------- Post added at 13:53 ---------- Previous post was at 13:47 ----------
Получается, что:
1. Запуск генератора CRC при чтении происходит в режиме поиска маркера по первому байту 0xA1 в сдвиговом регистре.
2. В процессе чтения признак CRC_VALID непрерывно отражает равенство текущего значения CRC величине 0xFFFF.
3. Повторное чтение маркера не сбрасывает генератор CRC. Чтобы перевести ВП1-128 в режим поиска маркера - нужно записать в регистр статуса бит "начало чтения" ( 8 ).
Сообщение от Vslav
Вот и верь после этого описаниям.Цитата:
Я сейчас выполил такое моделирование:На выходе записываемых данных получилось:Код:qbus_write(16'O177132, 16'H3130);
Код:0x30 (то есть, сначала МЛАДШИЙ байт, старший бит первым)
0x31 (то есть, потом СТАРШИЙ байт, старший бит первым)
Значит, хотя в описании ВП1-128 написано:Но на самом деле - первым пишется младший байт регистра данных, а требование выставляется при копировании в сдвиговый регистр старшего байта регистра данных.Код:В режиме 'запись' 7-й разряд РС (TR) устанавливается в единицу
после того, как младший байт РДЗ переписался в сдвиговый регистр.
---------- Post added at 14:25 ---------- Previous post was at 14:12 ----------
Здесь написано так:Получается, что и там в описании ошибка и сначала сохраняется младший байт, а затем старший данных.Цитата:
шестнадцатибитный регистр данных чтения принимает два байта данных из сдвигового регистра. В процессе считывания данных с диска сначала сохраняется старший байт, затем младший данных.
Так ?
---------- Post added at 14:35 ---------- Previous post was at 14:25 ----------
Сообщение от VslavНо если слово контрольной суммы пишется в обратном порядке байтов относительно слов данных, то как порядок байтов при чтении получается для всех слов одинаковым ?Код:0x91 (инвертированное 0x6E. Сначала пишется СТАРШИЙ байт инвертированной суммы)
0x16 (инвертированное 0xE9. Потом пишется МЛАДШИЙ байт инвертированной суммы)