PDA

Просмотр полной версии : Планирую сделать FDD эмулятор на Atmega8



Страницы : [1] 2 3

EvgenRU
20.03.2016, 13:15
В связи с тем, что существующие решения достаточно сложные и дорогостоящие возникла идея сделать максимально дешевый, простой и при этом достаточно функциональный девайс на Atmega8.

После обсуждений решено, что проект будет реализовываться на Arduino! :)

Проект уже работает на Arduino с SD картой! Поддерживается только чтение, записи нет!

Внимание, при использовании Arduino Pro Mini пины RX/TX расположены наоборот!

Исходники проекта на GitHub: https://github.com/EvgeniyRU/ZX_FDD_Emulator Схема подключения находится там же.
В GitHub можно скачать любую предыдущую версию прошивки выбрав в списке коммитов https://github.com/EvgeniyRU/ZX_FDD_Emulator/commits/master нужный коммит, затем Browse Files (справа), затем Clone or Download и после Download ZIP

В последних версиях работа ведется с SD/SDHC/MMC картой, файловая система FAT32, поддерживаются карты от 512Мб до 32Гб, больше не проверялись. Данные берутся из TRD образов, дисплей 1602.


За основу взята следующая спецификация флопа FD1035_Product_Description_Jul84.pdf (http://bitsavers.trailing-edge.com/pdf/nec/FD1035_Product_Description_Jul84.pdf).
Еще вот этот документ принимается во внимание http://www.mcamafia.de/pdf/ps2_fdd_trm_s42g2194_00.pdf

Насколько я понимаю, работа с устройством происходит по сигналам

1. DRIVE SELECT выбирает нужное устройство из 4-ех DS0-DS3, на нужном устанавливается уровень LOW (INPUT)
2. STEP двигает голову на дорожку вперед/назад в зависимости от сигнала DIRECTION (INPUT)
3. DIRECTION - направление движения головок HIGH - к центру, LOW - к краю (track 0).
4. SIDE SELECT выбирает сторону HIGH - Head 0, LOW - Head 1 (INPUT)
5. WRITE GATE определяет ЧТЕНИЕ[HIGH]/ЗАПИСЬ[LOW] (INPUT)
6. WRITE DATA данные которые записываются на дискету (INPUT)
7. MOTOR ON - запуск шпинделя LOW запуск, HIGH останов (INPUT)
8. TRK00 - генерируется, если головка на нулевой дорожке, LOW означает, что мы на нулевой дорожке (OUTPUT)
9. READY - насколько я понял, для ZX не актуален (OUTPUT) ***
10. READ DATA - данные считываемые с дискеты и отправляемые в BDI (OUTPUT) формат MFM
11. WRITE PROTECT - генерируется для защиты от записи (LOW), на этапе разработки он всегда будет генерироваться, пока не заработает чтение нормально, потом уже перейду к разработке записи, если это будет представляться возможным. (OUTPUT)

Принцип работы устройства (насколько я пока что понимаю)

1. Читаем нулевой цилиндр, вычисляем CRC для секторов нижней и верхней дорожки, выставляем TRK00
(можно вычислить CRC для всех дорожек при монтировании)

2. Организуется цикл c выходом на повтор, если нужный нам DS в положении HIGH
Как только он стал LOW и MOTOR ON - LOW начинаем обрабатывать

3. Обработчик
a) Вешаем пин STEP на прерывание.
b) Методично (циклично) шлем данные дорожки посекторно в READ DATA в формате MFM, пульсируя INDEX в начале отправки дорожки
b2) После отправки сектора проверяем DS и MOTOR ON, если не наши значения, отключаем прерывания, переходим на пункт 2
------------------------
Функция STEP (в обработчике прерывания)
1. Проверяем DIRECTION, HIGH - увеличиваем дорожку (прибавляем к смещению 8192 байт), LOW - проверяем, если дорожка больше нуля - уменьшаем (вычитаем 8192 байт), если дорожка стала = 0, ставим TRACK00 в LOW.
2. Если трек изменился ставим флаг об изменении трека.
3. Выходим из прерывания.



Вроде с виду всё просто, но есть много вопросов.

1. Где посмотреть формат передаваемых данных (READ DATA, WRITE DATA) Уже разобрался
2. Как происходят операции с секторами, пишется/читается вся дорожка целиком? С этим тоже разобрался
3. Почему вход SIDE пульсирует? (тоже разобрался, в процессе чтения сторона может измениться в любой момент)

То что уже нашел буду отмечать красным, то что уже неактуально зеленым.

Информацию по сигналам возьму отсюда http://zx-pk.ru/showthread.php?t=1262&p=825463&viewfull=1#post825463


Нашел еще интересную информацию:
http://www.avrfreaks.net/comment/328274#comment-328274


PS: по форматам дорожек нашел инфу, есть в экселевском файле по ссылке про сигналы, но в книжке Ларченко и Родионова приводится немного другая инфа http://zxpress.ru/book_articles.php?id=1868 http://zxpress.ru/article.php?id=8992 Кому верить? (оказалось, формат может немного отличаться)


PS2: Так в целом понятно по формату дороги, если смотреть по экселю, там для адресного поля CRC можно заранее табличку сделать в коде прошивки, данные подсовываются в поле данных, с этим тоже не сложно, 256 байт можно в памяти хранить и считывать следующие перед генерацией INDEX, вот CRC для поля данных налету генерировать это уже сложнее, хотя в процессе отправки думаю можно успеть, а можно и при открытии образа сгенерировать, но налету кажется это сделать проще.
Налету оказалось достаточно просто генерировать CRC по таблице размещенной во Flash памяти

PS3: пожалуй начну с того, что буду генерировать пустой образ дискеты, т.е. чистой отформатированной, если диск доктор начнет читать нормально нули в секторах, то буду двигаться дальше. Это было сделано достаточно быстро :)

Вот, кстати, откуда ноги растут
56523

Окончательный вариант формата дорожки, в конце дорожки 598 байт это крайний случай, реально конечно будет меньше
56524
ВНИМАНИЕ!!! В описании дорожки данные в ячейках A1 и C2 являются командами контроллера дисковода! Т.е. на их месте в закодированном виде должны быть значения 0x4489 и 0x5224 соответственно

Генерация CRC16 для Адресного поля и Поля данных
Используется CRC-CCITT нач. значение 0xFFFF, полином 0x1021. Кодируются данные вместе с A1 и маркером, начиная с первого значения 0xA1, т.е. используется именно A1!!!



Снял диаграмму сигналов на лог анализаторе, вот уменьшенная версия, чтобы примерно понять, что и как происходит, на картинке второй STEP это SIDE.
56526

Выходит, по приходу сигнала MOTOR ON дисковод начинает слать данные в READ DATA без перерыва :) и WG и WD стоят неактивные в режиме чтения, так что всё еще проще оказалось.

Расписываю основные времянки, снимал на частоте 1МГц:
INDEX - LOW - 3.52ms, между индексами HIGH примерно 196ms, погрешность 0.1%
MOTOR активен LOW пока требуется чтение
WR GATE, WR DATA всегда не активны HIGH в режиме чтения
TRK00 всегда выставлено LOW после прихода MOTOR ON
STEP период четко 3мс, пульс 1-2мкс

READ DATA пульсирует LOW на время 1мкс, вот как выглядит
56527
Интервал окна составляет 4, 6 и 8 мкс


ВАЖНО! По поводу кодирования в MFM отличная инфа здесь http://firmware.altervista.org/Data%20Encoding%20and%20Decoding.htm и тут http://info-coach.fr/atari/hardware/FD-Hard.php#Example_of_CRC_Code

Вот из этой картинки становится понятно, что и как кодируется http://info-coach.fr/atari/hardware/_fd-hard/pictures/read_data.png
http://info-coach.fr/atari/hardware/_fd-hard/pictures/MFM%20Example.png
http://www.tpub.com/neets/book23/0070.GIF


Схема кодирования такая

Например, есть байт 0xC6 - 1100 0110

Если бит данных равен 1, то он заменяется на 01
Если бит данных равен 0, предыдущий бит равен 0, то он заменяется на 10
Если бит данных равен 0, предыдущий бит равен 1, то он заменяется на 00

Кодированными данными будет значение |01|01|00|10|10|01|01|00|

Разбиваем это по биту 1, получаем 10, 100, 10, 100, 10, 100

На выходе получаем сигналы такой последовательности:
4мкс(10), 6мкс(100), 4мкс(10), 6мкс(100), 4мкс(10), 6мкс(100)

Остается только скорректировать первый бит последовательности в потоке данных, если старший бит равен 0, то проверить младший предыдущего, и на основе этого скорректировать.

Получается такая схема, если встретилась единица в потоке данных, то опускаем уровень в LOW на 1мкс, затем поднимаем и ждем 1мкс, если встретился ноль, то просто ждем 2мкс, всё оооочень просто :)

Кодировать данные проще всего по таблице ОБНОВЛЕНА 28.03.2016

0xAAAA, 0xAAA9, 0xAAA4, 0xAAA5, 0xAA92, 0xAA91, 0xAA94, 0xAA95,
0xAA4A, 0xAA49, 0xAA44, 0xAA45, 0xAA52, 0xAA51, 0xAA54, 0xAA55,
0xA92A, 0xA929, 0xA924, 0xA925, 0xA912, 0xA911, 0xA914, 0xA915,
0xA94A, 0xA949, 0xA944, 0xA945, 0xA952, 0xA951, 0xA954, 0xA955,
0xA4AA, 0xA4A9, 0xA4A4, 0xA4A5, 0xA492, 0xA491, 0xA494, 0xA495,
0xA44A, 0xA449, 0xA444, 0xA445, 0xA452, 0xA451, 0xA454, 0xA455,
0xA52A, 0xA529, 0xA524, 0xA525, 0xA512, 0xA511, 0xA514, 0xA515,
0xA54A, 0xA549, 0xA544, 0xA545, 0xA552, 0xA551, 0xA554, 0xA555,
0x92AA, 0x92A9, 0x92A4, 0x92A5, 0x9292, 0x9291, 0x9294, 0x9295,
0x924A, 0x9249, 0x9244, 0x9245, 0x9252, 0x9251, 0x9254, 0x9255,
0x912A, 0x9129, 0x9124, 0x9125, 0x9112, 0x9111, 0x9114, 0x9115,
0x914A, 0x9149, 0x9144, 0x9145, 0x9152, 0x9151, 0x9154, 0x9155,
0x94AA, 0x94A9, 0x94A4, 0x94A5, 0x9492, 0x9491, 0x9494, 0x9495,
0x944A, 0x9449, 0x9444, 0x9445, 0x9452, 0x9451, 0x9454, 0x9455,
0x952A, 0x9529, 0x9524, 0x9525, 0x9512, 0x9511, 0x9514, 0x9515,
0x954A, 0x9549, 0x9544, 0x9545, 0x9552, 0x9551, 0x9554, 0x9555,
0x4AAA, 0x4AA9, 0x4AA4, 0x4AA5, 0x4A92, 0x4A91, 0x4A94, 0x4A95,
0x4A4A, 0x4A49, 0x4A44, 0x4A45, 0x4A52, 0x4A51, 0x4A54, 0x4A55,
0x492A, 0x4929, 0x4924, 0x4925, 0x4912, 0x4911, 0x4914, 0x4915,
0x494A, 0x4949, 0x4944, 0x4945, 0x4952, 0x4951, 0x4954, 0x4955,
0x44AA, 0x44A9, 0x44A4, 0x44A5, 0x4492, 0x4491, 0x4494, 0x4495,
0x444A, 0x4449, 0x4444, 0x4445, 0x4452, 0x4451, 0x4454, 0x4455,
0x452A, 0x4529, 0x4524, 0x4525, 0x4512, 0x4511, 0x4514, 0x4515,
0x454A, 0x4549, 0x4544, 0x4545, 0x4552, 0x4551, 0x4554, 0x4555,
0x52AA, 0x52A9, 0x52A4, 0x52A5, 0x5292, 0x5291, 0x5294, 0x5295,
0x524A, 0x5249, 0x5244, 0x5245, 0x5252, 0x5251, 0x5254, 0x5255,
0x512A, 0x5129, 0x5124, 0x5125, 0x5112, 0x5111, 0x5114, 0x5115,
0x514A, 0x5149, 0x5144, 0x5145, 0x5152, 0x5151, 0x5154, 0x5155,
0x54AA, 0x54A9, 0x54A4, 0x54A5, 0x5492, 0x5491, 0x5494, 0x5495,
0x544A, 0x5449, 0x5444, 0x5445, 0x5452, 0x5451, 0x5454, 0x5455,
0x552A, 0x5529, 0x5524, 0x5525, 0x5512, 0x5511, 0x5514, 0x5515,
0x554A, 0x5549, 0x5544, 0x5545, 0x5552, 0x5551, 0x5554, 0x5555,



0x00:0xAAAA, 0x01:0xAAA9, 0x02:0xAAA4, 0x03:0xAAA5, 0x04:0xAA92, 0x05:0xAA91, 0x06:0xAA94, 0x07:0xAA95,
0x08:0xAA4A, 0x09:0xAA49, 0x0A:0xAA44, 0x0B:0xAA45, 0x0C:0xAA52, 0x0D:0xAA51, 0x0E:0xAA54, 0x0F:0xAA55,
0x10:0xA92A, 0x11:0xA929, 0x12:0xA924, 0x13:0xA925, 0x14:0xA912, 0x15:0xA911, 0x16:0xA914, 0x17:0xA915,
0x18:0xA94A, 0x19:0xA949, 0x1A:0xA944, 0x1B:0xA945, 0x1C:0xA952, 0x1D:0xA951, 0x1E:0xA954, 0x1F:0xA955,
0x20:0xA4AA, 0x21:0xA4A9, 0x22:0xA4A4, 0x23:0xA4A5, 0x24:0xA492, 0x25:0xA491, 0x26:0xA494, 0x27:0xA495,
0x28:0xA44A, 0x29:0xA449, 0x2A:0xA444, 0x2B:0xA445, 0x2C:0xA452, 0x2D:0xA451, 0x2E:0xA454, 0x2F:0xA455,
0x30:0xA52A, 0x31:0xA529, 0x32:0xA524, 0x33:0xA525, 0x34:0xA512, 0x35:0xA511, 0x36:0xA514, 0x37:0xA515,
0x38:0xA54A, 0x39:0xA549, 0x3A:0xA544, 0x3B:0xA545, 0x3C:0xA552, 0x3D:0xA551, 0x3E:0xA554, 0x3F:0xA555,
0x40:0x92AA, 0x41:0x92A9, 0x42:0x92A4, 0x43:0x92A5, 0x44:0x9292, 0x45:0x9291, 0x46:0x9294, 0x47:0x9295,
0x48:0x924A, 0x49:0x9249, 0x4A:0x9244, 0x4B:0x9245, 0x4C:0x9252, 0x4D:0x9251, 0x4E:0x9254, 0x4F:0x9255,
0x50:0x912A, 0x51:0x9129, 0x52:0x9124, 0x53:0x9125, 0x54:0x9112, 0x55:0x9111, 0x56:0x9114, 0x57:0x9115,
0x58:0x914A, 0x59:0x9149, 0x5A:0x9144, 0x5B:0x9145, 0x5C:0x9152, 0x5D:0x9151, 0x5E:0x9154, 0x5F:0x9155,
0x60:0x94AA, 0x61:0x94A9, 0x62:0x94A4, 0x63:0x94A5, 0x64:0x9492, 0x65:0x9491, 0x66:0x9494, 0x67:0x9495,
0x68:0x944A, 0x69:0x9449, 0x6A:0x9444, 0x6B:0x9445, 0x6C:0x9452, 0x6D:0x9451, 0x6E:0x9454, 0x6F:0x9455,
0x70:0x952A, 0x71:0x9529, 0x72:0x9524, 0x73:0x9525, 0x74:0x9512, 0x75:0x9511, 0x76:0x9514, 0x77:0x9515,
0x78:0x954A, 0x79:0x9549, 0x7A:0x9544, 0x7B:0x9545, 0x7C:0x9552, 0x7D:0x9551, 0x7E:0x9554, 0x7F:0x9555,
0x80:0x4AAA, 0x81:0x4AA9, 0x82:0x4AA4, 0x83:0x4AA5, 0x84:0x4A92, 0x85:0x4A91, 0x86:0x4A94, 0x87:0x4A95,
0x88:0x4A4A, 0x89:0x4A49, 0x8A:0x4A44, 0x8B:0x4A45, 0x8C:0x4A52, 0x8D:0x4A51, 0x8E:0x4A54, 0x8F:0x4A55,
0x90:0x492A, 0x91:0x4929, 0x92:0x4924, 0x93:0x4925, 0x94:0x4912, 0x95:0x4911, 0x96:0x4914, 0x97:0x4915,
0x98:0x494A, 0x99:0x4949, 0x9A:0x4944, 0x9B:0x4945, 0x9C:0x4952, 0x9D:0x4951, 0x9E:0x4954, 0x9F:0x4955,
0xA0:0x44AA, 0xA1:0x44A9, 0xA2:0x44A4, 0xA3:0x44A5, 0xA4:0x4492, 0xA5:0x4491, 0xA6:0x4494, 0xA7:0x4495,
0xA8:0x444A, 0xA9:0x4449, 0xAA:0x4444, 0xAB:0x4445, 0xAC:0x4452, 0xAD:0x4451, 0xAE:0x4454, 0xAF:0x4455,
0xB0:0x452A, 0xB1:0x4529, 0xB2:0x4524, 0xB3:0x4525, 0xB4:0x4512, 0xB5:0x4511, 0xB6:0x4514, 0xB7:0x4515,
0xB8:0x454A, 0xB9:0x4549, 0xBA:0x4544, 0xBB:0x4545, 0xBC:0x4552, 0xBD:0x4551, 0xBE:0x4554, 0xBF:0x4555,
0xC0:0x52AA, 0xC1:0x52A9, 0xC2:0x52A4, 0xC3:0x52A5, 0xC4:0x5292, 0xC5:0x5291, 0xC6:0x5294, 0xC7:0x5295,
0xC8:0x524A, 0xC9:0x5249, 0xCA:0x5244, 0xCB:0x5245, 0xCC:0x5252, 0xCD:0x5251, 0xCE:0x5254, 0xCF:0x5255,
0xD0:0x512A, 0xD1:0x5129, 0xD2:0x5124, 0xD3:0x5125, 0xD4:0x5112, 0xD5:0x5111, 0xD6:0x5114, 0xD7:0x5115,
0xD8:0x514A, 0xD9:0x5149, 0xDA:0x5144, 0xDB:0x5145, 0xDC:0x5152, 0xDD:0x5151, 0xDE:0x5154, 0xDF:0x5155,
0xE0:0x54AA, 0xE1:0x54A9, 0xE2:0x54A4, 0xE3:0x54A5, 0xE4:0x5492, 0xE5:0x5491, 0xE6:0x5494, 0xE7:0x5495,
0xE8:0x544A, 0xE9:0x5449, 0xEA:0x5444, 0xEB:0x5445, 0xEC:0x5452, 0xED:0x5451, 0xEE:0x5454, 0xEF:0x5455,
0xF0:0x552A, 0xF1:0x5529, 0xF2:0x5524, 0xF3:0x5525, 0xF4:0x5512, 0xF5:0x5511, 0xF6:0x5514, 0xF7:0x5515,
0xF8:0x554A, 0xF9:0x5549, 0xFA:0x5544, 0xFB:0x5545, 0xFC:0x5552, 0xFD:0x5551, 0xFE:0x5554, 0xFF:0x5555

В таблице предполагается, что последний бит предыдущего байта данных был равен 0! Поэтому, если это не так, то нужно корректировать старший бит, если старший бит текущего байта данных равен нулю!


ПОСЛЕДНИЕ ИССЛЕДОВАНИЯ ПОКАЗАЛИ, ЧТО ДАННЫЙ ШАГ МОЖНО ОПУСТИТЬ!!! Т.Е. бит можно не исправлять!!!

Самые последние исследования показали, что достаточно менять 1 на 01, а 0 на 10 (для инвертированного сигнала наоборот) и контроллер такой сигнал нормально хавает через Master SPI :)
ВНИМАНИЕ! Вышесказанное справедливо только для ВГ93!!! Если у вас другой контроллер (импортный), то, скорее всего, придется делать полное MFM кодирование, что, в принципе, делается в последних версиях прошивки.

Сигнал генерируется с использованием USART в режиме MasterSPI (поддерживается контроллерами Atmega48/88/168/328, может еще какими-то но точно не Atmega8,128...) Затем сигнал инвертируется (проще всего программно) на выходе получается код, совместимый с MFM.

Пример


uint8_t MFM_tab[32] =
{
0xAA,0xA9,0xA4,0xA5,0x92,0x91,0x94,0x95,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
0x2A,0x29,0x24,0x25,0x12,0x11,0x14,0x15,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
};

first_mfm_byte = sector_byte; // current data byte
first_mfm_byte >>= 4;
first_mfm_byte = MFM_tab[first_mfm_byte]; // get first MFM byte from table
if((prev_byte & 1) && !(sector_byte & 0x80)) first_mfm_byte &= 0x7F;

prev_byte = sector_byte;

second_mfm_byte = sector_byte & 0x1f;
second_mfm_byte = MFM_tab[second_mfm_byte]; // get second MFM byte from table

Спасибо за комментарии.

CodeMaster
20.03.2016, 21:09
возникла идея сделать максимально дешевый, простой и при этом достаточно функциональный девайс на Atmega8

Помочь ничем не могу, но идею плюсую ;-)

Trol73
20.03.2016, 21:22
Вангую, что сейчас тут появятся советы на тему того, что вместо AVR лучше взять ARM, ПЛИС или core i7 :)
atmega8 - это однозначно мало для нормального эмулятора FDD. Советую сразу смотреть в сторону atmega128 - масса преимуществ и ни одного недостатка.

s_kosorev
20.03.2016, 22:11
нужно цилинд в памяти держать при смене трека, меги8 не хватит, а нужно потому что "диск" крутится, данные постоянно должны быть, а sd они такие, могут в любое время задуматься, иногда существенно для рилтайма

EvgenRU
20.03.2016, 22:18
нужно цилинд в памяти держать при смене трека, меги8 не хватит, а нужно потому что "диск" крутится, данные постоянно должны быть, а sd они такие, могут в любое время задуматься, иногда существенно для рилтайма

У 8 атмеги 1К SRAM, цилиндр вроде 512байт, так что может и получится, после смены трека есть 17мс для чтения следующего, а если учесть, что INDEX генерируется через 200мс после этого, то и все 217мс, а вот при смене стороны, действительно, нет задержки никакой.

IanPo
20.03.2016, 22:29
MFM-цилиндр<=12800 байт *2 = 25600
Для поддержки файловой системы карточки также требуется память
HFE-формат отличается от MFM, в основном тем, что там биты реверсированы уже и цилиндры поделены на 512-байтовые блоки, что удобно для МК с малым размером ОЗУ

Trol73
20.03.2016, 22:31
Если надо работать с SD-картой в режиме реального времени, то нужно два буфера минимум по 512 байт (512 - размер сектора на SD карте). Из одного буфера данные берём, в другой читаем с карты в фоновом режиме. Т.е., МК должен иметь не менее 2КБ памяти, т.е., нужна как минимум atmega32.
Писать лучше всего на С с ассемблерными вставками.
Но если хочется сделать действительно хороший эмулятор, то 32кб флеша однозначно не хватит.

EvgenRU
21.03.2016, 07:38
Petit FatFs не требует много памяти при чтении, при смене дорожки вполне можно успеть считать данные по SPI в буфер сектора, особенно, если карта быстрая. У меня есть модуль на C с вырезанной кучей всего ненужного из Petit, так что он работает очень быстро, но нужна карта класса 10 (таких сейчас полно).

Пока что есть 2 непонятных момента по этой диаграмме.
56528

1. Почему SIDE начинает колбасить ?
2. Все-таки в каком формате идет поток бит с READ DATA ?

На второй пункт нашел ответ здесь
http://firmware.altervista.org/Data%20Encoding%20and%20Decoding.htm
Каждый бит данных кодируется как 2 бита RN, NN, NR. И еще про MFM тут http://www.spas-info.ru/stati/14-chastotnaya-modulyatsiya-v-kodirovanii-informatsii-dlya-magnitnykh-nositelej

- - - Добавлено - - -


MFM-цилиндр<=12800 байт *2 = 25600
Для поддержки файловой системы карточки также требуется память
HFE-формат отличается от MFM, в основном тем, что там биты реверсированы уже и цилиндры поделены на 512-байтовые блоки, что удобно для МК с малым размером ОЗУ

Уже ответил про карточку.
Насчет размера цилиндра, где-то читал инфу, что сырой MFM трэк имеет длину 6300 байт, т.е. цилиндр 12600 получается
Но я не буду писать цилиндр. У меня данные будут из TRD, это сильно упрощает задачу. Остальные данные будут браться из области кода прошивки в том числе CRC адресного поля. CRC данных буду генерироваться налету в процессе сдвига бит данных.

- - - Добавлено - - -

Получается, дискета крутится со скоростью 300 оборотов в минуту, т.е. 5 оборотов в секунду, кластер в идеальных условиях должен считываться примерно за пол секунды - секунду, чего вполне достаточно. А если еще учесть, что при отсутствии сектора на обороте делается еще несколько попыток его чтения, то можно на одном обороте подсовывать не все сектора, будет работать медленнее чем настоящий флоп, но зато будет! Хотя конечно проще мегу пожирнее поставить...

ZXFanat
21.03.2016, 09:14
Вангую, что сейчас тут появятся советы на тему того, что вместо AVR лучше взять ARM, ПЛИС или core i7 :)
atmega8 - это однозначно мало для нормального эмулятора FDD. Советую сразу смотреть в сторону atmega128 - масса преимуществ и ни одного недостатка.
Поддерживаю, но не вмешиваюсь. Тогда уж делать на два варианта!

Trol73
21.03.2016, 09:58
... А если еще учесть, что при отсутствии сектора на обороте делается еще несколько попыток его чтения, то можно на одном обороте подсовывать не все сектора, будет работать медленнее чем настоящий флоп, но зато будет! Хотя конечно проще мегу пожирнее поставить...
Т.е., первичная цель чисто спортивная - показать, что на atmega8 можно сделать эмулятор флопа который работает? Функциональность не принципиальна?


Насколько я понимаю, работа с устройством происходит по сигналам ...
У atmega8 20 пинов (если предполагается использовать ISP-программатор). Если 11 пинов уйдет на интерфейс FDD + еще 7 на дисплей 1602, без подствеки + 1 на клавиатуру. Тогда останется 1 свободный вывод. Для светодиода, например. А для SD-карты надо ещё минимум 3 (но скорее все же 4) пина (а ещё лучше все 5).

По RAM- и flash-памяти все тоже получается на пределе. Т.е., если что-то из atmega8 получится, то это обещает быть шедевром с точки зрения разработки и программирования, но не с точки зрения юзабельности.

s_kosorev
21.03.2016, 10:21
Petit FatFs не требует много памяти при чтении, при смене дорожки вполне можно успеть считать данные по SPI в буфер сектора, особенно, если карта быстрая.
он в минимальном режиме 44байт оперативки, постоянно читает FAT, т.е. очень медленно, по идее нужно сразу вычитать все номера кластеров в память, что бы быстро сектор нужный находить

- - - Добавлено - - -

либо при шаге с трека не трек, можно только кластера текущего цилиндра получить, операция шага по трекам достаточно медленная, если другие варианты не приемлемы, вкладывать логику именно в эти промежутки

EvgenRU
21.03.2016, 10:25
Т.е., первичная цель чисто спортивная - показать, что на atmega8 можно сделать эмулятор флопа который работает? Функциональность не принципиальна?
Первичная цель - разобраться как работает флопик, ну и сделать решение попроще/подешевле, без доп обвязки логикой.



У atmega8 20 пинов (если предполагается использовать ISP-программатор). Если 11 пинов уйдет на интерфейс FDD + еще 7 на дисплей 1602, без подствеки + 1 на клавиатуру. Тогда останется 1 свободный вывод. Для светодиода, например. А для SD-карты надо ещё минимум 3 (но скорее все же 4) пина (а ещё лучше все 5).

По RAM- и flash-памяти все тоже получается на пределе. Т.е., если что-то из atmega8 получится, то это обещает быть шедевром с точки зрения разработки и программирования, но не с точки зрения юзабельности.

Для дисковода в режиме чтения требуется всего 8 пинов (DS, INDEX, MOTORON, STEP, DIR, RDT, SIDE, TRK0) при поддержке записи 10 пинов (+WDT и WGT), DS и MOTOR можно вынести на логику конечно или на диоды, но это в крайнем случае. DS0-DS3 переключаются джампером и преобразуются во вход DS.

У атмеги8 18 пинов, если использовать кристалл, 8 пинов уйдет на чтение, 3 пина уйдет на карточку, считаю нецелесообразным использовать пин под CS карты. 6 пинов на экран, подсветка и RW пойдут на +5в. Остается 1-2 пина под кнопки :) Тут еще нужно будет подумать...

s_kosorev
21.03.2016, 10:29
цилиндр вроде 512байт
цилинд это сумма всех секторов в случае TRD, то есть что то около 5кб * 2 стороны

- - - Добавлено - - -

по дисплеям, в крайнем случае можно с SPI интерфейсом, это всего 2 доп CS что бы разделить карту и дисплей 5 пинов на карту + дисплей

EvgenRU
21.03.2016, 10:32
цилинд это сумма всех секторов в случае TRD, то есть что то около 5кб * 2 стороны

по дисплеям, в крайнем случае можно с SPI интерфейсом, это всего 2 доп CS что бы разделить карту и дисплей 5 пинов на карту + дисплей

Насчет цилиндра вчера еще разобрался, это 8к в случае TRD, чтоб его хранить нужно 128 атмегу еще и со SRAM....

Насчет SPI... в принципе, можно, т.к. индикация будет только при смене дорожки или в период неактивности, а можно и через сдвиговый регистр, тоже достаточно бюджетная вещь.

s_kosorev
21.03.2016, 10:38
то 8к в случае TRD, чтоб его хранить нужно 128 атмегу еще и со SRAM....
в теории, диск крутится, данные одновременно не фигурируют, можно как выше писали, по мере кручения диска подтягивать данные, 2 буфера по 512к, только тут главное что бы не наткнутся на подтормаживания SD

как по мне вместо mega128 уже есть смысл брать xmega, таже мега но чуть шустрее ядро, и всякого рода event и dma, что в теории может разгрузить ядро, но есть одно но! она на 1такт дольше на прерывания реагирует, могут быть вопросы со стороны шины компьютера

EvgenRU
21.03.2016, 10:43
как по мне вместо mega128 уже есть смысл брать xmega, таже мега но чуть шустрее ядро, и всякого рода event и dma, что в теории может разгрузить ядро, но есть одно но! она на 1такт дольше на прерывания реагирует, могут быть вопросы со стороны шины компьютера
Отличия в цене ОЧЕНЬ существенные, если Atmega128 можно взять в китаях за 60р, то xmega самая дешевая обойдется в 300р

Trol73
21.03.2016, 10:55
Первичная цель - разобраться как работает флопик, ну и сделать решение попроще/подешевле, без доп обвязки логикой.
Вот :) Если попроще/подешевле, то есть смысл посмотреть и сравнить на алиэкспрессе цены на mega8, mega32 и mega128. Разница стоимости МК в 10 рублей ведёт к многократному упрощению задачи )

EvgenRU
21.03.2016, 11:07
Наверное так и поступлю, есть атмеги128 и срам 512кб, всё по 60р :)

Окончательно разобрался со схемой кодирования в MFM (см первое сообщение), в связи с этим есть вопрос, как лучше это сделать.
Первое что приходит на ум, сделать в прошивке таблицу перекодировки байт в 16 битное значение и по ней кодировать, вроде как получается на порядок быстрее, чем генерировать клок и 2 байта налету.

Т.е. последовательность действий такова

1. Есть таблица перекодировки байт
2. Есть таблица CRC16 для адресного поля всех секторов
3. Открываем TRD, генерируем CRC16 для каждых 256 байт и помещаем в таблицу в SRAM
4. Шлем данные нулевой дорожки в READ DATA пока не пришел STEP или смена стороны
5. Читаем новую дорожку или переключаемся на другую сторону
6. Шлем данные новой дорожки, повторяем пункт 5 пока дисковод активен

Так же неплохо бы предусмотреть возможность работы с количеством секторов до 166 включительно, чтобы можно было защищенные дискеты открывать.

Trol73
21.03.2016, 11:31
Имхо, MFM лучше сразу сделать по таблице. А CRC16 можно попробовать для начала на лету считать. Потом, если где-то не хватит производительности, либо разбираться, либо ставить SRAM. По идее, тут одной меги128 должно хватить без внешней памяти (сужу по опыту разработки эмулятора магнитофона на ней).

s_kosorev
21.03.2016, 11:44
там несколько табличек будет в MFM на дискетах есть пропуски синхроимпульса, для разных меток

EvgenRU
21.03.2016, 12:34
там несколько табличек будет в MFM на дискетах есть пропуски синхроимпульса, для разных меток

Они уже учтены в таблице дорожки же 0xC2 заменяется на 0xF6, 0xA1 на 0xF5

CodeMaster
21.03.2016, 13:27
+ еще 7 на дисплей 1602

1602 можно управлять полубайтами, а если с параллельно/последовательным конвертером, то и по одному пину. Но, тут уже вопрос: потратить бакс на конвертер или доплатить за МК помощнее и "попинастее"

s_kosorev
21.03.2016, 13:30
Они уже учтены в таблице дорожки же 0xC2 заменяется на 0xF6, 0xA1 на 0xF5
не, есть обычный байт C2 а есть с меткой С2 отличаются пропущеным импульсом

EvgenRU
21.03.2016, 15:01
не, есть обычный байт C2 а есть с меткой С2 отличаются пропущеным импульсом

Вот тут http://info-coach.fr/atari/hardware/FD-Hard.php#Example_of_CRC_Code описано по этому поводу в разделе MFM Synch Byte Pattern

Хотя да, понял о чем речь.

Т.е. тут еще выходит, что F5 и F6 это не данные дорожки, а команды контроллера....


Note that with the WD1772 an $A1 sync byte is produced by sending a $F5 byte to the FDC during the command, a $C2 sync byte is produced by sending a $F6 byte, and that the 2 bytes CRC are written by sending one $F7 byte. Normally the $C2 sync byte is is only used before an IAM and therefore normally not used in standard Atari diskettes. However having an IAM records on a track (as formatted on a PC) is perfectly acceptable on an Atari.

Указал в первом сообщении данную информацию.

- - - Добавлено - - -

Сравнил свою таблицу и значения в HFE файле, некоторые отличаются, например,

для 0x4E 01001110
МОЕ 0010010010101001 0x24A9
HFE 0100100100101010 0x492A
NEW 1001001001010100 0x9254

Следующие байты располагаются последовательно в файле

для 0x6E 01101110
МОЕ 00101000 00101001 0x28A9
HFE 0010100010101001 0x28A9
NEW 1001010001010100 0x9454

для 0x69 01101001
МОЕ 0010100000101001 0x2892
HFE 1010100010100010 0xA8A2
NEW 1001010001001001 0x9449

для 0x76 01110110
МОЕ 0010101000101001 0x2A29
HFE 0010101000101001 0x2A29
NEW 1001010100010100 0x9514

не пойму, то ли я где-то ошибся, то ли HFM, но скорее всего я...

Если смотреть в идеологии RN, NN, NR, то получается, что 4E должно быть закодировано как
Rn nR nn Rn nR nR nR n, буду думать дальше

4E 01001110, 01001001 00101010
R-означает смену полярности, N — отсутствие.

0 (предшествующий 0) RN
0 (предшествующий 1) NN
1 NR

Т.е. в данном примере, считается что перед первым байтом идет 0, в последующих учитывается значение последнего бита предыдущего.
Т.е. 4E (01001110) кодируется так
Предыдущий бит Текущий бит Код Значение
0 0 RN 01
0 1 NR 00
1 0 NN 10
0 0 RN 01
0 1 NR 00
1 1 NR 10
1 1 NR 10
1 0 NN 10

Получаем 01001001 00101010

Пока что не совсем понятно...


Так, утащил корректную табличку с гитхаба HxC
Взято тут https://github.com/jfdelnero/libhxcfe/blob/master/sources/tracks/track_generator.c

Хм... какой-то сложный у них метод.... очень мудреный, с отдельной таблицей для клока....

Вот чего нашел


In our example, the character ‘N’ is encoded this way (if the bit on the left was ‘0’):
0 1 0 0 1 1 1 0 The character ‘N’.
1 0 0 1 0 0 0 0 The MFM synchronization bits.
1 0 0 1 0 0 1 0 0 1 0 1 0 1 0 0 The resulting data, written to disk.

http://retro.icequake.net/dob/files/bleuge/disk2fdi/DOCS/TECH/RAWFLOPY.DOC

Т.е. получается наоборот, и используется предыдущий клок, а не последующий :)

по этому примеру получается что 0x4E = 0x9254, т.е. с HxC не сходится..., ну и ладно, наверное это всё-таки корректно :) Вроде там может быть несколько вариантов кодирования, главное чтобы последовательности шли правильно, значит так и буду составлять таблицу, т.е. положение тактирующего бита на данные не влияет вроде, главное, что все биты данных на месте. Плюс этого подхода в том, что первый бит нового значения вычисляется на основе последнего бита предыдущего значения.

Таким образом, для тех 3 последовательных байт получается
0x6E, 0x69, 0x76 = 01101110, 01101001, 1110110
DAT 0 1 1 0 1 1 1 0 |0 1 1 0 1 0 0 1 |0 1 1 1 0 1 1 0
CLK 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0

Результат

100101000101010010010100010010010001010100010100 МОЙ (NEW)
001010001010100110101000101000100010101000101001 HFE

Trol73
21.03.2016, 15:35
1602 можно управлять полубайтами, а если с параллельно/последовательным конвертером, то и по одному пину. Но, тут уже вопрос: потратить бакс на конвертер или доплатить за МК помощнее и "попинастее"
Полубайтами - это же 4 бита шина + 3 линии управления, итого как раз 7 выводов?

CodeMaster
21.03.2016, 15:57
Полубайтами - это же 4 бита шина + 3 линии управления, итого как раз 7 выводов?

Да, так и есть, попутал. Тогда, вот этот вариант (http://www.aliexpress.com/item/IIC-I2C-Interface-LCD1602-2004-LCD-Adapter-Plate-for-Arduino-LCD-1602/32621618497.html?spm=2114.01010208.3.20.wmZKEc&ws_ab_test=searchweb201556_9,searchweb201602_1_100 34_507_10032_10020_10001_10002_10017_10010_10005_1 0011_10006_10021_10003_10004_10022_10009_401_10008 _10018_10019,searchweb201603_7&btsid=924a4151-b8ac-43b7-a48d-6d4ac037e83a) - 2 пина всего за 50 центов. Не знаю правда, I2C вроде бы не сложный протокол, много места в прошивке не должен занять.

EvgenRU
21.03.2016, 21:04
Продолжаю изыскания

Закодировал еще один TRD, строка кодирования
hxcfe.exe -finput:d0011.trd -foutput:1.hfe -conv:HXC_HFE

Первые 4 байта в TDR
62, 6F, 6F, 74 (слово "boot")
01100010, 01101111, 01101111, 01110100

В HFE значения
0x2825, 0x29AA, 0x28AA, 0xA848,
0010100000100101 0010100110101010 0010100010101010 1010100001001000


По моей таблице (новой)
0x94A4, 0x9455, 0x9455, 0x9512
1001010000100100 1001010001010101 1001010001010101 1001010100010010
С учетом соседних бит
0x94A4, 0x9455, 0x1455, 0x1512
1001010000100100 1001010001010101 0001010001010101 0001010100010010
Убираем первый бит и сравниваем с HFE
00101000010010010010100010101010001010001010101000 1010100010010
00101000001001010010100110101010001010001010101010 1010000100100
Видим различия


По старой таблице
0x2949, 0x28AA, 0x28AA, 0x2A25
0010100101001001 0010100010101010 0010100010101010 0010101000100101
С учетом соседних бит
0010100101001001 0010100010101010 0010100010101010 0010101000100101
Сравниваем с HFE
0010100101001001 0010100010101010 0010100010101010 0010101000100101
0010100000100101 0010100110101010 0010100010101010 1010100001001000

Опять же есть различия...

Пока что оставлю это всё, как соберу пробное устройство, тогда и буду разбираться :)
Возможно в HFE есть какие-то свои маркеры...


Вот еще какая-то инфа https://en.wikipedia.org/wiki/Modified_Frequency_Modulation

- - - Добавлено - - -


Да, так и есть, попутал. Тогда, вот этот вариант (http://www.aliexpress.com/item/IIC-I2C-Interface-LCD1602-2004-LCD-Adapter-Plate-for-Arduino-LCD-1602/32621618497.html?spm=2114.01010208.3.20.wmZKEc&ws_ab_test=searchweb201556_9,searchweb201602_1_100 34_507_10032_10020_10001_10002_10017_10010_10005_1 0011_10006_10021_10003_10004_10022_10009_401_10008 _10018_10019,searchweb201603_7&btsid=924a4151-b8ac-43b7-a48d-6d4ac037e83a) - 2 пина всего за 50 центов. Не знаю правда, I2C вроде бы не сложный протокол, много места в прошивке не должен занять.

С TWI не так просто работать напрямую и библиотека тяжелая достаточно, регистр сдвига или SPI в этом плане куда проще использовать.

PS: отключаюсь до четверга, работа не волк. Буду признателен за любые дельные советы за это время.

Еще несколько диаграмм напоследок, снято на 8 МГц, если несколько STEP подряд, то период между ними 3мс, у последнего степа период 16мс, потом начинается выдача данных

Trol73
21.03.2016, 21:47
У atmeg-ов есть встроенный TWI и работать с ним проще, чем писать с нуля свою I2C библиотеку. Другой вопрос, что atmega8 + i2c расширитель будут стоить уже определённо дороже, чем atmega128. И места займут больше на плате. Дисплей можно взять графический - они уже SPI обычно + с графическим экраном можно реализовать гораздо более удобный интерфейс выбора файла, чем с 1602.

EvgenRU
22.03.2016, 00:10
Тут еще идея возникла, если слать данные с помощью таймера и ШИМ, то вообще остается куча времени на чтение с SD и обработку :-D

s_kosorev
22.03.2016, 03:30
тут есть еще одна тема для изучения, нужно ли искажать mfm что бы его смогли прочитать или чистый mfm нормально пройдет через аналоговый тракт контролера дисковода, там есть такая вещь, две подрят единицы в mfm, вторая единица будет смещена слегка вперед, ну и обратная ситуация с нолями, причем искажения в середине диска гораздо больше чем на краю, но это все аналоговые нюансы, нужно ли их учитывать при эмуляции, мне к примеру не сильно ясно

- - - Добавлено - - -

вернее речь не о двух единица а о двух рядом идущих импульсах

но с другой стороны, нормальный контролер дисковода вносит при записи искажения в сигнал, что бы компенсировать этот эффект

- - - Добавлено - - -

с таймеров тоже не все просто, на вход/выход в прерывание нужно тратить такты, это раз.
причем если основной цикл на си, то нужно еще и регистры сохранять которые в обработчике прерывания используются, на ассемблере можно предусмотреть и не трогать какие то регистры для целей ISR с си же, тут много нюансов

EvgenRU
22.03.2016, 07:38
Проверил линию данных от флоппи, там идут исключительно окна 4,6,8мкс, ничего другого, за исключением задержки после STEP и еще есть иногда задержка после пульсации SIDE на 10мкс. Кстати, вопрос с пульсацией SIDE до сих пор так и не прояснен.

PS для AVR буду использовать кварц 20МГц, цикл МК составляет 50нс, что очень удобно для генерации сигналов с помощью ШИМ, т.е. на пульс (1мкс) и ожидание после пульса (1мкс) нужно 40 циклов, на ноль (2мкс) - тоже 40 циклов т.е. устанавливаем ICR на 40, а в OCR будет слаться 2 разных значения для 0 и единицы.
Вход в прерывание 4 цикла, выход 4 цикла, остается 32 цикла на код таймера, сдвиг 16 битного значения 2 цикла, остается 30 за эти 30 нужно проверить, что данные в регистре не закончились, выставить флаги или взять значение из SRAM (2 цикла) и т.д., думаю не более 10 циклов, чтобы сильно не замедлять основной код.

s_kosorev
22.03.2016, 08:01
после смены SIDE нужно заново синхронизацию проходить, так что все равно что там дисковод выдает

EvgenRU
22.03.2016, 08:18
после смены SIDE нужно заново синхронизацию проходить, так что все равно что там дисковод выдает

Так вот непонятно, там именно пульсация SIDE идет а не смена уровня.

Trol73
22.03.2016, 10:05
PS для AVR буду использовать кварц 20МГц
У atmega128A максимальная частота 16МГц, насколько вероятна её устойчивая работа на 20 МГц?

Вход в прерывание 4 цикла, выход 4 цикла, остается 32 цикла на код таймера

Реально 4 цикла? У меня получается минимум 11 циклов + еще 2 цикла на каждый сохраняемый регистр



push r1 // 2 clk 2
push r0 // 2 clk 4
in r0, _SFR_IO_ADDR(SREG) // 1 clk 5
push r0 // 2 clk 7
eor r1, r1 // 1 clk 8
in r0, _SFR_IO_ADDR(RAMPZ) // 1 clk 9
push r0 // 2 clk 11

s_kosorev
22.03.2016, 10:19
можно SPI/USART использовать, нужно просто импульс снаружи формировать, простейший вариант, исключающее или + RC задержка на одном из входов, на байт данных MFM 2 записи в порт данных передатчика

EvgenRU
22.03.2016, 21:02
Реально 4 цикла? У меня получается минимум 11 циклов + еще 2 цикла на каждый сохраняемый регистр

Ну, вроде как при прерывании вызывается ICALL на вектор прерывания, а это 4 цикла + 2 цикла RJMP + RETI 4 цикла, а PUSH/POP, сохранение SREG это делать не обязательно, если использовать ASM и не использовать операции меняющие флаги, хотя, т.к. там сдвиг, то как минимум срег придется сохранять... или думать как сделать без сдвига и других операций влияющих на срег


можно SPI/USART использовать, нужно просто импульс снаружи формировать, простейший вариант, исключающее или + RC задержка на одном из входов, на байт данных MFM 2 записи в порт данных передатчика

Не совсем понял этот момент
Я пока что вижу это себе так

Таймер в CTC режиме, с генерацией прерываний каждую 1мкс (20 циклов) и в коде таймера на выход READ DATA устанавливается значение HIGH, для каждого бита данных получается два прерывания, в случае появления единицы в данных, в первом прерывании меняем выход на LOW, во втором делаем HIGH.

s_kosorev
22.03.2016, 22:00
байт MFM это два байта в нечто манчестеро подобном коде, их можно через SPI или UART выводить, получается по 2 прерывания на байт, что как минимум в 4 раза реже чем с таймером
что бы MFM был, нужно смену уровня заменить на импульсы, простейший вариант, на выходе последовательного порта поставить к примеру "исключающее или" с задержкой сигнала на одном из входов
получится настоящий MFM

- - - Добавлено - - -


Ну, вроде как при прерывании вызывается ICALL на вектор прерывания, а это 4 цикла + 2 цикла RJMP + RETI 4 цикла, а PUSH/POP, сохранение SREG это делать не обязательно, если использовать ASM и не использовать операции меняющие флаги, хотя, т.к. там сдвиг,
ну тут сложно будет, особенно если речь идет о FatFs библиотеке, она на Си и в любом случае с ней нужно будет работать параллельно с обработчиком прерывания

EvgenRU
22.03.2016, 22:33
А можно поподробнее про USART? Там же еще старт/стоп биты есть, как с ними быть?

s_kosorev
22.03.2016, 23:14
USART в нативном режиме плохой пример, использовать его в режиме SPI, там нет лишних битов

EvgenRU
22.03.2016, 23:59
USART в нативном режиме плохой пример, использовать его в режиме SPI, там нет лишних битов

Идею понял, спасибо, т.е. нужно использовать режим Master SPI для USART... в 8 атмеге такого точно нет, а вот в 328p есть, так что можно взять её, можно даже ардуинку для отладки погонять :-D
Получается, для отправки нужно установить скорость 500000 бит/с (что соответствует 2мкс на бит) (для 16МГц и 20МГц можно выставить четко данное значение)
затем выводимый сигнал раздваивается и идет на XOR микросхему, к одному цепляется конденсатор для задержки в 1мкс, т.е. на выходе получаем из единицы 10, а из нуля 00, с интервалом 1мкс.

Да, использование USART сильно разгрузит МК при передаче данных и будет много времени на чтение с карты.

Ох, да там еще можно сразу 16 бит передавать, вообще сказка! Т.е. у МК есть 32мкс для выдачи нового значения!

CodeMaster
23.03.2016, 09:14
в 8 атмеге такого точно нет, а вот в 328p есть

Чувствуется, идея плавно подползает к Core i7, как предполагали изначально ;-) А Мега 8515 не подойдёт, на ней самоделок много и она распространена среди народа?

newart
23.03.2016, 12:33
Делай на Ардуино. Будь человеком! ))

- - - Добавлено - - -


графическим экраном можно реализовать гораздо более удобный интерфейс выбора файла, чем с 1602.
А почему бы не сделать выбор через спектрум?
Скажем при включении в образ диска подставляет бут, в котором уже можно менять текущие диски, а за одно и смотреть что на них.

AlexNN
23.03.2016, 12:58
Действительно, ардуино без экрана (atmega328), выбор на спектруме, разве не оптимальный вариант в плане легкости повторения
и низкой стоимости?

CodeMaster
23.03.2016, 13:54
Действительно, ардуино без экрана (atmega328)

Тогда уж на Altera DE1, там можно монитор и мышь подключить для выбора файла.



А почему бы не сделать выбор через спектрум?

А если будет не Спектрум, кто напишет буты под все платформы?

s_kosorev
23.03.2016, 14:16
А если будет не Спектрум, кто напишет буты под все платформы?
TRD где то кроме спектрума используется? А без экрана легко сделать, есть несколько сигналов которые либо минуют ВГ93 либо достаточно легко читаются через регистр статуса, к примеру INDEX, Выбор дисковода, SIDE
может еще что то, нужно смотреть, но уже этих сигналов достаточно что бы без экрана реализовать обмен с контроллером

- - - Добавлено - - -


А Мега 8515 не подойдёт, на ней самоделок много и она распространена среди народа?
Arduino c 328 уже готовый девайс, подключил шильд с SD у устройство без производства готово

AlexNN
23.03.2016, 14:33
Скорее всего видели, на всякий случай, может наведёт на какие полезные мысли..
SD-контроллер Vinxru
https://youtu.be/lo2y5ZJLkPo?t=7m30s
https://github.com/vinxru/86RKSD

ps может уже есть подобный контроллер SD карт для спектрума?

- - - Добавлено - - -



А если будет не Спектрум, кто напишет буты под все платформы?

Сделать только для спектрума, для начала, лучше меньше, да лучше)


UPD:
Controlling Floppy Disk Drive with Arduino
http://arduino.stackexchange.com/questions/3702/controlling-floppy-disk-drive-with-arduino

UPD2:
Флеш-карта с интерфейсом FDD
http://hxc2001.free.fr/floppy_drive_emulator/index.html#SDCARDFloppyemulator
http://kazus.ru/forums/showpost.php?p=294456&postcount=6
http://zx-pk.ru/showthread.php?t=13735
http://service4u.narod.ru/html/emulator.html

Trol73
23.03.2016, 17:21
Сделать только для спектрума, для начала, лучше меньше, да лучше)
А не проще изначально выбрать правильный дисплей и правильный МК? :)

AlexNN
23.03.2016, 17:47
В идеале, предусмотреть модульность как в железе, так и в софте, т.е. экран цепляется по желанию.

balu_dark
23.03.2016, 18:25
Обычно - контроллер выбирают под задачу! А не задачу урезают под контроллер! :) Выбрать контроллер с 2-4мя кб рам минимум - ну как бы совершенно не проблема! Но как обычно вмешивается "да у меня мешок контроллеров .... модели в любимом мной xxx корпусе..." И начинается год бодания с ограничениями железа. В конце концов - оказывается что реализовать базовые хотелки с лету не получается и проект тихо умирает :) . Знакомая ситуация. Для не любителей ARM есть еще вполне ногодрыгательный С51 и по моему даже с достаточным количеством ОЗУ на борту - силабс делает мешок целый.

s_kosorev
23.03.2016, 18:30
328p по идее должно с головой хватить, он же юзается в Ardiuno Uno

EvgenRU
23.03.2016, 20:11
328p по идее должно с головой хватить, он же юзается в Ardiuno Uno

Да, именно на нем и начну, скорее всего это оптимальный вариант, попробую взять одну дорожку из TRD и загнать её во флеш, потом генерить все остальные из неё :) т.е. проверить будет ли отображаться оглавление на эве, если да. то буду уже карту цеплять.

PS: насчет 8535, посмотрел даташит на него, нет там Master SPI у USART, так же как и у 8-ой атмеги, у Atmega128, как оказалось, его тоже нет, пичалька...

Рискну даже начать это реализовывать прямо на ардуине :) Если не хватит ресурсов тогда на студию перейду. Разумеется без всяких там digitalWrite :) Начну завтра, завтра буду посвободнее, ну и прощайте выходные, конечно же :)

У меня конечно есть PIC18F4620, но это на самый крайний случай... Хотя там разницы с 328 атмегой практически нет

dosikus
23.03.2016, 20:45
Может учесть все плюсы и минусы, цену, доставаемость, грядущие проблемы с авр.
И уже исходя из этого заложить камень.
Авр в данном случае имеет лишь один плюс и то лишь для адепетов. В остальном сливает по полной во всем...

s_kosorev
23.03.2016, 21:34
Но всё еще остается неясным вопрос с пульсирующим сигналом SIDE на второй стороне.
это фигня какая то, не должен он пульсировать, может подтяжка на стороне дисковода отвалилась, либо звон, либо не туда подключен

- - - Добавлено - - -


Изучать авр уже нет смысла, это труп. В свое время так же слили моторолу.
discovery стоит раза в 4 дороже arduino, я думаю тут в другом дело, одно дело выжать из железа 146% другое, взять арм на с++ жуя семечки неспешно заниматься скучной вещью, arm не интересно, напрягаться не надо

- - - Добавлено - - -

Еще стоит учеть момент, возможно человек знает avr, смысл ему тратить н-ное кво месяцевечеров осваивая новое

AlexNN
23.03.2016, 22:16
Так посудить, спектрум тоже ниочем по сравнению с современными пк..
Atmega128 распространенный, недорогой, и судя по всему достаточный вариант,
от того искать что-то более модное не обязательно.

s_kosorev
23.03.2016, 22:17
Надеюсь вы не будете спорить что в стм перефирия на несколько порядков круче?
а если она не нужна для задачи, какая разница, лучше/хуже?

у атома еще круче переферия, почему его не взять? можно на питоне написать эмулятор или там на php

dosikus
23.03.2016, 22:44
А сколько атому обвязки надось, ась? А здесь меньше габарит той меги, единственное соглпсование уровней.

s_kosorev
23.03.2016, 23:16
А сколько атому обвязки надось, ась?
да микромодуль, уже со всей обвязкой + wifi на борту, подал питание, он уже работает, припаял дип штыри, можно хоть в бредборду вставлять

- - - Добавлено - - -

вот такого плана модули (http://pt.aliexpress.com/item/Core210-S5PV210-SAMSUNG-ARM-Cortex-A8-core-Board/1922578432.html?spm=2114.02010208.3.66.d9bJA7&ws_ab_test=searchweb201556_9,searchweb201602_5_100 36_10035_10034_507_10020_10001_10002_10017_10010_1 0005_10011_10006_10003_10021_10004_10022_10009_100 08_10018_10019,searchweb201603_7&btsid=150f86c3-ab9a-4f72-b312-b5c7b15a6e67)

только подешевле, поменьше бывают, лень искать

EvgenRU
23.03.2016, 23:47
Так, сгенерил на ардуине сигнал, но выбрать данные из 2 массивов в прерывании оно не успевает, видимо много пушей там, так что придется всё-таки переходить на асм или Algoritm Builder, второе мне кажется предпочтительнее. Вариант с HFE пока что рассматривать не хочу, хочется всё-таки TRD.

Нижний это клок, с периодом 2мкс

newart
24.03.2016, 00:20
Так, сгенерил на ардуине сигнал, но выбрать данные из 2 массивов в прерывании оно не успевает, видимо много пушей там, так что придется всё-таки переходить на асм или Algoritm Builder,
А в ардуино IDE разве нельзя делать ассемблерные вставки?

Trol73
24.03.2016, 00:23
Так, сгенерил на ардуине сигнал, но выбрать данные из 2 массивов в прерывании оно не успевает, видимо много пушей там, так что придется всё-таки переходить на асм или Algoritm Builder, второе мне кажется предпочтительнее.

На ардуине - это с использованием бабуиновской IDE, компилятора и библиотек, где на каждую инструкцию кода добавляется еще 10 мусорных?
Что именно пытались генерить и насколько сильно не успевает AVR?
Пушей "видимо много", или на самом деле много (легко понять по листингу)?
GCC с ассемблерными вставками как вариант не рассматриваете?
Библиотека работы с SDHC и FAT32 на ассемблере или Algoritm Builder-е уже существует или планируете писать и отлаживать сами?

EvgenRU
24.03.2016, 00:28
А в ардуино IDE разве нельзя делать ассемблерные вставки?
Можно, но толку от них, если неизвестно, что в каком регистре и их нужно сохранять перед использованием




Что именно пытались генерить и насколько сильно не успевает AVR?
Пушей "видимо много", или на самом деле много (легко понять по листингу)?
GCC с ассемблерными вставками как вариант не рассматриваете?
Библиотека работы с SDHC и FAT32 на ассемблере или Algoritm Builder-е уже существует или планируете писать и отлаживать сами?

Вот такая LPM конструкция работает нормально

ISR(USART_UDRE_vect)
{
tmp2 = MFM_tab[1];
UDR0=(byte)(tmp2 >> 8);
UDR0=(byte)tmp2;
}

а вот такая уже нет

ISR(USART_UDRE_vect)
{
tmp2 = MFM_tab[track0[i++]];
UDR0=(byte)(tmp2 >> 8);
UDR0=(byte)tmp2;
}

GCC со вставками опять же упрется в сохранение регистров.
Для AB думаю не составит большой сложности FatFs переделать, там кода не много.

В принципе, если на компе TRD перегнать в MFM, и потом эти данные выдавать, то ардуины должно хватить (теоретически)

s_kosorev
24.03.2016, 00:40
а вот такая уже нет
ISR(USART_UDRE_vect)
{
tmp2 = MFM_tab[track0[i++]];
UDR0=(byte)(tmp2 >> 8);
UDR0=(byte)tmp2;
}

это на ассемблере делать нужно
причем что бы шустрее работало, MFM_tab выравнять в памяти по 256байт граице, в ISR можно сказать каждый такт на счету
причем что бы быстрее было, 2 таблицы, сначала 256 старших байт, потом младших

Trol73
24.03.2016, 10:04
GCC со вставками опять же упрется в сохранение регистров.
Для AB думаю не составит большой сложности FatFs переделать, там кода не много.
Идея писать все на ассемблере - это преждевременная оптимизация, классическая ошибка проектирования. GCC умеет оптимизировать код, тем более, такой тривиальный. Перенос на ассемблер может дать не более ~10% ускорения, что в данном случае не имеет никакого значения.

Для начала надо оптимизировать код на Си. А для этого надо смотреть его ассемблерный листинг.

Сейчас бросаются в глада две вещи:
1. MFM_tab[track0[i++]] - зачем тут два массива? нельзя сразу поместить подготовленные данные в массив track_data[] ?
2. ну и да, алгоритм надо преобразовать так, чтобы индексы были однобайтными - это сокращает код в разы.



В принципе, если на компе TRD перегнать в MFM, и потом эти данные выдавать, то ардуины должно хватить (теоретически)
Перегонять TRD во что угодно можно и на самом девайсе - есть SD-карта, и ничто не мешает на нее сохранять временные данные в любом удобном формате

s_kosorev
24.03.2016, 11:54
track_data[]
тогда на буфер сектора надо будет 512 байт а не 256

- - - Добавлено - - -

как вариант можно нечто такое расмотреть




alignas(256) static const uint8_t mfmtab_h[256] = { .... };
alignas(256) static const uint8_t mfmtab_l[256] = { ... };

alignas(256) static uint8_t sect_data[2][256];
register uint8_t rdbuff asm("r3"); // тут держим старшую половину адреса текущего буфера
register uint8_t rdpos asm("r4"); // тут позиция в буфере

ISR(USART_UDRE_vect, ISR_NAKED)
{
asm ("push r31");
asm ("push r30");
asm ("push r29");
// формируем указатель в буфере сектора
asm ("mov r31, r3");
asm ("mov r30, r4");
// читаем данные из буфера сектора
asm ("ld r29, Z");
asm ("inc r3");
// формируем указатель на mfmtab_h
asm ("ldi r31, hi8(mfmtab_h)");
asm ("mov r30, r29");
// чтение mfm_h
asm ("lpm r29, Z");
asm ("sts 0xc9, r29");
// формируем указатель на mfmtab_l
asm ("inc r31");
// чтение mfm_l
asm ("lpm r29, Z");
asm ("sts 0xc9, r29");

asm ("pop r29");
asm ("pop r30");
asm ("pop r31");
asm ("reti");

/* аналог на Си
uint8_t* pos = (uint8_t*)((rdbuff << 8) | rdpos);
UDR0 = mfmtab_h[*pos];
UDR0 = mfmtab_l[*pos];
rdpos++;
*/
}


тело ISR где то 19 тактов, GCC раз 5 больше выхлоп дает

tnt23
24.03.2016, 12:02
Идея писать все на ассемблере - это преждевременная оптимизация, классическая ошибка проектирования. GCC умеет оптимизировать код, тем более, такой тривиальный. Перенос на ассемблер может дать не более ~10% ускорения, что в данном случае не имеет никакого значения.


Ерунда. В данном случае писать на ассемблере можно и нужно, особенно если прикинуть длительность bit cell (500нс) и время выполнения однотактовой AVR инструкции на 16МГц (62.5нс).

Топикстартеру - я это все уже проходил на ATmega256@16MHz. Помогал только выпрямленный tight loop c очень плотным кодированием по тактам, а также высушенные и обрезанные по самое немогу обработчики прерываний. Да, и еще у меня была привешана внешняя DRAM c программной же регенерацией.

Мой вам совет (с) маркер из "Шерлока Холмса" - выкинуть AVR и взять любой STM32.

- - - Добавлено - - -

Например, самый простой из семейства STM32F0 на Терраэлектронике - 84р (восемьдесят четыре рубля, Карл!). Тактовая 48МГц, фигова куча периферии - а кстати, для формирования MFM потока можно использовать SPI, - и вообще.

dosikus
24.03.2016, 12:09
Тактовая 48МГц,

Причем гонятся до 64МГц, но это уже из области извращений... :)
А STM32F0x2 умеют набортный DFU бут ...

s_kosorev
24.03.2016, 12:16
В данном случае писать на ассемблере можно и нужно, особенно если прикинуть длительность bit cell (500нс) и время выполнения однотактовой AVR инструкции на 16МГц (62.5нс).
итого при 120 инструкций на байт MFM, ISR в 20-30 тактов, оставляет уйму времени для подкачки данных с SDCARD, 20-25% времени ядра на ISR это ниочем, зачем тут ARM с кучей не нужной для задачи перефирии?

Кстати в ARM почти весь профит от частоты съест вход в ISR, возможно даже будет не хватать

Trol73
24.03.2016, 12:47
тогда на буфер сектора надо будет 512 байт а не 256

А разве 256 байт - это критично для m328? Массивы mfmtab так вообще 512 байт занимают..



Ерунда. В данном случае писать на ассемблере можно и нужно, особенно если прикинуть длительность bit cell (500нс) и время выполнения однотактовой AVR инструкции на 16МГц (62.5нс).

На ассемблере есть смысл писать критичные к скорости выполнения куски кода в конечном приложении. Это позволить немного ускорить код. Сейчас же речь о прототипе, который только формирует сигнал и ничего при этом не делает, с картой не работает. Эти 10% выигрыша быстродействия тут не должны играть решающую роль. Когда добавится работа с картой требования к процессорному времени, затрачиваемому на формирования сигнала могут возрасти.

Проходил нечто подобное когда делал поддержку воспроизведения WAV 44100 Гц в своём магнитофоне. Сначала все тормозило и скорости не хватало. Переписывания кода обработчика прерывания на Си, разбиение массивов длиной 512 байт на два массива по 256 байт дало ощутимый прирост в скорости выполнения. Небольшие оптимизации библиотеки поддержки SD-карты и FAT-а (разворачивания циклов, inline-зация нескольких функций и отключение лишних проверок) ещё немного ускорило прошивку.
Потом переписал обработчик прерывания на ассемблер. Да, он стал работать чуть быстрее, но основной вклад внесла именно оптимизация Си-кода и отказ от 16-битных индексов массивов.

PS. использование 48МГц МК для эмуляции флопа для компьютеров, частота которых измеряется единицами МГц - как-то неприлично, имхо :)

s_kosorev
24.03.2016, 13:07
так вообще 512 байт занимают..
ну так таблицы в флеше, а 2 буфера в оперативке по 512 это уже 50% памяти в расход ушло

Trol73
24.03.2016, 13:59
ну так таблицы в флеше, а 2 буфера в оперативке по 512 это уже 50% памяти в расход ушло
Ну не совсем 50% в расход, а + 256 байт, т.е., +25% за сильное упрощение процедуры обработчика. Тут вопрос, на что еще нужна память во время выдачи трека. И, если её хватает, то это вообще не проблема.

s_kosorev
24.03.2016, 14:29
Ну не совсем 50% в расход, а + 256 байт
один буфер выводится, второй в это время заполняется на каждый надо по 512байт, если сразу в буфере mfm держать

- - - Добавлено - - -

причем затраты +- одинаковые на преобразования 256 байт данных в 512 mfm, разница только где это время будет потрачено в ISR или главном цикла, что по мне все равно, а вот расход памяти сразу виден, причем без веской причины

EvgenRU
24.03.2016, 17:25
У меня тут мысль появилась, а зачем нам вообще эти 512байт? Можно же читать не весь сектор, а скажем по 64 или 128 байт, наверное лучше 128, чтобы получилось как раз 256 в MFM, из считанных данных гнать в MFM по кольцу через 2 указателя. Основная проблема будет с подсчетом последнего бита и с CRC. При переключении на дургую сторону можно один оборот прогнать то что заполняется

Ктати, SWAP, ROL и AND 0x1F экономит нам 224 байт под MFM_tab_h, т.к. таблица там такая

0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,
0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,
0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,
0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,
0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,0x4A,
0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,
0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,
0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,
0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,
0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,
0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,
0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,
0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,
0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,0x8A,
0xA5,0xA5,0xA5,0xA5,0xA5,0xA5,0xA5,0xA5,
0xA4,0xA4,0xA4,0xA4,0xA4,0xA4,0xA4,0xA4,
0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,
0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,0xA2,
0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,
0xA8,0xA8,0xA8,0xA8,0xA8,0xA8,0xA8,0xA8,
0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,

MFM_tab_l, думаю аналогично, тут даже меньше, всего 16 значений, хватит одного AND 0x0F

0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,
0x95,0x92,0x89,0x8A,0xA5,0xA2,0xA9,0xAA,

tnt23
24.03.2016, 19:16
И еще там есть DMA, что для циклически повторяющихся задач (к которым и относится проигрывание дорожки) вообще идеально подходит.

- - - Добавлено - - -


итого при 120 инструкций на байт MFM, ISR в 20-30 тактов, оставляет уйму времени для подкачки данных с SDCARD, 20-25% времени ядра на ISR это ниочем, зачем тут ARM с кучей не нужной для задачи перефирии?

Кстати в ARM почти весь профит от частоты съест вход в ISR, возможно даже будет не хватать

Не очень понятно, откуда оценка в 20-30 тактов на ISR (и что ISR делает?). Далее, с SD данные подкачивать нужно, видимо, с файловой системой (FatFS/TinyFS/PicoFS/etc), что совсем не быстро, если предполагается это делать периодически ввиду отсутствия буфера на дорожку.

Опять же, с какого перепугу в ARM профит будет съедать вход в ISR? мне немножечко приходилось работать с тем и с другим, уверяю, это достаточно быстро даже на 48МГц.

Если у вас идиосинкразия на ARM, тогда другое дело. Наличие ненужной периферии огорчает? Возьмите Z80, будет благолепно. Просто я не понимаю, отчего не взять современный дешевый (84р, да?) МК с кучей возможностей уже включенных в эти 84р, если нужно решить задачу, а не потрахаться :)

- - - Добавлено - - -



На ассемблере есть смысл писать критичные к скорости выполнения куски кода в конечном приложении. Это позволить немного ускорить код. Сейчас же речь о прототипе, который только формирует сигнал и ничего при этом не делает, с картой не работает. Эти 10% выигрыша быстродействия тут не должны играть решающую роль. Когда добавится работа с картой требования к процессорному времени, затрачиваемому на формирования сигнала могут возрасти.

PS. использование 48МГц МК для эмуляции флопа для компьютеров, частота которых измеряется единицами МГц - как-то неприлично, имхо :)

Дисковод от ленты немножечко отличается. Скажем, у дисковода есть определенные требования к скорости позиционирования головок (читай - к загрузке/отдаче новой дорожки) - допустим, 3мс на шаг и 15мс на стабилизацию после последнего шага. Для достоверной эмуляции хорошо бы эти требования выдерживать. Есть платформы, под которые существует ненулевое количество софта, смертельно обижающегося на "неуспеваемость" эмуляции.

Про неприличность 48МГц - ну вы же наверняка пользуетесь часами в смартфоне, без особых угрызений совести :)

Trol73
24.03.2016, 19:53
У меня тут мысль появилась, а зачем нам вообще эти 512байт? Можно же читать не весь сектор, а скажем по 64 или 128 байт...
512 байт - размер сектора SD-карты, читать блоками меньшего размера будет, скорее всего, неудобно, если использовать готовые библиотеки.


Если у вас идиосинкразия на ARM, тогда другое дело. Наличие ненужной периферии огорчает? Возьмите Z80, будет благолепно. Просто я не понимаю, отчего не взять современный дешевый (84р, да?) МК с кучей возможностей уже включенных в эти 84р, если нужно решить задачу, а не потрахаться :)
Так интерес, насколько понимаю, как раз в том, чтобы сделать самому, и не палить при этом из пушки по воробьям :) Ну и да, потрахаться, но сделать ретро-железку на почти-ретро-микроконтроллере :)
Кстати, в случае использования STM придётся же конвертер 3.3В <-> 5.0В ставить?


Про неприличность 48МГц - ну вы же наверняка пользуетесь часами в смартфоне, без особых угрызений совести :)
Так то телефон, я же с него не только время смотрю, а еще звоню и всякими там интернетами пользуюсь :) Но если бы делал простые часы, то точно взял бы AVR-ку, а не ARM 48МГц :)

EvgenRU
24.03.2016, 20:03
Ну, давайте еще вспомним STM8... та же атмега8...

PS: alignas ардуина не понимает, а вот регистры мапить дает, уже плюс!

Вот такая штука в ардуинке отлично работает

.........устаревший код удален, см. код на следующей странице.........

PS: вариант с размещением таблиц во флеше отпадает, т.к. скорость считывания очень медленная, только SRAM.

dosikus
24.03.2016, 21:18
Ну, давайте еще вспомним STM8... та же атмега8
вы настолько неосведомлены. В стм8 периферия на порядок круче авр. Хотя о покойниках лучше молча.

s_kosorev
24.03.2016, 21:21
Не очень понятно, откуда оценка в 20-30 тактов на ISR (и что ISR делает?).
код выше, выводит через SPI MFM

Далее, с SD данные подкачивать нужно, видимо, с файловой системой (FatFS/TinyFS/PicoFS/etc), что совсем не быстро, если предполагается это делать периодически ввиду отсутствия буфера на дорожку.
можно при открытии файла получить список всех кластеров и расчитать координаты всех секторов образа, тогда в основном цикле будет тупо чтение с SD карты по известным номерам

пять же, с какого перепугу в ARM профит будет съедать вход в ISR? мне немножечко приходилось работать с тем и с другим, уверяю, это достаточно быстро даже на 48МГц.
ну смотре, мега 20мгц 4такта вход, арм 48 мгц, 12тактов вход, + NVIC

Если у вас идиосинкразия на ARM, тогда другое дело.
тут другое, avr достаточно по ресурсам + доступность dip корпуса (берборды беспаечные) + ардруина (цена в несколько раз доступнее того же дискавери), человек судя по сайту с Avr знаком

Наличие ненужной периферии огорчает?
был аргумент что там круче перефирия, он то так, только какая разница если не юзается

Просто я не понимаю, отчего не взять современный дешевый (84р, да?)
дискавери дороже, ардуина у каждого 3 имеется (наличие usb-com + мега в дипе + бердборда, считай у тебя есть ардуина)

мс на шаг и 15мс на стабилизацию после последнего шага.
решается вообще без напрягов

- - - Добавлено - - -

PS: задрали проповедники ARM, в каждую ветку с AVR лезут, чешется что ли?

tnt23
24.03.2016, 21:50
Я не проповедник ARM, и лезу не в каждую ветку, а конкретно думал, что мой опыт реализации эмулятора дисковода на AVR кому-то может быть полезен.

s_kosorev
24.03.2016, 21:51
>>PS: alignas ардуина не понимает, а вот регистры мапить дает, уже плюс!

Alidnas это нужно компилятору сказать что нужно ждать c11 или gnu-c99

EvgenRU
24.03.2016, 22:10
Я не проповедник ARM, и лезу не в каждую ветку, а конкретно думал, что мой опыт реализации эмулятора дисковода на AVR кому-то может быть полезен.

Если есть опыт реализации на AVR, так поделитесь опытом реализации на AVR :-D

А то, как пример, я бы спросил, на каком транзисторе лучше сделать усилитель для пищалки, а мне бы стали советовать какую TDA выбрать... всё, на этом умолкаю насчет AVR, STM, PIC и т.д. Проект будет на AVR, кому хочется сделать на другом - делайте, выкладывайте, думаю, все будут рады.


PS: просьба к спецам, проинспектируйте код на предыдущей странице на предмет оптимизации и сохранения регистров. Код 100% рабочий, сигналы генерируются корректно, проверил лог анализатором.

При такой реализации получается кодирование данных в коде ISR, т.е. буфер под данные остается размером с сами данные! Ну и под заголовки дорожки/сектора нужно будет что-то придумать. С CRC пока что не знаю, то ли при переключении дорожек генерить, то ли еще как, но все не войдут в память при монтировании, получается 2.5кб данных. Еще вариант сгенерить CRC во временный файл при монтировании.

balu_dark
24.03.2016, 23:47
Так - народ! я уже часть оффтопа и флуда - снес в соотв ветку. Давайте холиварить не тут!
В конце концов - демо пишут как раз вопреки...
Может и этот проект таки до релиза дойдет...

s_kosorev
25.03.2016, 00:39
но все не войдут в память при монтировании, получается 2.5кб данных.
есть еще кило eeprom :)

dosikus
25.03.2016, 07:19
del

EvgenRU
25.03.2016, 07:26
есть еще кило eeprom :)

Не уверен, что обращение к еепром будет быстрее чем к флеш. Так что придется все-равно налету делать или что-то изобретать, временный файл здесь мне видится наиболее подходящим вариантом с подгрузкой нужной части CRC при переходе с дорожки на дорожку.

PS: последний раз про STM, если вам нужно на STM то вот здесь http://zx-pk.ru/showthread.php?t=1262&p=825463&viewfull=1#post825463 есть всё готовое, отправляйтесь туда

Ну и шутка дня: Core-i7, LPT порт, 32GB, 8TB HDD покроют всю возможную нехватку ресурсов атмеги и программировать будет удобнее :-D

trader2k4
25.03.2016, 08:25
Я не проповедник ARM, и лезу не в каждую ветку, а конкретно думал, что мой опыт реализации эмулятора дисковода на AVR кому-то может быть полезен.

Было бы более полезно, если бы вы открыли свои тогдашние наработки, а не вынуждали людей изобретать трехколесные велосипеды, приговаривая "у вас всё неправильно, а я знаю как делать, но вам не скажу".
Понятное дело, деньги всем нужны - но вы или умные, или красивые, либо вы честно барыжите закрытым продуктом - либо открываете его для всех желающих, без вот этой вот клоунады.

Со всем уважением к вашим бесспорным заслугам.

EvgenRU
25.03.2016, 11:45
Насчет кодирования данных, сейчас я себе это вижу так.

Есть буфер на 256 байт, загружаем в него 256 байт сектора.
После того как индекс ушел за середину буфера, подгружаем в его начало следующие 128 байт.
Когда индекс перескочил в первую половину, подгружаем следующие 128 байт.

После того как индекс стал = 0 переключаемся на другой буфер, где находится CRC и закодированные пробелы и синхробайты в формате БАЙТ,КОЛИЧЕСТВО.

Как-то так.

Не помешает сделать еще один буфер на 256 для второй стороны, но не знаю, на сколько это необходимо.


И так, XOR не дает правильный сигнал, импульсы идут как по фронту, так и по спаду.

Получил корректный MFM с помощью инвертора и RC цепочки.
Вот, снял на лог анализаторе, на картинке, верхний - выход с МК, нижний - MFM
56592

Для получения такого сигнала, инвертировал выходной сигнал, передал его через конденсатор 2.2нФ, после чего притянул его к +5в через 1кОм

PS: наверное можно обойтись и без инвертора, инвертировав таблицу и исправив операцию замены последнего бита

PS2: поставил последнюю версию ардуины, в ней alignas работает.

Вот в таком виде отлично работает без инвертора.

// ZX-Spectrum FDD Emulator
//
//#include <petit_fatfs.h>

#define DRIVE_SEL PC0 // DRIVE SELECT CONNECT DS0-DS3 using jumper (INPUT)
#define MOTOR_ON PC1 // MOTOR ON (INPUT)
#define WRT_DATA PC2 // WRITE DATA (INPUT)
#define WRT_GATE PC3 // WRITE GATE (INPUT)
#define DIR_SEL PC4 // DIRECTION SELECT (INPUT)
#define SIDE_SEL PC5 // SIDE SELECT (INPUT)

uint8_t sector_data[256] = // 1 сектор
{
0x62,0x6F,0x6F,0x74,0x20,0x20,0x20,0x20,0x42,0xB4, 0x00,0xB4,0x00,0x23,0x00,0x01,
0x46,0x55,0x4C,0x4C,0x20,0x54,0x48,0x52,0x42,0x6D, 0x00,0x6D,0x00,0x01,0x03,0x03,
0x66,0x74,0x31,0x20,0x20,0x20,0x20,0x20,0x43,0x40, 0x9C,0x00,0x12,0x12,0x04,0x03,
0x66,0x74,0x32,0x20,0x20,0x20,0x20,0x20,0x43,0xB4, 0x5F,0x0A,0x6E,0x6F,0x06,0x04,
0x52,0x41,0x49,0x4E,0x42,0x4F,0x57,0x2B,0x42,0x08, 0x01,0x08,0x01,0x02,0x05,0x0B,
0x52,0x41,0x49,0x4E,0x42,0x2E,0x2B,0x24,0x43,0x00, 0x40,0x00,0x1B,0x1B,0x07,0x0B,
0x52,0x41,0x49,0x4E,0x42,0x2E,0x2B,0x63,0x43,0xA8, 0x61,0x58,0x9E,0x9F,0x02,0x0D,
0x52,0x41,0x49,0x4E,0x42,0x2E,0x2B,0x73,0x43,0x00, 0x40,0x08,0x07,0x08,0x01,0x17,
0x52,0x41,0x49,0x31,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x57,0x1A,0x1B,0x09,0x17,
0x52,0x41,0x49,0x32,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x1A,0x1B,0x1C,0x04,0x19,
0x52,0x41,0x49,0x33,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x13,0x1D,0x1E,0x00,0x1B,
0x52,0x41,0x49,0x34,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x26,0x1D,0x1E,0x0E,0x1C,
0x52,0x41,0x49,0x35,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x92,0x1C,0x1D,0x0C,0x1E,
0x52,0x41,0x49,0x36,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x08,0x1E,0x1F,0x09,0x20,
0x52,0x41,0x49,0x37,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0x10,0x1C,0x1D,0x08,0x22,
0x52,0x41,0x49,0x38,0x20,0x20,0x20,0x20,0x43,0x98, 0x00,0xE3,0x1F,0x20,0x05,0x24,
};//

register volatile uint8_t sector_byte asm("r19");
register volatile uint8_t tmp asm("r20");

register volatile uint8_t XH_Save asm("r9");
register volatile uint8_t XL_Save asm("r10");
register volatile uint8_t ZH_Save asm("r11");
register volatile uint8_t ZL_Save asm("r12");
register volatile uint8_t b_index asm("r13");
register volatile uint8_t SREGSave asm("r14");

uint8_t MFM_tab_h[32] =
{
0x55,0x54,0x52,0x52,0x49,0x48,0x4A,0x4A,0x25,0x24, 0x22,0x22,0x29,0x28,0x2A,0x2A,0x95,0x94,0x92,0x92, 0x89,0x88,0x8A,0x8A,0xA5,0xA4,0xA2,0xA2,0xA9,0xA8, 0xAA,0xAA
};
uint8_t MFM_tab_l[16] = //PROGMEM =
{
0x55,0x52,0x49,0x4A,0x25,0x22,0x29,0x2A,0x95,0x92, 0x89,0x8A,0xA5,0xA2,0xA9,0xAA
};


ISR(USART_UDRE_vect, ISR_NAKED)
{
asm ("in r14,0x3F"); // save SREG
asm ("mov r9,r24"); // save XH
asm ("mov r10,r25"); // save XL
asm ("mov r11,r30"); // save ZH
asm ("mov r12,r31"); // save ZL
if(!tmp) // it is ok, as MFM_tab doesn't have zero values
{ // Send first MFM byte

asm(
"mov r20,r19\n" //tmp = sector_byte;
"lsr r20\n" //tmp >>= 3; -------------
"lsr r20\n"
"lsr r20" // -----------------------
);
tmp = MFM_tab_h[tmp]; // get first MFM byte from table

UDR0 = ~tmp; // put byte to send buffer
tmp = sector_byte;
tmp &= 0x0f;
tmp = MFM_tab_l[tmp]; // get second MFM byte from table to "tmp"
}
else
{ // Send second MFM byte
sector_byte = sector_data[b_index]; // pre-get new byte from buffer
//if((tmp & 0x02) || (sector_byte & 0x80)) tmp &= 0xFE; else tmp |= 0x1; // change the last bit
if(sector_byte & 0x80) tmp &= 0xFE; // ДАННЫЙ КОД ОПТИМАЛЬНЕЕ ПРЕДЫДУЩЕЙ СТРОКИ :-D

UDR0 = ~tmp; // put byte to send buffer
tmp=0;
b_index++;
}

asm ("mov r31,r12"); // restore ZL
asm ("mov r30,r11"); // restore ZH
asm ("mov r25,r10"); // restore XL
asm ("mov r24,r9"); // restore XH
asm ("out 0x3F,r14"); // restore SREG
reti();
}

int main() {
// init();

// Setup USART in MasterSPI mode 500000bps
cli();
//DDRD |= (1 << DDD4);
UBRR0H = 0x00;
UBRR0L = 0x0F;
UCSR0C = 0xC0;
UCSR0A = 0x00;
UCSR0B = 0x28;
tmp=0;

b_index = 0;
sector_byte=sector_data[b_index++];

sei();

while(1)
{
// main loop
}
}

tnt23
25.03.2016, 23:01
Было бы более полезно, если бы вы открыли свои тогдашние наработки, а не вынуждали людей изобретать трехколесные велосипеды, приговаривая "у вас всё неправильно, а я знаю как делать, но вам не скажу".
Понятное дело, деньги всем нужны - но вы или умные, или красивые, либо вы честно барыжите закрытым продуктом - либо открываете его для всех желающих, без вот этой вот клоунады.

Со всем уважением к вашим бесспорным заслугам.

Фигассе наезд. Идите в удалено модератором

s_kosorev
26.03.2016, 00:25
И так, XOR не дает правильный сигнал, импульсы идут как по фронту, так и по спаду.
так и должно, на запись идет манчестероподобный сигнал, который меняет полярность магнитного поля головки дисковода, а при чтении, магнитная головка вырабатывает импульс в момент смены полярности на диске

- - - Добавлено - - -

хотя про запись точно не помню, в дисководе триггер стоит который по сигналу меняет полярность или от контроллера дисковода идет сигнал в управляющий полярностью, но это пока не важно

- - - Добавлено - - -


tmp = MFM_tab_h[tmp];
тут поидее в ISR будет регистры портить, для расчета адреса

- - - Добавлено - - -

вот (http://www.emuverse.ru/wiki/%D0%A0%D0%B0%D0%B4%D0%B8%D0%BE-86%D0%A0%D0%9A/%D0%A0%D0%B0%D0%B4%D0%B8%D0%BE_1,2-93/%D0%9A%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D 0%B5%D1%80_%D0%BD%D0%B0%D0%BA%D0%BE%D0%BF%D0%B8%D1 %82%D0%B5%D0%BB%D1%8F_%D0%BD%D0%B0_%D0%93%D0%9C%D0 %94) отличнейшая статья чтение/запись на дисководы

EvgenRU
26.03.2016, 00:41
так и должно, на запись идет манчестероподобный сигнал, который меняет полярность магнитного поля головки дисковода, а при чтении, магнитная головка вырабатывает импульс в момент смены полярности на диске

хотя про запись точно не помню, в дисководе триггер стоит который по сигналу меняет полярность или от контроллера дисковода идет сигнал в управляющий полярностью, но это пока не важно

тут поидее в ISR будет регистры портить, для расчета адреса

вот (http://www.emuverse.ru/wiki/%D0%A0%D0%B0%D0%B4%D0%B8%D0%BE-86%D0%A0%D0%9A/%D0%A0%D0%B0%D0%B4%D0%B8%D0%BE_1,2-93/%D0%9A%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D 0%B5%D1%80_%D0%BD%D0%B0%D0%BA%D0%BE%D0%BF%D0%B8%D1 %82%D0%B5%D0%BB%D1%8F_%D0%BD%D0%B0_%D0%93%D0%9C%D0 %94) отличнейшая статья чтение/запись на дисководы

Поправил регистры, пришлось дизассемблировать, чтобы понять что там и как :)
Вот код ISR в таком виде, как выше.

L0053:
; 4 (ICALL)+2 (RJMP) + 1 = 7 циклов перед входом в прерывание
; вход в прерывание (7-8 циклов) ---------------------------------
in r14,SREG
mov r9,r24
mov r10,r25
mov r11,r30
mov r12,r31
cpse r19,r1
rjmp L006F
;-----------------------------------------------------------------------
;
; // отправка первого байта (26 циклов) ---------------------------
mov r20,r18
lsr r20
lsr r20
lsr r20
mov r30,r20
ldi r31,0x00
subi r30,0xE0
sbci r31,0xFE
ld r30,Z
mov r20,r30
mov r24,r30
com r24
sts D00C6,r24
mov r20,r18
andi r20,0x0F
ldi r31,0x00
subi r30,0x00
sbci r31,0xFF
ld r19,Z
rjmp L0080
; ----------------------------------------------------------------------
L006F:
; // отправка второго байта (20 циклов макс) ---------------------
mov r30,r13
ldi r31,0x00
subi r30,0x00
sbci r31,0xFE
ld r24,Z
mov r18,r24

sbrc r24,7
rjmp L0087

sbrc r19,1
rjmp L0087

rjmp L0089
; ----------------------------------------------------------------------
L007A:
mov r24,r19
com r24
sts D00C6,r24
clr r19
inc r13
; ----------------------------------------------------------------------
L0080:
; выход из прерывания (9 циклов)
mov r31,r12
mov r30,r11
mov r25,r10
mov r24,r9
out SREG,r14
reti
; ----------------------------------------------------------------------
L0087:
andi r19,0xFE
rjmp L007A
; ----------------------------------------------------------------------
L0089:
ori r19,0x01
rjmp L007A


Итого имеем вроде как 50 циклов в худшем случае. 50*62.5 = 3.1мкс, байт у нас отправляется за 16мкс (байт данных за 32мкс), остается ~13мкс (~26мкс на байт) на основной код. Итого, нагрузка ISR составляет не более 9%
Правда надо еще учитывать, что ардуина использует свой жуткий таймерный код, хотя там всего-то идет увеличение переменной типа long на единицу каждую мкс, для работы функций delay_ms и delay_us, так что, думаю общая нагрузка периодических прерываний не должна превышать 20%

Насчет сигнала, я же снимал анализатором с реального дисковода и он там был именно таким как сейчас генерируется через RC.

s_kosorev
26.03.2016, 01:57
Насчет сигнала, я же снимал анализатором с реального дисковода и он там был именно таким как сейчас генерируется через RC.
по всей видимости ты формируешь не смену сигнала а фронты, RC + инвертор ты их просто подрезаешь, ну такой вариант тоже можно, просто эти импульсы что шли с дисковода это момент смены сигнала

- - - Добавлено - - -

вот картинка (http://www.emuverse.ru/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:RK86_FDDP02.png)
1. строка MFM сигнал (на байт 16 возможных изменений сигнала)
2. то что выдает дисковод

Итого что бы в 2х байтах SPI выдать нужно количество импульсов, надо слать или 32 бита и укорачивать фронт или выдавать импульс по изменению сигнала и тогда хватит 16 бит

- - - Добавлено - - -

ну или как вариант, подмешивать сигнал синхронизации SPI по логическому И тогда бит 1 это импульс, 0 пропуск

- - - Добавлено - - -

байт 0xFF в mfm будет 16 импульсов, для формирования 16 импульсов нужно 32бит либо 16 смен уровня

EvgenRU
26.03.2016, 02:20
Не, мне кажется это уже не из той серии :) Может так дисковод внутри работает, но то что в него из него передается оно имеет вид именно тот что я привел на рисунке. Оно даже по той ссылке так показано.

Вот, еще раз приведу диаграммы.
Первая это сигнал который сейчас генерит ардуина (верхний график) через RC (нижний график).
Вторая реальный дисковод.
Сигналы полностью идентичны, правда на реальном нужно было поставить частоту побольше, а то брешет немного.

s_kosorev
26.03.2016, 02:50
я не вижу что идентичного, похожие импульсы и интервалы это еще не значит что правильно, я привел ссылку что на выходе дисковода, по описанию mfm байт 0xff это 16 импульсов с минимальным шагом
на диаграммах нужна привязка к времени и какие входные данные были до mfm кодирования, что бы понять правильно или нет

- - - Добавлено - - -

>> 0xF8:0xAA95,0xF9:0xAA92,0xFA:0xAA89,0xFB:0xAA8A,0x FC:0xAAA5,0xFD:0xAAA2,0xFE:0xAAA9,0xFF:0xAAAA,

вот кстати из таблицы, видно что 0xFF = 0xAAAA это не 8 импульсов а !16 смен уровня сигнала, то есть 16 мпульсов на выходе дисковода, о чем я и говорил, вернее 15, нужно учитывать последний бит предыдущего байта

EvgenRU
26.03.2016, 07:40
Так оно и кодируется там в 2 байта по таблице, каждый импульс получается 2мкс, после инвертирования и применения RC импульс становится 1мкс (уменьшается только импульс нуля, единица остается такой как и была), всё в точности как в оригинальном сигнале.

s_kosorev
26.03.2016, 08:58
Можно семпл, как буфет выглядеть последовательность, 0xff, 0x00, 0xAA

EvgenRU
26.03.2016, 09:32
Вечером выложу, неожиданно пришлось ехать на работу

Исправил ошибку в скетче на предыдущей странице, по дурости заменил >>= 3 на ROL :))) а надо на 3 LSR

Вот картинка с этими 3 байтами с самого начала передачи
56601

Походу пришло время генерить дорожки, на основе этого сектора пока что, и цеплять к реалу. Потом уже SD.

Данные сектора скорее всего буду подгружать так.
Первая половина данных ушла - грузим первую половину следующего сектора
Вторая половина ушла, грузим вторую половину следующего сектора

Вот так вычисляю CRC для заголовка

// CRC CALCULATION, PRE-CALC value for A1,A1,A1,FE = 0xB230
{
union
{
uint16_t value;
unsigned char bytes[2];
} crc;

crc.value = 0xB230;

crc.bytes[0] ^= track;
for (b_index = 0; b_index < 8; b_index++) crc.value = crc.bytes[0] & 0x80 ? (crc.value << 1) ^ 0x1021 : crc.value << 1;
crc.bytes[0] ^= side;
for (b_index = 0; b_index < 8; b_index++) crc.value = crc.bytes[0] & 0x80 ? (crc.value << 1) ^ 0x1021 : crc.value << 1;
crc.bytes[0] ^= sector;
for (b_index = 0; b_index < 8; b_index++) crc.value = crc.bytes[0] & 0x80 ? (crc.value << 1) ^ 0x1021 : crc.value << 1;
crc.bytes[0] ^= 1; // sector size;
for (b_index = 0; b_index < 8; b_index++) crc.value = crc.bytes[0] & 0x80 ? (crc.value << 1) ^ 0x1021 : crc.value << 1;
sector_header[0x56]=crc.bytes[0];
sector_header[0x57]=crc.bytes[1];
}

Каждое действие делаю на шаге генерации байта первого пробела сектора, т.е. циклов там нет, а есть кейс по номеру байта пробела.

И так, дорожку сгенерировал, данные на лог анализаторе выводятся нормально, без разрывов, всё отлично, CRC успевает сгенерироваться.
Причем дорожка у меня во флеше 4к, и он её читает по пол сектора, успевает! Проверял успеваемость флажком состояния, когда не успевает, то отключает прерывания и уходит в бесконечный цикл.

s_kosorev
26.03.2016, 09:51
не, отбой, в голове попутался mfm и fm

EvgenRU
27.03.2016, 22:08
Подключил к ZX, получаю

Disc Error
Trk 0 sec 9
Retry, Abort, Ignore ?

Помню такая фигня была когда втыкаешь MS-DOS дискету

В чем здесь может быть проблема? Неверный формат? Не вовремя Index генерирую?

PS: скорее всего где-то что-то напутал, буду дальше разбираться...

Выяснил, такую ошибку выдает, когда вычисленная CRC не совпадает, при этом должен генерироваться INDEX, если INDEX не генерируется, то зависает :) CRC генерил в регистре 20,21, но он видимо портился при вызове функций.

UPD: теперь диск егор, думаю это уже наполовину успех :)
UPD2: действительно! наполовину успех! диск егор означает, что адресное поле грузится нормально и CRC в нем рассчитано нормально, а вот поле данных кривое пока что, буду дальше оптимизировать. САМОЕ УДИВИТЕЛЬНОЕ это то, что эта штука работает напрямую с выхода атмеги, никаких резисторов и конденсаторов не нужно!

UPD3: Ура товарищи! Чтение работает как надо! Всё, буду допиливать ближайшие дни, потом буду выкладывать результаты, так что ожидайте. Короче, в итоге для эмуляции дисковода нужно будет I2C дисплей, Atmega328p, SD карта по SPI, кнопки. Ну и всё, в принципе.

s_kosorev
28.03.2016, 08:27
если разобраться не получится, можно на fpga сделать сепаратор и декодер mfm и логировать что видит контролер дисковода

EvgenRU
29.03.2016, 00:47
Ну что ж, господа, выкладываю первый рабочий вариант для ардуины.
В данном скетче нулевая дорожка с одного из моих дисков вбита во флеш.
Из флеша читаются сектора, для других дорожек нулевая дублируется. В итоге, при подключении к ZX нормально выводится оглавление диска и можно бегать по секторам в диск докторе.

Принимается любая критика и пожелания по дальнешему допиливанию.

Вот, собственно скетч. Провода к шлейфу цеплять прямо от ардуины, те что указаны в дефайнах. PD0-PD7 это пины 0-7 на ардуины, PC0-PC2 - это A0-A2, PB0-PB1 пока что не используются. DRIVE SELECT цеплять пока что не надо, только MOTOR ON.

// ZX-Spectrum FDD Emulator
//
//#include <petit_fatfs.h>

#define SIDE_SEL PC0 // SIDE SELECT (INPUT)
#define DRIVE_SEL PC1 // DRIVE SELECT CONNECT DS0-DS3 using jumper (INPUT) /// not used yet
#define MOTOR_ON PC2 // MOTOR ON (INPUT)

#define WRT_GATE PB0 // WRITE GATE (INPUT) /// not used yet
#define WRT_DATA PB1 // WRITE DATA (INPUT) /// not used yet

#define READ_DATA PD1 // READ_DATA (OUTPUT) /// defined in USART
#define STEP PD2 // STEP (INPUT)
#define DIR_SEL PD3 // DIRECTION SELECT (INPUT)
// PD4 UNABLE TO USE!!
#define INDEX PD5 // INDEX (OUTPUT)
#define TRK00 PD6 // TRACK 00 (OUTPUT)
#define WP PD7 // WRITE PROTECT (OUTPUT)


uint8_t sector_header[64]; // sector header
uint8_t sector_data[256]; // sector data

// STATE variable values
// 0 - TRACK HEADER
// 1 - SECTOR HEADER
// 2 - SECTOR DATA
// 3 - SECTOR FOOTER
// 4 - TRACK FOOTER
register uint8_t XH_Save asm("r2");
register uint8_t XL_Save asm("r3");
register uint8_t ZH_Save asm("r4");
register uint8_t ZL_Save asm("r5");

register volatile uint8_t state asm("r6");
register volatile uint8_t SREGSave asm("r7");

register volatile uint8_t sector_byte asm("r8");
register volatile uint8_t track asm("r9");
register volatile uint8_t sector asm("r10");
register volatile uint8_t side asm("r11");
register volatile uint8_t data_sent asm("r12");
register volatile uint8_t second_byte asm("r13");
register volatile uint8_t prev_byte asm("r14");

register volatile uint8_t b_index asm("r17");
register volatile uint8_t tmp asm("r19");

//register volatile uint8_t trk00 = 0;

uint16_t CRC;

uint8_t MFM_tab[32] =
{
0xAA,0xA9,0xA4,0xA5,0x92,0x91,0x94,0x95,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
0x2A,0x29,0x24,0x25,0x12,0x11,0x14,0x15,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
};


// STEP pin interrupt
ISR(INT0_vect)
{
if ((PIND & (1 << DIR_SEL))==0) {
track++;
if (track > 79) track = 79; // !!!!!!!!!!!!!!!! use max track calculated on mounting TRD
}
else
{
if (track > 0) track--;
}
sector = 1;
}

ISR(USART_UDRE_vect, ISR_NAKED)
{
asm ("in r7,0x3F"); // save SREG
asm ("mov r2,r24"); // save XH
asm ("mov r3,r25"); // save XL
asm ("mov r4,r30"); // save ZH
asm ("mov r5,r31"); // save ZL
if (!tmp) // it is ok, as MFM_tab doesn't have zero values
{ // Send first MFM byte

// GET DATA BYTE (REAL DATA NOT MFM)
switch (state)
{
case 0: // ------------------------------------------------------------
// send track GAP
switch (b_index)
{
case 0:
// set index LOW
PORTD &= ~(1 << INDEX);
sector_byte = 0x4E;
//set TRK00 LOW or HIGH
if (track == 0) PORTD &= ~(1 << TRK00); else PORTD |= (1 << TRK00);
break;

case 78:
// set index HIGH
PORTD |= (1 << INDEX);
break;

case 80:
sector_byte = 0;
break;

case 92:
sector_byte = 0xC2; // translate this value!
case 93:
case 94:
second_byte = 0x24;
break;

case 95:
sector_byte = 0xFC;
break;

case 96:
sector_byte = 0x4E;
break;
}
b_index++;
if (b_index != 146) break;
state = 1;
b_index = 0;
break;

case 1: // ------------------------------------------------------------
switch (b_index)
{
case 0:
CRC = 0xB230;
CRC ^= track*256;
break;

case 1:
case 2:
case 3:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
break;

case 4:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
tmp = PINC;
tmp ^= 1;
tmp &= 1;
side = tmp;
break;

case 5:
sector_header[16] = track;
sector_header[17] = side;
CRC ^= side*256;
break;

case 6:
case 7:
case 8:
case 9:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
break;

case 10:
CRC ^= sector*256;
break;

case 11:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
break;

case 12:
case 13:
case 14:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
second_byte = 0x89;
break;

case 15:
sector_header[18] = sector;
CRC ^= 256; // sector size;
break;

case 16:
case 17:
case 18:
case 19:
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
break;

case 20:
sector_header[20] = (byte)(CRC >> 8);
break;

case 21:
sector_header[21] = (byte)CRC;
/*if(sector == 1 && side == 0 && CRC != 0xFA0C) {
cli();
while(1);
}*/
break;

case 56:
case 57:
case 58:
second_byte = 0x89;
break;
}
// send sector bytes before data
sector_byte = sector_header[b_index]; // pre-get new byte from buffer
b_index++;
if (b_index != 60) break;

b_index = 0;
state = 2;
// START GENERATING CRC HERE, PRE-CALC value for A1,A1,A1,FB = 0xE295
CRC = 0xE295; // next CRC value
data_sent = 0;
break;

case 2: // ------------------------------------------------------------
// get sector data values
sector_byte = sector_data[b_index]; // pre-get new byte from buffer
// CALCULATE CRC HERE!
CRC ^= sector_byte << 8; // sector size;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;
CRC = CRC & 0x8000 ? (CRC << 1) ^ 0x1021 : CRC << 1;

if (b_index != 255)
{
b_index++;
break;
}
state = 3;
b_index = 0;
break;

case 3:
// send CRC + sector footer
if (b_index == 0)
sector_byte = (byte)(CRC >> 8);
else if (b_index == 1)
sector_byte = (byte)CRC;
else sector_byte = 0x4E;

b_index++;

if (b_index != 24) break;

if (sector <= 15)
{
sector++; // increase sector
data_sent = 1;
state = 1;
b_index = 0;
break;
}
sector = 1;
data_sent = 1;

state = 4;
b_index = 0;
break;

case 4:
// send track footer
sector_byte = 0x4E;
b_index++;

if (b_index != 80) break;

state = 0;
b_index = 0;
break;
}
// PRE-FETCH END


// tmp = sector_byte;
// tmp >>= 4;
asm(
"mov r19,r8\n" //tmp = sector_byte;
"swap r19\n" //tmp >>= 4; -------------
"andi r19,0x0f" // -----------------------
);

tmp = MFM_tab[tmp]; // get first MFM byte from table

if((prev_byte & 1) && !(sector_byte & 0x80)) tmp &= 0x7F;
UDR0 = ~tmp; // put byte to send buffer

}
else
{ // Send second MFM byte

prev_byte = sector_byte;

if (second_byte == 0)
{
tmp = sector_byte;
tmp &= 0x1f;
tmp = MFM_tab[tmp]; // get second MFM byte from table to "tmp"
}
else
{
tmp = second_byte;
second_byte = 0;
}

UDR0 = ~tmp; // put byte to send buffer

tmp = 0; // this is important!
}

asm ("mov r31,r5"); // restore ZL
asm ("mov r30,r4"); // restore ZH
asm ("mov r25,r3"); // restore XL
asm ("mov r24,r2"); // restore XH
asm ("out 0x3F,r7"); // restore SREG
reti();
}

void prepare_sector_header()
{
// Address field
byte i;
for(i=0; i <= 11; i++) sector_header[i] = 0x00; // 0x00(0)-0x0B(11) sync field
for(i=12; i <= 14; i++) sector_header[i] = 0xA1; // 0x0C(12)-0x0E(14) 3x0xA1
sector_header[15] = 0xFE; // 0x0F(15) 0xFE
// TRACK, SIDE, SECTOR
sector_header[16] = 0x00; // 0x10(16) track
sector_header[17] = 0x00; // 0x11(17) side
sector_header[18] = 0x01; // 0x12(18) sector
sector_header[19] = 0x01; // 0x13(19) sector len (256 bytes)
sector_header[20] = 0xFA; // 0x14(20) CRC1 for trk=0, side=0, sector=1
sector_header[21] = 0x0C; // 0x15(21) CRC2

// GAP 2
for(i=22; i <= 43; i++) sector_header[i] = 0x4E; // 0x16(22)-0x2B

// DATA field
for(i=44; i <= 55; i++) sector_header[i] = 0x00; // 0x2C(44)-0x37 sync field
for(i=56; i <= 58; i++) sector_header[i] = 0xA1; // 0x38(56)-0x3A
sector_header[59] = 0xFB; // 0x3B(59)
}

//alignas(256)
const byte track0[4096] PROGMEM =
{
0x62, 0x6F, 0x6F, 0x74, 0x20, 0x20, 0x20, 0x20, 0x42, 0xB4, 0x00, 0xB4, 0x00, 0x23, 0x00, 0x01,
0x46, 0x55, 0x4C, 0x4C, 0x20, 0x54, 0x48, 0x52, 0x42, 0x6D, 0x00, 0x6D, 0x00, 0x01, 0x03, 0x03,
0x66, 0x74, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x40, 0x9C, 0x00, 0x12, 0x12, 0x04, 0x03,
0x66, 0x74, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0xB4, 0x5F, 0x0A, 0x6E, 0x6F, 0x06, 0x04,
0x52, 0x41, 0x49, 0x4E, 0x42, 0x4F, 0x57, 0x2B, 0x42, 0x08, 0x01, 0x08, 0x01, 0x02, 0x05, 0x0B,
0x52, 0x41, 0x49, 0x4E, 0x42, 0x2E, 0x2B, 0x24, 0x43, 0x00, 0x40, 0x00, 0x1B, 0x1B, 0x07, 0x0B,
0x52, 0x41, 0x49, 0x4E, 0x42, 0x2E, 0x2B, 0x63, 0x43, 0xA8, 0x61, 0x58, 0x9E, 0x9F, 0x02, 0x0D,
0x52, 0x41, 0x49, 0x4E, 0x42, 0x2E, 0x2B, 0x73, 0x43, 0x00, 0x40, 0x08, 0x07, 0x08, 0x01, 0x17,
0x52, 0x41, 0x49, 0x31, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x57, 0x1A, 0x1B, 0x09, 0x17,
0x52, 0x41, 0x49, 0x32, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x1A, 0x1B, 0x1C, 0x04, 0x19,
0x52, 0x41, 0x49, 0x33, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x13, 0x1D, 0x1E, 0x00, 0x1B,
0x52, 0x41, 0x49, 0x34, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x26, 0x1D, 0x1E, 0x0E, 0x1C,
0x52, 0x41, 0x49, 0x35, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x92, 0x1C, 0x1D, 0x0C, 0x1E,
0x52, 0x41, 0x49, 0x36, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x08, 0x1E, 0x1F, 0x09, 0x20,
0x52, 0x41, 0x49, 0x37, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0x10, 0x1C, 0x1D, 0x08, 0x22,
0x52, 0x41, 0x49, 0x38, 0x20, 0x20, 0x20, 0x20, 0x43, 0x98, 0x00, 0xE3, 0x1F, 0x20, 0x05, 0x24,
0x50, 0x2E, 0x42, 0x4F, 0x41, 0x54, 0x34, 0x38, 0x42, 0x1F, 0x01, 0xF9, 0x00, 0x02, 0x05, 0x26,
0x50, 0x2E, 0x42, 0x31, 0x20, 0x20, 0x20, 0x20, 0x43, 0xFF, 0x00, 0x00, 0x1B, 0x1B, 0x07, 0x26,
0x50, 0x2E, 0x42, 0x32, 0x20, 0x20, 0x20, 0x20, 0x43, 0xA8, 0x61, 0x60, 0x9B, 0x9C, 0x02, 0x28,
0x53, 0x54, 0x5F, 0x43, 0x4F, 0x42, 0x52, 0x41, 0x42, 0xFF, 0x00, 0xEC, 0x00, 0x02, 0x0E, 0x31,
0x53, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0xBE, 0x6E, 0xCB, 0x07, 0x08, 0x00, 0x32,
0x53, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0xA8, 0x61, 0x58, 0x9E, 0x9F, 0x08, 0x32,
0x48, 0x49, 0x47, 0x48, 0x5F, 0x53, 0x5F, 0x52, 0x42, 0xE9, 0x00, 0xE9, 0x00, 0x01, 0x07, 0x3C,
0x48, 0x53, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x00, 0x40, 0x00, 0x1B, 0x1B, 0x08, 0x3C,
0x48, 0x53, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x00, 0x66, 0x00, 0x9A, 0x9A, 0x03, 0x3E,
0x53, 0x41, 0x49, 0x47, 0x4F, 0x4E, 0x31, 0x52, 0x42, 0x47, 0x01, 0x34, 0x01, 0x02, 0x0D, 0x47,
0x53, 0x43, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x43, 0x00, 0x7C, 0x00, 0x03, 0x03, 0x0F, 0x47,
0x53, 0x43, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x43, 0xA8, 0x61, 0x5A, 0x64, 0x65, 0x02, 0x48,
0x53, 0x43, 0x31, 0x24, 0x20, 0x20, 0x20, 0x20, 0x43, 0xBE, 0x6E, 0x33, 0x0B, 0x0C, 0x07, 0x4E,
0x53, 0x41, 0x4E, 0x58, 0x5F, 0x52, 0x55, 0x53, 0x42, 0x33, 0x02, 0x20, 0x02, 0x03, 0x03, 0x4F,
0x53, 0x41, 0x4E, 0x58, 0x2E, 0x31, 0x52, 0x20, 0x43, 0xA8, 0x61, 0x12, 0x3E, 0x3F, 0x06, 0x4F,
0x53, 0x41, 0x4E, 0x58, 0x2E, 0x32, 0x52, 0x20, 0x43, 0xF0, 0x6E, 0x00, 0x03, 0x03, 0x05, 0x53,
0x43, 0x2E, 0x53, 0x68, 0x65, 0x72, 0x77, 0x2E, 0x42, 0x66, 0x00, 0x66, 0x00, 0xA9, 0x08, 0x53,
0x4F, 0x56, 0x45, 0x52, 0x2E, 0x52, 0x55, 0x53, 0x42, 0x3F, 0x01, 0x2C, 0x01, 0x02, 0x01, 0x5E,
0x6F, 0x76, 0x6C, 0x31, 0x20, 0x20, 0x20, 0x20, 0x43, 0x40, 0x9C, 0xBA, 0x10, 0x11, 0x03, 0x5E,
0x6F, 0x76, 0x6C, 0x32, 0x20, 0x20, 0x20, 0x20, 0x43, 0xA8, 0x61, 0xA9, 0x99, 0x9A, 0x04, 0x5F,
0x6F, 0x76, 0x6C, 0x33, 0x20, 0x20, 0x20, 0x20, 0x43, 0x00, 0x7C, 0x00, 0x03, 0x03, 0x0E, 0x68,
0x56, 0x49, 0x58, 0x45, 0x4E, 0x2D, 0x33, 0x20, 0x42, 0xA5, 0x00, 0xA5, 0x00, 0xB3, 0x01, 0x69,
0x46, 0x52, 0x55, 0x49, 0x54, 0x2D, 0x49, 0x49, 0x42, 0x64, 0x00, 0x64, 0x00, 0x01, 0x04, 0x74,
0x46, 0x52, 0x55, 0x49, 0x54, 0x5F, 0x34, 0x38, 0x43, 0xC0, 0x5E, 0xBB, 0x95, 0x96, 0x05, 0x74,
0x57, 0x41, 0x54, 0x45, 0x52, 0x4D, 0x49, 0x4C, 0x42, 0x10, 0x01, 0x10, 0x01, 0x02, 0x0B, 0x7D,
0x57, 0x4D, 0x34, 0x38, 0x2F, 0x31, 0x32, 0x38, 0x43, 0x00, 0x40, 0x00, 0x00, 0xFF, 0x0D, 0x7D,
0x4B, 0x61, 0x62, 0x61, 0x6C, 0x69, 0x73, 0x74, 0x42, 0x00, 0x03, 0x00, 0x03, 0xD7, 0x0C, 0x8D,
0x55, 0x44, 0x41, 0x42, 0x2E, 0x52, 0x20, 0x20, 0x42, 0x24, 0x10, 0x24, 0x10, 0x11, 0x03, 0x9B,
0x75, 0x64, 0x61, 0x76, 0x20, 0x20, 0x20, 0x20, 0x43, 0x18, 0xF6, 0xE8, 0x09, 0x0A, 0x04, 0x9C,
0x00, 0x6F, 0x6F, 0x74, 0x20, 0x20, 0x20, 0x20, 0x42, 0xB4, 0x00, 0xB4, 0x00, 0x23, 0x02, 0x9B,
0x00, 0x61, 0x72, 0x75, 0x6D, 0x61, 0x7E, 0x32, 0x43, 0x00, 0x80, 0xFF, 0x05, 0x06, 0x02, 0x23,
0x00, 0x65, 0x73, 0x73, 0x69, 0x79, 0x61, 0x20, 0x43, 0x00, 0x80, 0x90, 0x05, 0x06, 0x08, 0x23,
0x00, 0x6F, 0x75, 0x6E, 0x64, 0x6D, 0x7E, 0x31, 0x43, 0x00, 0x80, 0xE4, 0x09, 0x0A, 0x0E, 0x23,
0x00, 0x74, 0x61, 0x72, 0x74, 0x32, 0x20, 0x20, 0x43, 0x00, 0x80, 0x76, 0x06, 0x07, 0x08, 0x24,
0x00, 0x68, 0x65, 0x66, 0x6C, 0x61, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x51, 0x03, 0x04, 0x0F, 0x24,
0x00, 0x6F, 0x72, 0x6C, 0x64, 0x20, 0x20, 0x20, 0x43, 0x00, 0x80, 0xF7, 0x02, 0x03, 0x03, 0x25,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x16, 0x05, 0x06, 0x06, 0x25,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x32, 0x43, 0x00, 0x80, 0x86, 0x07, 0x08, 0x0C, 0x25,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x33, 0x43, 0x00, 0x80, 0xD6, 0x0D, 0x0E, 0x04, 0x26,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x34, 0x43, 0x00, 0x80, 0x4C, 0x08, 0x09, 0x02, 0x27,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x35, 0x43, 0x00, 0x80, 0xBA, 0x0A, 0x0B, 0x0B, 0x27,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x36, 0x43, 0x00, 0x80, 0x5F, 0x06, 0x07, 0x06, 0x28,
0x00, 0x78, 0x63, 0x6C, 0x75, 0x62, 0x7E, 0x37, 0x43, 0x00, 0x80, 0xDE, 0x08, 0x09, 0x0D, 0x28,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x31, 0x43, 0x00, 0x80, 0xD9, 0x0A, 0x0B, 0x06, 0x29,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x32, 0x43, 0x00, 0x80, 0x9B, 0x07, 0x08, 0x01, 0x2A,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x33, 0x43, 0x00, 0x80, 0x7B, 0x0A, 0x0B, 0x09, 0x2A,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x34, 0x43, 0x00, 0x80, 0xC1, 0x09, 0x0A, 0x04, 0x2B,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x36, 0x43, 0x00, 0x80, 0x27, 0x0D, 0x0E, 0x0E, 0x2B,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x37, 0x43, 0x00, 0x80, 0x64, 0x13, 0x14, 0x0C, 0x2C,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x38, 0x43, 0x00, 0x80, 0xD5, 0x08, 0x09, 0x00, 0x2E,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x61, 0x7E, 0x39, 0x43, 0x00, 0x80, 0xC0, 0x09, 0x0A, 0x09, 0x2E,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x30, 0x43, 0x00, 0x80, 0x08, 0x0B, 0x0C, 0x03, 0x2F,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x31, 0x43, 0x00, 0x80, 0x01, 0x07, 0x08, 0x0F, 0x2F,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x32, 0x43, 0x00, 0x80, 0x8B, 0x07, 0x08, 0x07, 0x30,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x33, 0x43, 0x00, 0x80, 0x98, 0x06, 0x07, 0x0F, 0x30,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x34, 0x43, 0x00, 0x80, 0x8E, 0x10, 0x11, 0x06, 0x31,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x35, 0x43, 0x00, 0x80, 0xF7, 0x06, 0x07, 0x07, 0x32,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x36, 0x43, 0x00, 0x80, 0xF1, 0x06, 0x07, 0x0E, 0x32,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x37, 0x43, 0x00, 0x80, 0x00, 0x0A, 0x0A, 0x05, 0x33,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x38, 0x43, 0x00, 0x80, 0x38, 0x0E, 0x0F, 0x0F, 0x33,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x31, 0x39, 0x43, 0x00, 0x80, 0xEA, 0x04, 0x05, 0x0E, 0x34,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x32, 0x30, 0x43, 0x00, 0x80, 0x57, 0x0A, 0x0B, 0x03, 0x35,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x32, 0x31, 0x43, 0x00, 0x80, 0xC4, 0x05, 0x06, 0x0E, 0x35,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x32, 0x32, 0x43, 0x00, 0x80, 0x81, 0x06, 0x07, 0x04, 0x36,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x32, 0x33, 0x43, 0x00, 0x80, 0xAD, 0x16, 0x17, 0x0B, 0x36,
0x00, 0x75, 0x6E, 0x65, 0x72, 0x7E, 0x32, 0x34, 0x43, 0x00, 0x80, 0xB5, 0x09, 0x0A, 0x02, 0x38,
0x00, 0x65, 0x77, 0x79, 0x65, 0x61, 0x7E, 0x31, 0x43, 0x00, 0x80, 0xC6, 0x06, 0x07, 0x0C, 0x38,
0x00, 0x61, 0x72, 0x75, 0x6D, 0x61, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x1E, 0x03, 0x04, 0x03, 0x39,
0x00, 0x69, 0x6E, 0x67, 0x62, 0x6F, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x49, 0x05, 0x06, 0x07, 0x39,
0x00, 0x69, 0x6E, 0x67, 0x62, 0x6F, 0x7E, 0x32, 0x43, 0x00, 0x80, 0xF2, 0x05, 0x06, 0x0D, 0x39,
0x00, 0x61, 0x74, 0x76, 0x61, 0x39, 0x20, 0x20, 0x43, 0x00, 0x80, 0x5A, 0x06, 0x07, 0x03, 0x3A,
0x00, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x20, 0x20, 0x43, 0x00, 0x80, 0x65, 0x06, 0x07, 0x0A, 0x3A,
0x00, 0x72, 0x65, 0x65, 0x6C, 0x6F, 0x76, 0x65, 0x43, 0x00, 0x80, 0x03, 0x07, 0x08, 0x01, 0x3B,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x75, 0x0B, 0x0C, 0x09, 0x3B,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x32, 0x43, 0x00, 0x80, 0xA1, 0x04, 0x05, 0x05, 0x3C,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x33, 0x43, 0x00, 0x80, 0x05, 0x0C, 0x0D, 0x0A, 0x3C,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x34, 0x43, 0x00, 0x80, 0x90, 0x05, 0x06, 0x07, 0x3D,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x35, 0x43, 0x00, 0x80, 0x3C, 0x04, 0x05, 0x0D, 0x3D,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x36, 0x43, 0x00, 0x80, 0xA2, 0x06, 0x07, 0x02, 0x3E,
0x00, 0x75, 0x6E, 0x6E, 0x79, 0x62, 0x7E, 0x37, 0x43, 0x00, 0x80, 0x2B, 0x06, 0x07, 0x09, 0x3E,
0x00, 0x5F, 0x6D, 0x5F, 0x62, 0x6F, 0x62, 0x61, 0x43, 0x00, 0x80, 0x87, 0x03, 0x04, 0x00, 0x3F,
0x00, 0x6E, 0x76, 0x69, 0x73, 0x69, 0x7E, 0x31, 0x43, 0x00, 0x80, 0x07, 0x0A, 0x0B, 0x04, 0x3F,
0x00, 0x30, 0x6C, 0x64, 0x65, 0x61, 0x74, 0x68, 0x43, 0x00, 0x80, 0xB0, 0x03, 0x04, 0x0F, 0x3F,
0x00, 0x6F, 0x6C, 0x6F, 0x62, 0x6F, 0x7E, 0x31, 0x43, 0x00, 0x80, 0xE0, 0x08, 0x09, 0x03, 0x40,
0x00, 0x7A, 0x32, 0x5F, 0x35, 0x20, 0x20, 0x20, 0x43, 0x00, 0x80, 0x20, 0x06, 0x07, 0x0C, 0x40,
0x00, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x31, 0x38, 0x43, 0x00, 0x80, 0xAE, 0x06, 0x07, 0x03, 0x41,
0x00, 0x61, 0x72, 0x61, 0x7A, 0x6D, 0x35, 0x20, 0x43, 0x00, 0x80, 0xC9, 0x02, 0x03, 0x0A, 0x41,
0x00, 0x70, 0x65, 0x63, 0x74, 0x72, 0x65, 0x32, 0x43, 0x00, 0x80, 0x7F, 0x04, 0x05, 0x0D, 0x41,
0x00, 0x74, 0x6F, 0x70, 0x66, 0x69, 0x72, 0x65, 0x43, 0x00, 0x80, 0xD4, 0x07, 0x08, 0x02, 0x42,
0x00, 0x6E, 0x6B, 0x6E, 0x32, 0x20, 0x20, 0x20, 0x43, 0x00, 0x80, 0xB3, 0x05, 0x06, 0x0A, 0x42,
0x00, 0x6E, 0x6B, 0x6E, 0x33, 0x20, 0x20, 0x20, 0x43, 0x00, 0x80, 0x63, 0x05, 0x06, 0x00, 0x43,
0x00, 0x6E, 0x6B, 0x6E, 0x34, 0x20, 0x20, 0x20, 0x43, 0x00, 0x80, 0xAA, 0x03, 0x04, 0x06, 0x43,
0x00, 0x5F, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x20, 0x43, 0x00, 0x80, 0xA1, 0x05, 0x06, 0x0A, 0x43,
0x00, 0x5F, 0x77, 0x65, 0x61, 0x72, 0x20, 0x20, 0x43, 0x00, 0x80, 0x4D, 0x06, 0x07, 0x00, 0x44,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x9C, 0x16, 0x2D, 0x32, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x11, 0x00, 0x44, 0x55, 0x47, 0x4C, 0x41, 0x53, 0x20, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};


// read sector
void read_sector()
{
byte i = 0;
while(1)
{
sector_data[i] = pgm_read_byte_near(track0 + i + (sector-1)*256);
if(i==255) break;
i++;
}
}


int main() {
// init();

cli();
prepare_sector_header();

// Setup USART in MasterSPI mode 500000bps
//DDRD |= (1 << DDD4);
UBRR0H = 0x00;
UBRR0L = 0x0F; // 500 kbps
UCSR0C = 0xC0;
UCSR0A = 0x00;
UCSR0B = 0x28; // enable USART

//INIT INT0 interrupt
EICRA = 0x03; // falling edge=2, rising edge=3
EIFR = 0x01; // clear interrupt flag
EIMSK = 0x01; // enable INT0

// AFTER TRD is MOUNTED

PORTC |= ((1 << MOTOR_ON) | (1 << DRIVE_SEL) | (1 << SIDE_SEL));

//SET INDEX,TRK00 AS OUTPUT AND HIGH, WP AS OUTPUT AND LOW
//PORTD |= ((1 << INDEX) | (1 << TRK00)); // set 1
//PORTD |= (1 << STEP) | (1 << DIR_SEL);
PORTD = 255;
//////PORTD &= ~(1 << READ_DATA); // set 0
PORTD &= ~(1 << WP); // set 0
DDRD |= ((1 << INDEX) | (1 << TRK00) | (1 << WP));

// ---------------------------------------------------

while (1)
{
uint16_t sector_offset;

while ((PINC & (1 << MOTOR_ON)) > 0);

// this part is after motor on and drive sel --------
PORTD &= ~(1 << TRK00); // set 0
tmp = 0;
state = 0;
b_index = 0;
prev_byte = 0x4E;
second_byte = 0;
sector = 1;
track = 0;
side = 0;
data_sent = 0;

read_sector();


sei(); // ENABLE INTERRUPTS

do
{
while (data_sent != 1);
// read next half of sector
read_sector();

if (data_sent == 0) { cli(); while (1); } // speed test
while (data_sent != 0);
}
while ((PINC & (1 << MOTOR_ON)) == 0);
cli(); // DISABLE INTERRUPTS
PORTD |= (1 << TRK00);
}
}


Теперь наконец-то можно спокойно поспать :-D

AlexNN
29.03.2016, 12:08
Отлично! А что за проблема была постом ранее?

ps увидел, не превыкну, что здесь принято сообщения старые дополнять)

- - - Добавлено - - -

Ещё бы в итоге оставить независимость блока работы с дисководом, чтобы не вплеталось в него работа с картой памяти, дисплеем и прочим, чтобы при желании использовать с другим дисплеем например или совсем без него.

- - - Добавлено - - -

Где-то выше было про открытый проект и обучающий вроде)
Давно не программировал, но всё это интересно уровне хобби,
если можно опишите структуру уже написанной программы,
возможно добавите обобщающие комментарии непосредственно в коде?

ps надо купить ардуино, на досуге повторить этот проект и кормушку для кота сделать давно задумал.

EvgenRU
29.03.2016, 23:15
Что-то с картой пока что засада, не успевает нифига... походу надо 2 дорожки всё-таки в памяти держать :( придется что-то думать, возможно ардуину придется исключить... Первое, что приходит на ум - это ATMEGA1284P :-D (700р DIP, 200р QFP)

AlexNN
30.03.2016, 00:23
Извиняюсь за очередной, возможно странный вопрос, но почему не последовательную память использовать для буфера?
вроде такой http://arduino-related.livejournal.com/1414.html

EvgenRU
30.03.2016, 01:10
Извиняюсь за очередной, возможно странный вопрос, но почему не последовательную память использовать для буфера?
вроде такой http://arduino-related.livejournal.com/1414.html

Идея хорошая, но, думаю работать не будет такой вариант, т.к. у нас очень прожорливое прерывание работает. Последовательная передача будет практически невозможна. Хотя, тут нужно еще подумать, но сомневаюсь. Нужна SRAM доступная параллельно. Здесь есть 2 варианта, выбрать дорогой AVR с 16к памяти или перейти на PIC, STM32 и т.д. Еще можно использовать RAW формат флешки и данные получать по прерыванию.

Ну, и, совсем сумасшедший вариант, читать данные двух дорожек во флеш атмеги, а потом из флеша отдавать ))) Вопрос только долго она проживет...

PS: еще можно сделать таблицу кластеров для дорожки и читать её по таймеру, но это очень долго ковырять, если будет много времени свободного...

newart
30.03.2016, 01:48
Еще можно использовать RAW формат флешки и данные получать по прерыванию.
Почему бы и нет?

Накидать за вечер удобный конвертор не проблема.

Как вариант, можно сделать что-бы сама ардуинка в фоновом режиме конвертила trd в raw.
RAW это MFM формат подразумевается?

s_kosorev
30.03.2016, 02:54
Идея хорошая, но, думаю работать не будет такой вариант, т.к. у нас очень прожорливое прерывание работает
так там финтов можно накрутить и укоротить, вместо тех же case и fsm можно заюзать указатель на простые naked функции, мутки с mfm не понятны, почему не хранить целиком таблицу? места есть а проца не хватает
так же, куча регистров зарезервировано, компилятор начинает городить когда ему регистров не хватает, в общем как по мне, есть где над ISR поработать

- - - Добавлено - - -

служебную область и данных разными ISR формировать, по указателю скакать, в общем несколько но простых обработчиков сделать чем один навороченый и по максимуму ветвления за скобки

kasper
30.03.2016, 08:02
Может попробуете на http://olx.ua/obyavlenie/arduino-32-bit-72-mgts-maple-mini-stm32-IDcjqJP.html#da342014cf, точно должно времени хватить

EvgenRU
30.03.2016, 08:07
Может попробуете на http://olx.ua/obyavlenie/arduino-32-bit-72-mgts-maple-mini-stm32-IDcjqJP.html#da342014cf, точно должно времени хватить

На этой штуке точно хватит :-D но хотелось бы на ардуине

UPD:
Еще мне видится вполне работоспособным такой вариант

Инициализируем передачу даннах с SD карты, пропускаем нужное число байт в кластере до начала сектора.
После чего в прерывании читаем данные не из буфера а по SPI с SD карты. В данном случае пропускается несколько промежуточных шагов и нет необходимости ждать чтения всего сектора.

tnt23
30.03.2016, 08:57
По поводу чтения SD через SPI. У AVR SPI молотит максимум на половине тактовой частоты, это ограничение плюс необходимость в худшем случае вычитывать все 512 байт сектора позволяют прикинуть типичные траты по времени.

trader2k4
30.03.2016, 10:34
На этой штуке точно хватит :-D но хотелось бы на ардуине

Раз пошла такая пьянка - есть же Arduino Mega (да простят меня Arduino-хейтеры), стоит в Китае меньше 500р в сборе:http://ru.aliexpress.com/item/Mega-2560-R3-Mega2560-REV3-ATmega2560-16AU-CH340G-Board-ON-USB-Cable-compatible-for-arduino-No/ (http://ru.aliexpress.com/item/Mega-2560-R3-Mega2560-REV3-ATmega2560-16AU-CH340G-Board-ON-USB-Cable-compatible-for-arduino-No/32363357651.html?spm=2114.30010708.3.38.EuCyio&ws_ab_test=searchweb201556_1,searchweb201602_2_100 17_10010_10011_10018_10019_10036_10035_10034_301_5 07_10033_10032_10020_10001_10002_10005_10006_10021 _10003_10022_10004_401_10009_10007_10008,searchweb 201603_9&btsid=2767ecfd-9976-4a3a-923d-de5a7a71bae0)

Почему не взять её? Возни с пайкой нет, ног просто море, можно LCD без I2C-переходника (если приспичит) прицепить и ещё останутся!

И вопрос - с какой SD-шкой тестируете? Может, просто карта тормозная?

AlexNN
30.03.2016, 11:31
В регистраторах явно никто не парится о ресурсе флешки, тем не менее годами служат, конечно совсем не думать о ресурсе не стоит,
но здесь трафик и объем небольшие получаются,
можно создать временный файл на несколько мегабайт и последовательно его использовать несколько раз,
затем создать новый временный и стереть предыдущий, это если получится хранить буфер на карте.

По-моему надо постараться остаться на ардуине, что ближе к первоначальной задумке простого и недорогого устройства,
это способствует популярности проекта, т.к. нет препятствия в создании платы и монтаже.
Мало ли, возможно в результате оптимизация дойдет и до Atmega8)

Производительности для основного блока по передаче данных на fdd уже хватает, остальное мелочи)

Trol73
30.03.2016, 16:52
По поводу производительности AVR и SD - нужно для начала оценить, с какой скоростью требуется читать с карты.
По поводу ардуины - никогда не мог понять, почему некоторые так любят использовать эту хрень и плодить макаронных монстров на её основе. Когда можно развести нормальную печатную плату и поиметь аккуратный девайс на одной плате без клубка МГТФа. При том, что по стоимости получится не дороже (или ненамного дороже) бабуины.
По поводу дисплея - вчера соорудил для тестера микросхем такой дисплейный модуль (красная платка) (http://zx-pk.ru/showthread.php?t=25406&page=14&p=862819&viewfull=1#post862819) - экран от nokia 5110 + 5 клавиш. Рулится по двум проводкам (UART). По стоимости получается почти как 1602 с i2c контроллером (ну или чуть дороже), а возможностей куда больше. Особенно для устройства, интерфейс которого требует навигации по файловой системе

s_kosorev
30.03.2016, 17:00
adruino это удобно, хотя ни разу не юзал её среду, AvrStudio это то что реально делает AVR на голову выше ARM, платные среды с кряками не мой путь, CLion + gcc/calng + cmake + stm32 что то не получилось завести пока

AlexNN
30.03.2016, 17:32
Можно сделать прототип на ардуине, и уже релиз на отдельной плате для красоты, если проект некоммерческий,
то возможность воспроизвести его на коленке - хороший фактор, для жизнеспособности девайса.

EvgenRU
30.03.2016, 21:47
Arduino Mega это вариант, 8к SRAM достаточно, чтобы держать дорожку в памяти, конечно 16к было бы оптимальнее, но 8к это уже что-то не нужно др..чить карту каждые 12мс, а при переключении сторон отключать прерывания, не будет генерироваться INDEX и контроллер будет спокойно ждать его появления после обновления данных.

Насчет MFM таблицы урезанной, ну, тут я подумал, зачем 512 байт в памяти держать, когда там всего один AND, не так уж много он циклов отнимает, особенно для регистра r19.

Пока что буду оптимизировать ISR, потом скорее всего буду думать в сторону Arduino Mega.


UPD:
Сейчас пытаюсь добиться нормальной работы двух дорожек из флеша ардуины, переделал расчет CRC по таблице, заметно увеличилась производительность, даже почти нормально грузится BOOT из второй дорожки.
Всё, дооптимизировал, что бут нормально загружается :)


Вот пример, где грузится бут нормально.

// ZX-Spectrum FDD Emulator
//
//#include <petit_fatfs.h>

#define SIDE_SEL PC0 // SIDE SELECT (INPUT)
#define DRIVE_SEL PC1 // DRIVE SELECT CONNECT DS0-DS3 using jumper (INPUT) /// not used yet
#define MOTOR_ON PC2 // MOTOR ON (INPUT)

#define WRT_GATE PB0 // WRITE GATE (INPUT) /// not used yet
#define WRT_DATA PB1 // WRITE DATA (INPUT) /// not used yet

#define READ_DATA PD1 // READ_DATA (OUTPUT) /// defined in USART
#define STEP PD2 // STEP (INPUT)
#define DIR_SEL PD3 // DIRECTION SELECT (INPUT)
// PD4 UNABLE TO USE!!
#define INDEX PD5 // INDEX (OUTPUT)
#define TRK00 PD6 // TRACK 00 (OUTPUT)
#define WP PD7 // WRITE PROTECT (OUTPUT)


uint8_t sector_header[64]; // sector header
uint8_t track_header[146]; // track header
uint8_t sector_data[256]; // sector data

// STATE variable values
// 0-1 - TRACK HEADER
// 2-7 - SECTOR
// 8 - TRACK FOOTER
uint8_t state;
uint8_t sector_byte;
uint8_t prev_byte;
uint8_t second_byte;
uint8_t tmp;
uint8_t b_index;
uint16_t CRC;
volatile uint8_t track;
volatile uint8_t sector;
volatile uint8_t side;
volatile uint8_t data_sent;

uint8_t MFM_tab[32] =
{
0xAA,0xA9,0xA4,0xA5,0x92,0x91,0x94,0x95,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
0x2A,0x29,0x24,0x25,0x12,0x11,0x14,0x15,0x4A,0x49, 0x44,0x45,0x52,0x51,0x54,0x55,
};

const uint16_t Crc16Table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};


// STEP pin interrupt
ISR(INT0_vect)
{
if ((PIND & (1 << DIR_SEL))==0) {
track++;
if (track > 79) track = 79; // !!!!!!!!!!!!!!!! use max track calculated on mounting TRD
}
else
{
if (track > 0) track--;
}
sector = 1;
}

ISR(USART_UDRE_vect)
{
if (!tmp) // it is ok, as MFM_tab doesn't have zero values
{ // Send first MFM byte
// GET DATA BYTE (REAL DATA NOT MFM)
switch (state)
{
case 0: // start track header -----------------------------------------
// set index LOW
PORTD &= ~_BV(INDEX);
//set TRK00 LOW or HIGH
if (track == 0) PORTD &= ~(1 << TRK00); else PORTD |= (1 << TRK00);
sector_byte = 0x4E;
b_index = 1;
state = 1;
break;

case 1: // send track header ------------------------------------------
sector_byte = track_header[b_index];
if(sector_byte == 0xC2) second_byte = 0x24;
b_index++;
if (b_index != 146) break;
state = 2;
b_index = 0;
break;

case 2: // ------------------------------------------------------------
switch (b_index)
{
case 0:
// set INDEX high
PORTD |= _BV(INDEX);
CRC = 0xB230;
break;

case 1:
CRC = (CRC << 8) ^ Crc16Table[(CRC >> 8) ^ track];
break;

case 2:
CRC = (CRC << 8) ^ Crc16Table[(CRC >> 8) ^ side];
break;

case 3:
CRC = (CRC << 8) ^ Crc16Table[(CRC >> 8) ^ sector];
break;

case 4:
CRC = (CRC << 8) ^ Crc16Table[(CRC >> 8) ^ 1]; // sector size 1 = 256;
break;

case 5:
sector_header[16] = track;
sector_header[17] = side;
break;

case 12:
case 13:
case 14:
second_byte = 0x89;
break;

case 15:
sector_header[18] = sector;
sector_header[20] = (byte)(CRC >> 8);
sector_header[21] = (byte)CRC;
/*if(sector == 1 && side == 0 && CRC != 0xFA0C) {
cli();
while(1);
}*/
break;

case 56:
case 57:
case 58:
second_byte = 0x89;
break;
}
// send sector bytes before data
sector_byte = sector_header[b_index++]; // pre-get new byte from buffer
if (b_index != 60) break;

b_index = 0;
state = 3;
// START GENERATING CRC HERE, PRE-CALC value for A1,A1,A1,FB = 0xE295
CRC = 0xE295; // next CRC value
data_sent = 0;
break;

case 3: // ------------------------------------------------------------
// get sector data values
sector_byte = sector_data[b_index++]; // pre-get new byte from buffer
CRC = (CRC << 8) ^ Crc16Table[(CRC >> 8) ^ sector_byte];
if (b_index != 0) break;

state = 4;
break;

case 4:
if(bit_is_set(PINC, SIDE_SEL)) side = 0; else side = 1;
sector_byte = (byte)(CRC >> 8);
state = 5;
// b_index = 0; not needed
break;

case 5:
if (sector <= 15)
{
sector++; // increase sector
data_sent = 1;
}
sector_byte = (byte)CRC;
state = 6;
break;

case 6:
sector_byte = 0x4E;
state = 7;
break;

case 7:
b_index++;

if (b_index != 56) break;

if (data_sent)
{
state = 2;
b_index = 0;
break;
}
sector = 1;
data_sent = 1;

state = 8;
b_index = 0;
break;

case 8:
// send track footer
if (++b_index != 200) break;

state = 0;
b_index = 0;
break;
}
// PRE-FETCH END


tmp = sector_byte;
tmp >>= 4;

tmp = MFM_tab[tmp]; // get first MFM byte from table

if((prev_byte & 1) && !(sector_byte & 0x80)) tmp &= 0x7F;
UDR0 = ~tmp; // put byte to send buffer

}
else
{ // Send second MFM byte
prev_byte = sector_byte;

if (second_byte == 0)
{
tmp = sector_byte;
tmp &= 0x1f;
tmp = MFM_tab[tmp]; // get second MFM byte from table to "tmp"
}
else
{
tmp = second_byte;
second_byte = 0;
}

UDR0 = ~tmp; // put byte to send buffer

tmp = 0; // this is important!
}
}

void prepare_sector_header()
{
// Address field
byte i;
for(i=0; i <= 11; i++) sector_header[i] = 0x00; // 0x00(0)-0x0B(11) sync field
for(i=12; i <= 14; i++) sector_header[i] = 0xA1; // 0x0C(12)-0x0E(14) 3x0xA1
sector_header[15] = 0xFE; // 0x0F(15) 0xFE
// TRACK, SIDE, SECTOR
sector_header[16] = 0x00; // 0x10(16) track
sector_header[17] = 0x00; // 0x11(17) side
sector_header[18] = 0x01; // 0x12(18) sector
sector_header[19] = 0x01; // 0x13(19) sector len (256 bytes)
sector_header[20] = 0xFA; // 0x14(20) CRC1 for trk=0, side=0, sector=1
sector_header[21] = 0x0C; // 0x15(21) CRC2

// GAP 2
for(i=22; i <= 43; i++) sector_header[i] = 0x4E; // 0x16(22)-0x2B

// DATA field
for(i=44; i <= 55; i++) sector_header[i] = 0x00; // 0x2C(44)-0x37 sync field
for(i=56; i <= 58; i++) sector_header[i] = 0xA1; // 0x38(56)-0x3A
sector_header[59] = 0xFB; // 0x3B(59)
}

void prepare_track_header()
{
// Address field
byte i;
for(i=0; i < 80; i++) track_header[i] = 0x4E;
for(i=80; i < 92; i++) track_header[i] = 0x00;
sector_header[92] = 0xC2;
sector_header[93] = 0xC2;
sector_header[94] = 0xC2;
sector_header[95] = 0xFC;
for(i=96; i < 146; i++) track_header[i] = 0x4E;
}


alignas(256) const byte track0[16][256] PROGMEM =
{
0x62,0x6F,0x6F,0x74,0x20,0x20,0x20,0x20,0x42,0x89, 0x06,0x00,0x00,0x07,0x00,0x01,
0x44,0x49,0x5A,0x5A,0x59,0x31,0x2E,0x52,0x42,0xD9, 0x02,0x00,0x00,0xA0,0x07,0x01,
0x44,0x49,0x5A,0x5A,0x59,0x32,0x2E,0x52,0x42,0xD1, 0x01,0x00,0x00,0xAF,0x07,0x0B,
0x44,0x49,0x5A,0x5A,0x59,0x33,0x2E,0x52,0x42,0xD9, 0x02,0x00,0x00,0xCD,0x06,0x16,
0x44,0x49,0x5A,0x5A,0x33,0x2E,0x35,0x52,0x42,0x90, 0x00,0x90,0x00,0x9D,0x03,0x23,
0x44,0x49,0x5A,0x5A,0x59,0x20,0x34,0x52,0x42,0xFA, 0x00,0x0E,0x00,0x64,0x00,0x2D,
0x44,0x49,0x5A,0x5A,0x59,0x20,0x34,0x52,0x43,0x00, 0x00,0x00,0x00,0xC4,0x04,0x33,
0x44,0x49,0x5A,0x5A,0x59,0x20,0x35,0x52,0x42,0x92, 0x00,0x92,0x00,0xFF,0x08,0x3F,
0x44,0x49,0x5A,0x5A,0x59,0x20,0x35,0x52,0x20,0x00, 0x00,0x00,0x00,0xB1,0x07,0x4F,
0x44,0x49,0x5A,0x5A,0x59,0x20,0x36,0x52,0x42,0x93, 0x00,0x93,0x00,0xE5,0x08,0x5A,
0x53,0x45,0x59,0x4D,0x4F,0x55,0x52,0x31,0x42,0xAB, 0x00,0xAB,0x00,0x7B,0x0D,0x68,
0x53,0x45,0x59,0x4D,0x4F,0x55,0x52,0x32,0x42,0xF2, 0x00,0x10,0x00,0xBF,0x08,0x70,
0x53,0x45,0x59,0x4D,0x4F,0x55,0x52,0x32,0x43,0x00, 0x00,0x00,0x00,0xB8,0x07,0x7C,
0x52,0x4F,0x42,0x4F,0x43,0x4F,0x50,0x33,0x42,0x5B, 0x00,0x5B,0x00,0x7B,0x0F,0x87,
0x72,0x6F,0x62,0x6F,0x63,0x6F,0x70,0x33,0x53,0x00, 0x00,0x00,0x00,0xFF,0x0A,0x8F,
0x00,0x41,0x57,0x53,0x2B,0x20,0x20,0x20,0x42,0xAD, 0x00,0x9A,0x00,0x94,0x02,0x96,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x41,0x64,0x76,0x61,0x6E,0x63,0x65,0x64,0x20,0x44, 0x69,0x73,0x6B,0x20,0x53,0x65,
0x72,0x76,0x69,0x63,0x65,0x20,0x76,0x2E,0x20,0x31, 0x2E,0x30,0x31,0x20,0x7F,0x20,
0x31,0x39,0x39,0x33,0x20,0x56,0x6C,0x61,0x64,0x69, 0x6D,0x69,0x72,0x20,0x56,0x61,
0x73,0x69,0x6C,0x65,0x76,0x73,0x6B,0x69,0x6A,0x2E, 0x4D,0x69,0x50,0x68,0x26,0x54,
0x20,0x48,0x41,0x43,0x4B,0x45,0x52,0x20,0x43,0x4C, 0x55,0x42,0x2E,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x09,0x9F,0x16,0x0F,0x07,0x00,0x10,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x67,0x61,0x6D,0x65,0x73, 0x30,0x32,0x33,0x00,0x00,0x00,
0x00,0x01,0xF6,0x02,0xF9,0xC0,0xB0,0x22,0x32,0x33, 0x38,0x38,0x34,0x22,0x3A,0xEA,
0x3A,0xAF,0xD3,0xFE,0x21,0x00,0x40,0xE5,0xD1,0x13, 0x01,0xFF,0x1A,0x75,0xED,0xB0,
0x21,0x68,0x5D,0x11,0x00,0xDE,0x01,0x00,0x03,0xD5, 0xED,0xB0,0xC9,0xF3,0x3E,0x70,
0x21,0x14,0xDE,0x06,0xA7,0xED,0x4F,0xED,0x5F,0xED, 0x7E,0xEE,0x40,0xAE,0x77,0x23,
0x10,0xC7,0x3D,0xA5,0x6C,0x7A,0x81,0x68,0x71,0x7A, 0xEE,0x62,0x15,0x1E,0xCA,0x6F,
0x39,0xAF,0x17,0xBA,0x2C,0xC8,0x18,0x5B,0x11,0x33, 0xF5,0xA8,0xA0,0x98,0xDA,0x29,
0x8E,0x76,0xBC,0x93,0x07,0xBE,0xD8,0x52,0xA8,0x20, 0x88,0x75,0x5C,0x95,0x97,0x0A,
0xF0,0xBE,0x8C,0xA0,0x82,0x20,0x88,0xEE,0x94,0x36, 0xEA,0xD0,0x32,0x7C,0x01,0xF4,
0x58,0xB8,0xBB,0x98,0x08,0xEC,0x21,0x54,0x19,0x51, 0x34,0x0D,0x69,0xE4,0xC8,0xF0,
0xD4,0xF1,0x64,0x54,0x63,0x5F,0x6E,0xC8,0x0A,0x0C, 0x4F,0xA0,0x55,0x33,0x86,0xCB,
0xB8,0xE0,0xF4,0xD0,0x99,0x10,0xF1,0xA5,0x48,0x5D, 0x75,0x1C,0x6C,0x45,0xD0,0x66,
0x04,0x3F,0x45,0x53,0x0B,0xDC,0x2E,0x38,0xAA,0x0F, 0xD5,0x33,0x56,0x8C,0x8A,0xCB,
0x59,0x47,0xB8,0x5C,0x20,0x1B,0x65,0x41,0xC4,0xB0, 0x66,0x37,0xA4,0xBC,0xC3,0xC6,
0x37,0x3E,0x64,0x5D,0x89,0x9C,0xAA,0xDB,0x39,0x37, 0xA8,0x5C,0xC2,0x3E,0x45,0x11,
0xA4,0x20,0xF0,0x02,0xE4,0x8C,0xE3,0x86,0x46,0x94, 0x8B,0xD4,0x9F,0x50,0x67,0x04,
0xB3,0x62,0xCB,0xE4,0xA3,0xC9,0x12,0x1B,0xA5,0x3A, 0xD0,0x29,0x14,0x0B,0xD7,0x54,
0x30,0x1A,0x06,0x9F,0x16,0xF8,0xBC,0x53,0x29,0xFD, 0x9B,0x6F,0x3C,0x96,0x99,0xA0,
0x3C,0xBD,0x43,0x69,0x5A,0x0A,0x72,0x36,0xA6,0x10, 0x06,0x26,0xC3,0x5D,0x10,0x49,
0xB3,0x27,0xDE,0xE8,0xE7,0xCE,0xC1,0x0D,0x08,0x0B, 0x16,0x71,0x1C,0xCA,0x24,0x9A,
0xF3,0xDD,0x76,0x6D,0xC1,0xF8,0xA1,0xA3,0xCB,0xAA, 0x68,0x7B,0xCB,0x07,0x30,0xA3,
0x07,0x72,0x44,0x2B,0x1E,0xD1,0x85,0x99,0x91,0x9D, 0x0C,0xC5,0x26,0x36,0x9D,0x9A,
0xCC,0x29,0xC2,0x03,0xDF,0x0F,0x0C,0x00,0x26,0x32, 0x99,0x7A,0x95,0x43,0x10,0x5C,
0xF6,0xAC,0x9D,0x53,0xE8,0xC8,0x04,0x27,0xAC,0x41, 0x92,0xF8,0x8F,0x35,0x43,0x92,
0x8F,0xB2,0x14,0xF5,0x2E,0xAB,0x8D,0x7A,0x62,0xEE, 0x1D,0x28,0x76,0xB9,0x97,0x9E,
0xE9,0xD3,0x24,0xAF,0xDB,0x6F,0xC4,0x9F,0xEE,0x11, 0xDE,0xA6,0x56,0x97,0xDD,0x1C,
0x84,0x94,0xA9,0x53,0xAD,0x0D,0xB9,0x57,0x31,0xAC, 0xC1,0xD6,0xE0,0x25,0xFA,0xA2,
0x6A,0xE7,0xA1,0x5F,0xA3,0xB1,0xC5,0x26,0x91,0xDE, 0x72,0x4B,0x38,0x01,0x49,0x0B,
0x26,0x16,0xE1,0x1E,0x77,0xEA,0x18,0x8E,0xAD,0x0F, 0x15,0x74,0xC6,0x8F,0x61,0x01,
0x66,0x62,0x6C,0x80,0x9F,0xAA,0x42,0xBD,0xB0,0x95, 0x4C,0xB8,0x6C,0x5B,0x12,0xAD,
0x89,0xF6,0x72,0x2E,0xC7,0x48,0x38,0x31,0xD3,0x7C, 0x9A,0xD8,0x5C,0x92,0xBE,0x2B,
0xA8,0x1B,0xF1,0x71,0xF4,0x16,0x3F,0x42,0xE3,0x1D, 0x74,0xEE,0x93,0x5D,0xFE,0xA7,
0x67,0xED,0x30,0x4C,0x0D,0x67,0xB5,0xA1,0xD3,0x44, 0xCB,0xE6,0x63,0x14,0x6D,0x6B,
0x75,0x67,0xD1,0x46,0x07,0x6B,0xC9,0x20,0x1A,0xB3, 0xE1,0xC8,0x21,0x22,0x3C,0x67,
0xD5,0x59,0x8E,0x31,0x4B,0xA6,0xA6,0x53,0xBD,0x3F, 0x7A,0x6D,0xAF,0x1C,0x6D,0x9A,
0xA9,0x69,0x4C,0x40,0x67,0x65,0x32,0x7D,0x7C,0x26, 0x79,0x77,0x2D,0x62,0x61,0x38,
0x34,0x69,0x36,0x50,0x6B,0x27,0x18,0x68,0x7C,0x1F, 0x09,0x7E,0x29,0x96,0xAD,0x28,
0x7B,0x79,0xB1,0xC0,0xA4,0xBA,0xBF,0x9F,0x4E,0x95, 0x99,0x44,0x12,0x76,0x38,0x1D,
0x8B,0x0A,0x46,0x04,0xE7,0xBA,0xE6,0x9E,0x0C,0x33, 0x69,0x07,0xF4,0x13,0xDD,0xEB,
0x98,0xF6,0x67,0x60,0x46,0xF6,0x69,0x98,0xD0,0x96, 0x97,0x3B,0x63,0xA2,0x21,0x23,
0x96,0x0D,0x1E,0xA0,0x45,0x67,0x58,0xFC,0x41,0x43, 0xC9,0xBB,0x42,0x2F,0x30,0x94,
0x51,0x3B,0xD1,0x71,0xE7,0x14,0x38,0xF9,0xD6,0x4C, 0xBD,0xAE,0xEA,0x14,0x61,0x7E,
0xB0,0xBE,0xD4,0xDD,0xCE,0xEF,0x57,0x9A,0x85,0x77, 0x0A,0x7D,0xDA,0x04,0x52,0xB9,
0xFE,0x8F,0x1F,0x48,0xCC,0xCF,0x42,0x34,0x6B,0x06, 0x8C,0x4F,0xF9,0xA7,0x3B,0xC2,
0x13,0x93,0x45,0x85,0x81,0x53,0xF3,0x55,0x0C,0x15, 0x5D,0xD8,0xBC,0x28,0x55,0x39,
0x34,0xD4,0x49,0xD4,0x3E,0xAE,0x35,0xEF,0xCE,0x9B, 0x0D,0x33,0x8C,0xA2,0xB8,0xBE,
0x4F,0x09,0x8F,0xBB,0xFD,0xD2,0x48,0x0B,0x15,0xE9, 0xF1,0x09,0xF6,0xF7,0x35,0x6E,
0xB5,0xAA,0x1E,0x43,0x6D,0xA1,0xA9,0x1F,0xA6,0x75, 0x32,0xB8,0xD5,0x54,0xF9,0xCB,
0xC0,0xE4,0x32,0x54,0xB5,0x70,0xE8,0xA5,0xEC,0x0D, 0x80,0xAA,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF7,0x3F, 0x4C,0x5B,0xCA,0x7E,0x09,0x03,
0xFF,0x3C,0x4C,0x5B,0xC5,0x7E,0x03,0x6E,0xF7,0x3F, 0x4C,0x5B,0xA7,0x7F,0x1E,0x49,
0xBE,0x3D,0xDC,0x5B,0xF7,0x7A,0x2B,0x54,0xD4,0x3D, 0x42,0x5B,0x0E,0x79,0x25,0x3F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBC,0x3D, 0xDE,0x5B,0x95,0x71,0x37,0x28,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBD,0x3D, 0xDF,0x5B,0x8F,0x71,0x52,0x41,
0x85,0x3D,0xE7,0x5B,0x11,0x74,0x60,0x2C,0xDC,0x3D, 0x5C,0x5B,0xD5,0x71,0x78,0x37,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x3D, 0x26,0x5B,0x1E,0x76,0x8F,0x20,
0x03,0x3F,0x61,0x59,0x32,0x7A,0x87,0x0B,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
};

alignas(256) const byte track1[16][256] PROGMEM =
{
0x00,0x01,0x1D,0x00,0xD4,0xC0,0x2E,0x0E,0x00,0x00, 0xF4,0x5E,0x00,0xF3,0x21,0x00,
0x3D,0x11,0x00,0x91,0x06,0x60,0xC5,0x01,0x04,0x00, 0xED,0xB0,0x06,0x04,0x7E,0xCB,
0x27,0xB6,0x12,0x23,0x13,0x10,0xF7,0xC1,0x10,0xEC, 0xC9,0x16,0x00,0x0E,0x4E,0x41,
0x4D,0x45,0x53,0x3A,0x3E,0xBF,0x90,0x47,0xA7,0x1F, 0x37,0x1F,0xA7,0x1F,0xA8,0xE6,
0xF8,0xA8,0x67,0x79,0x07,0x07,0x07,0xA8,0xE6,0xC7, 0xA8,0x07,0x07,0x6F,0x79,0xF6,
0xF8,0x2F,0xC9,0xC9,0xCD,0x6F,0x5D,0xCB,0x07,0xCB, 0x07,0xCB,0x07,0x06,0xC6,0x80,
0x32,0x9F,0x5D,0xCB,0x00,0xC9,0xCD,0x6F,0x5D,0xCB, 0x07,0xCB,0x07,0xCB,0x07,0x06,
0x86,0x80,0x32,0xB1,0x5D,0xCB,0x00,0xC9,0x3E,0x00, 0x32,0xF0,0x5E,0xCD,0xC2,0x5D,
0xCD,0xD2,0x5D,0xCD,0x27,0x63,0xC9,0x00,0xC5,0x01, 0x1F,0x00,0xED,0x78,0x21,0xF0,
0x5E,0xB6,0x32,0xF0,0x5E,0xC1,0xC9,0xC5,0x01,0xFE, 0xDF,0xED,0x78,0xE6,0x03,0xF5,
0x01,0xFE,0xFB,0xED,0x78,0xE6,0x01,0xCB,0x07,0xCB, 0x07,0xCB,0x07,0x57,0xF1,0xB2,
0xF5,0x01,0xFE,0xFD,0xED,0x78,0xE6,0x01,0xCB,0x07, 0xCB,0x07,0x57,0xF1,0xB2,0xF5,
0x01,0xFE,0x7F,0xED,0x78,0xE6,0x04,0xCB,0x07,0xCB, 0x07,0x57,0xF1,0xB2,0xC1,0x2F,
0xE6,0x1F,0x21,0xF0,0x5E,0xB6,0x32,0xF0,0x5E,0xC9, 0x00,0x00,0x00,0x00,0x00,0x0D,
0x00,0x01,0x00,0x00,0x0D,0x00,0x01,0x01,0x00,0x00, 0x0D,0x00,0x01,0x01,0x01,0x00,
0x00,0x0D,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x0D, 0x00,0x01,0x01,0x01,0x01,0x01,
0x00,0x00,0x0D,0x00,0x01,0x01,0x01,0x01,0x01,0x01, 0x00,0x00,0x0D,0x00,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x00,0x0D,0x00,0x01,0x01, 0x01,0x01,0x00,0x00,0x00,0x00,
0x0D,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x0D,0x00, 0x01,0x00,0x00,0x01,0x01,0x00,
0x0D,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x0D, 0x09,0x09,0x09,0x09,0x00,0x01,
0x01,0x00,0x0D,0x09,0x09,0x09,0x09,0x00,0x00,0x01, 0x00,0x0D,0x09,0x09,0x09,0x09,
0x09,0x00,0x01,0x00,0x0D,0x09,0x09,0x09,0x09,0x09, 0x00,0x00,0x00,0x0D,0xFF,0x21,
0x17,0x5E,0xED,0x4B,0xF1,0x5E,0xED,0x43,0xF3,0x5E, 0x7E,0xFE,0xFF,0xC8,0xFE,0x0D,
0x20,0x10,0x3A,0xF1,0x5E,0x32,0xF3,0x5E,0xDD,0x21, 0xF3,0x5E,0xDD,0x35,0x01,0x23,
0x18,0xE8,0xFE,0x09,0x20,0x09,0xE5,0x21,0xF3,0x5E, 0x34,0xE1,0x23,0x18,0xDB,0xFE,
0x01,0x20,0x11,0xE5,0xED,0x4B,0xF3,0x5E,0x03,0xED, 0x43,0xF3,0x5E,0xCD,0x8F,0x5D,
0xE1,0x23,0x18,0xC6,0xE5,0xED,0x4B,0xF3,0x5E,0x03, 0xED,0x43,0xF3,0x5E,0xCD,0xA1,
0x5D,0xE1,0x23,0x18,0xB5,0x00,0x00,0x00,0x00,0xCD, 0x48,0x5D,0xED,0x73,0xF5,0x5E,
0x01,0xF4,0x01,0xC5,0x3E,0x00,0x01,0x1F,0x00,0xED, 0x78,0xB7,0x28,0x05,0x3E,0xC9,
0x32,0xC2,0x5D,0xC1,0x0B,0xAF,0xB0,0xB1,0x20,0xE9, 0x00,0x00,0x21,0x00,0x90,0x22,
0x36,0x5C,0xFD,0x21,0x3A,0x5C,0xED,0x7B,0xF5,0x5E, 0x3E,0x06,0x32,0x12,0x5C,0x3E,
0x02,0xCD,0x01,0x16,0x3E,0xFF,0xFD,0x77,0x00,0x3E, 0x2B,0x32,0x48,0x5C,0x32,0x8D,
0x5C,0xCD,0x6B,0x0D,0x3E,0x05,0xD3,0xFE,0x2A,0x3D, 0x5C,0x01,0x15,0x5F,0x71,0x23,
0x70,0x21,0x40,0x9C,0x11,0x00,0x00,0x06,0x08,0x0E, 0x05,0xCD,0x13,0x3D,0x3E,0xFF,
0x32,0x15,0x5E,0x32,0x16,0x5E,0xF3,0xDD,0x21,0x40, 0x9C,0xFD,0x21,0xC8,0xAF,0xDD,
0x7E,0x00,0xFE,0x00,0xCA,0xEB,0x5F,0xFE,0x01,0xCA, 0x87,0x5F,0xDD,0x7E,0x08,0xFE,
0x42,0xCA,0x94,0x5F,0xDD,0x7E,0x0D,0xFE,0xC0,0xCA, 0xCF,0x5F,0xDD,0xE5,0xE1,0x11,
0x10,0x00,0x19,0xE5,0xDD,0xE1,0xC3,0x6A,0x5F,0xDD, 0x7E,0x00,0xFE,0x62,0x20,0x34,
0xDD,0x7E,0x01,0xFE,0x6F,0x20,0x2D,0xDD,0x7E,0x02, 0xFE,0x6F,0x20,0x26,0xDD,0x7E,
0x03,0xFE,0x74,0x20,0x1F,0xDD,0x7E,0x04,0xFE,0x20, 0x20,0x18,0xDD,0x7E,0x05,0xFE,
0x20,0x20,0x11,0xC3,0x87,0x5F,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFD,0xE5,0xD1,0xDD,0xE5,0xE1, 0x01,0x09,0x00,0xED,0xB0,0x21,
0x15,0x5E,0x34,0xFD,0xE5,0xE1,0x11,0x09,0x00,0x19, 0xE5,0xFD,0xE1,0xC3,0x87,0x5F,
0xFD,0x21,0x3A,0x5C,0x3A,0x15,0x5E,0xFE,0xFF,0xCA, 0x34,0x62,0xFE,0x14,0xD2,0x48,
0x62,0x06,0xB4,0x0E,0xA7,0xED,0x43,0xF1,0x5E,0x06, 0x00,0x0E,0x0C,0x2E,0x09,0x3A,
0x15,0x5E,0x67,0x24,0x24,0x24,0x3E,0x70,0x32,0xC0, 0x61,0xCD,0xC3,0x61,0x06,0x00,
0x0E,0x0C,0x21,0x09,0x00,0x3E,0x46,0x32,0xC0,0x61, 0xCD,0xC3,0x61,0x3E,0x47,0x32,
0xC0,0x61,0x3A,0x15,0x5E,0xC6,0x04,0x47,0x0E,0x0D, 0x21,0x09,0x00,0x3A,0xC0,0x61,
0xCD,0xC3,0x61,0x0E,0x16,0x3A,0x15,0x5E,0xC6,0x02, 0x67,0x2E,0x00,0x06,0x01,0x3A,
0xC0,0x61,0xCD,0xC3,0x61,0x3E,0x46,0x32,0x8D,0x5C, 0x3E,0x02,0xCD,0x01,0x16,0x11,
0x66,0x5D,0x01,0x09,0x00,0xCD,0x3C,0x20,0x3E,0x70, 0x32,0x8D,0x5C,0x3E,0x02,0xCD,
0x01,0x16,0x3A,0x15,0x5E,0xDD,0x21,0xC8,0xAF,0x26, 0x01,0x3C,0x47,0xC5,0x24,0x7C,
0x32,0x83,0x60,0xE5,0x3E,0x16,0xD7,0x3E,0x03,0xD7, 0x3E,0x0D,0xD7,0xDD,0xE5,0xD1,
0x01,0x08,0x00,0xCD,0x3C,0x20,0xDD,0xE5,0xE1,0x11, 0x09,0x00,0x19,0xE5,0xDD,0xE1,
0xE1,0xC1,0x10,0xD9,0xCD,0xAF,0x63,0x11,0x00,0xC0, 0x01,0x00,0x18,0xED,0xB0,0xCD,
0xB3,0x5D,0x3A,0xF0,0x5E,0xDD,0x21,0xF1,0x5E,0xCB, 0x47,0x28,0x03,0xDD,0x34,0x00,
0xCB,0x4F,0x28,0x03,0xDD,0x35,0x00,0xCB,0x57,0x28, 0x03,0xDD,0x35,0x01,0xCB,0x5F,
0x28,0x03,0xDD,0x34,0x01,0xCB,0x67,0x28,0x0B,0x3A, 0x16,0x5E,0xFE,0xFF,0x28,0x04,
0xFB,0xC3,0x8C,0x62,0xED,0x4B,0xF1,0x5E,0x3E,0x10, 0xB8,0x38,0x02,0x06,0x10,0xB9,
0x38,0x02,0x0E,0x10,0x3E,0xBD,0xB8,0x30,0x02,0x06, 0xBD,0x3E,0xEF,0xB9,0x30,0x02,
0x0E,0xEF,0xED,0x43,0xF1,0x5E,0xCD,0x9A,0x5E,0x3A, 0xF0,0x5E,0xFE,0x00,0xCA,0xB2,
0x61,0x06,0x11,0xC5,0xED,0x4B,0xF1,0x5E,0xD1,0xD5, 0x04,0x78,0x92,0x3C,0x47,0xCD,
0x6F,0x5D,0x3E,0x80,0x84,0x57,0x5D,0x1A,0xB6,0x77, 0x23,0x13,0x1A,0xB6,0x77,0x23,
0x13,0x1A,0xB6,0x77,0xC1,0x10,0xDC,0x3A,0xF2,0x5E, 0x47,0x3E,0xBF,0x90,0xE6,0xF8,
0xCB,0x0F,0xCB,0x0F,0xCB,0x0F,0xFE,0x02,0x38,0x4F, 0x47,0x3A,0x15,0x5E,0xC6,0x02,
0xB8,0x38,0x46,0x3A,0xF1,0x5E,0xFE,0x60,0x38,0x3F, 0xFE,0xB0,0x30,0x3B,0x3A,0xF2,
0x5E,0x47,0x3E,0xBF,0x90,0xE6,0xF8,0x0F,0x0F,0x0F, 0x21,0x16,0x5E,0xBE,0x28,0x47,
0x32,0x16,0x5E,0x06,0x02,0x0E,0x0C,0x2E,0x09,0x3A, 0x15,0x5E,0x67,0x24,0x3E,0x70,
0x32,0xC0,0x61,0xCD,0xC3,0x61,0x3A,0x16,0x5E,0x47, 0x0E,0x0C,0x21,0x09,0x00,0x3E,
0x46,0x32,0xC0,0x61,0xCD,0xC3,0x61,0x18,0x1E,0x3A, 0x16,0x5E,0xFE,0xFF,0x28,0x17,
0x3E,0xFF,0x32,0x16,0x5E,0x06,0x02,0x0E,0x0C,0x2E, 0x09,0x3A,0x15,0x5E,0x67,0x3E,
0x70,0x32,0xC0,0x61,0xCD,0xC3,0x61,0xCD,0x54,0x1F, 0xDA,0xAA,0x60,0xCD,0x54,0x1F,
0x30,0xFB,0xC3,0x15,0x5F,0x00,0x00,0x00,0x32,0xC0, 0x61,0xED,0x43,0xC1,0x61,0x05,
0x0D,0x24,0x2C,0x09,0x04,0x0C,0xCD,0xE2,0x61,0x79, 0xBD,0x38,0xF8,0x3A,0xC1,0x61,
0x4F,0x0D,0x78,0xBC,0x38,0xEE,0xC9,0xE5,0xC5,0x16, 0x00,0x58,0x06,0x05,0x3F,0xCB,
0x23,0xCB,0x12,0x10,0xF9,0xC1,0xC5,0xD5,0xE1,0x16, 0x00,0x59,0x19,0x11,0x00,0x58,
0x19,0x3A,0xC0,0x61,0x77,0xC1,0xE1,0xC9,0xCD,0xBC, 0x63,0x01,0x06,0x0C,0x21,0x11,
0x02,0x3E,0x57,0x32,0x8D,0x5C,0x32,0xC0,0x61,0xCD, 0xC3,0x61,0x06,0x0F,0x0E,0x07,
0x21,0x11,0x00,0x3E,0x00,0x32,0xC0,0x61,0xCD,0xC3, 0x61,0x06,0x0D,0x0E,0x18,0x2E,
0x00,0x26,0x02,0x3E,0x00,0xCD,0xC3,0x61,0xC9,0xCD, 0x03,0x62,0x3E,0x02,0xCD,0x01,
0x16,0x11,0x63,0x62,0x01,0x14,0x00,0xCD,0x3C,0x20, 0xC3,0x59,0x62,0xCD,0x03,0x62,
0x3E,0x02,0xCD,0x01,0x16,0x11,0x78,0x62,0x01,0x14, 0x00,0xCD,0x3C,0x20,0xCD,0x8E,
0x02,0xCB,0x7B,0x20,0xF9,0xC3,0x15,0x5F,0x16,0x0D, 0x07,0x20,0x20,0x4E,0x4F,0x20,
0x45,0x58,0x45,0x2D,0x46,0x49,0x4C,0x45,0x20,0x21, 0x20,0x20,0x20,0x16,0x0D,0x07,
0x4E,0x4F,0x20,0x4D,0x4F,0x52,0x45,0x20,0x54,0x48, 0x41,0x4E,0x20,0x32,0x30,0x21,
0x20,0x2A,0x3D,0x5C,0x01,0x15,0x5F,0x71,0x23,0x70, 0x3E,0x00,0x32,0x36,0x5C,0x3E,
0x3C,0x32,0x37,0x5C,0x3E,0x00,0x32,0x48,0x5C,0x32, 0x8D,0x5C,0x3E,0x02,0xCD,0x01,
0x16,0xCD,0x6B,0x0D,0x3E,0x00,0xD3,0xFE,0x31,0xFF, 0xFF,0x21,0xC8,0xAF,0x3A,0x16,
0x5E,0x3D,0x3D,0xCB,0x07,0xCB,0x07,0xCB,0x07,0x47, 0x3A,0x16,0x5E,0x3D,0x3D,0x80,
0x5F,0x16,0x00,0x19,0xE5,0xDD,0xE1,0xED,0x7B,0xF5, 0x5E,0xDD,0x7E,0x08,0xFE,0x43,
0x28,0x14,0x11,0x0D,0x63,0x01,0x08,0x00,0xED,0xB0, 0x21,0x08,0x63,0x22,0x5D,0x5C,
0xCD,0x03,0x3D,0xC3,0x15,0x5F,0x11,0x1C,0x63,0x01, 0x08,0x00,0xED,0xB0,0xCD,0xBF,
0x16,0x21,0x17,0x63,0x22,0x5D,0x5C,0xCD,0x03,0x3D, 0xC3,0x15,0x5F,0x3A,0xEA,0x3A,
0xF7,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x22,0x0D,0x3A,0xEA,0x3A,0xEC,
0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x22, 0xAF,0x0D,0x01,0xFE,0xEF,0x16,
0x00,0xED,0x78,0xCB,0x47,0x20,0x02,0xCB,0xE2,0xCB, 0x4F,0x20,0x02,0xCB,0xDA,0xCB,
0x57,0x20,0x02,0xCB,0xD2,0xCB,0x5F,0x20,0x02,0xCB, 0xC2,0xCB,0x67,0x20,0x02,0xCB,
0xCA,0x3A,0xF0,0x5E,0xB2,0x32,0xF0,0x5E,0xC9,0x01, 0xD0,0x07,0x21,0x00,0x00,0x7E,
0xE6,0xF8,0xF6,0x01,0xD3,0xFE,0x23,0x0B,0xAF,0xB0, 0xB1,0x20,0xF2,0xC9,0xCA,0x3A,
0x1D,0x5F,0xB2,0x32,0x1D,0x5F,0xC9,0x01,0xD0,0x07, 0x21,0x00,0x00,0x7E,0xE6,0xF8,
0xF6,0x01,0xD3,0xFE,0x23,0x0B,0xAF,0xB0,0xB1,0x20, 0xF2,0xC9,0x16,0x15,0x01,0x10,
0x02,0x11,0x05,0x13,0x00,0x20,0x50,0x55,0x42,0x4C, 0x49,0x53,0x48,0x45,0x44,0x20,
0x42,0x59,0x20,0x53,0x4F,0x46,0x54,0x53,0x54,0x41, 0x52,0x20,0x4F,0x46,0x20,0x4D,
0x4B,0x48,0x47,0x20,0x11,0x87,0x63,0x01,0x28,0x00, 0xCD,0x3C,0x20,0x21,0x00,0x40,
0xC9,0xCD,0x54,0x63,0x3E,0x05,0xD3,0xFE,0xC9,0x80, 0xAA,0x01,0x00,0x00,0x00,0x00,
0x43,0x4F,0x52,0x52,0x45,0x43,0x54,0x45,0x44,0x20, 0x42,0x59,0x20,0x4B,0x53,0x41,
0x20,0x53,0x4F,0x46,0x54,0x57,0x41,0x52,0x45,0x2C, 0x53,0x50,0x45,0x43,0x49,0x41,
0x4C,0x20,0x46,0x4F,0x52,0x20,0x41,0x4E,0x44,0x52, 0x45,0x57,0x20,0x49,0x53,0x41,
0x45,0x56,0x20,0x20,0x31,0x39,0x39,0x34,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x82,0x00,0xF9,0xC0,0x30,0x0E,0x00,0x00, 0x72,0x5D,0x00,0x16,0x00,0x00,
0x13,0x01,0x11,0x05,0x10,0x00,0x20,0x2A,0x20,0x50, 0x52,0x4F,0x54,0x45,0x43,0x54,
0x49,0x4F,0x4E,0x20,0x42,0x59,0x20,0x4B,0x53,0x41, 0x20,0x53,0x4F,0x46,0x54,0x57,
0x41,0x52,0x45,0x20,0x2A,0x20,0x13,0xF3,0x31,0x00, 0x40,0xAF,0xD3,0xFE,0x21,0x00,
0x40,0x11,0x01,0x40,0x01,0xFF,0x1A,0x75,0xED,0xB0, 0x21,0x90,0x5D,0x06,0xA1,0x7E,
0xAD,0x77,0x23,0x10,0xFA,0xA1,0x95,0xD2,0xB2,0x0B, 0xC8,0x87,0x93,0xD8,0x98,0xBA,
0x9B,0x71,0x2D,0x57,0x5F,0xFD,0xD5,0xBA,0x92,0x79, 0xF8,0x6A,0xFA,0x6E,0xF4,0xF7,
0x7E,0xF1,0x4A,0xF3,0x1A,0xED,0x0D,0xEF,0x40,0xE9, 0x84,0x07,0xEA,0x46,0xCD,0x15,
0x72,0x13,0x6E,0x40,0x76,0xFA,0xB4,0x9F,0x02,0xF7, 0x0C,0xFD,0xF9,0x82,0x37,0xB2,
0x02,0xF6,0xAF,0x93,0x61,0xF3,0x7F,0xF1,0x7D,0x1D, 0xF4,0xD4,0x89,0xE6,0xDC,0x09,
0x25,0x15,0xFC,0x2D,0x82,0x4E,0xC2,0x4C,0xC0,0x4A, 0xC6,0x2F,0xD9,0xC0,0xDE,0xFD,
0x45,0xCF,0x43,0xCD,0x41,0xD3,0x5F,0x3B,0xD2,0xDB, 0xAB,0xE7,0x12,0xF9,0xF8,0x1F,
0xFA,0x82,0x51,0x56,0x56,0xAA,0xAA,0xAF,0xED,0x05, 0xEB,0xF8,0xE9,0x4A,0xE7,0x22,
0x7C,0x2F,0x1E,0x05,0x77,0xA1,0x31,0xFB,0x32,0x3B, 0x4B,0x07,0x17,0xE8,0x18,0xFF,
0x1A,0xF1,0xAD,0x2F,0x08,0x7E,0x00,0x34,0x7D,0x35, 0x30,0x78,0x26,0x8D,0x29,0x1C,
0x2B,0xC1,0x95,0xE7,0x38,0xF8,0xEE,0xB3,0xD1,0xC7, 0x3A,0xDE,0xA1,0x9C,0xC7,0xDB,
0xDA,0x08,0x11,0x14,0xE7,0xA9,0xAE,0xA3,0xA0,0xA5, 0xBA,0xBF,0xBC,0xB1,0xB6,0x48,
0x4B,0x4E,0x41,0x44,0x47,0x5A,0x5D,0x50,0x53,0x56, 0x29,0x2C,0x2F,0x22,0x25,0x38,
0x3B,0x3E,0x31,0x34,0x37,0x0A,0xE0,0x57,0xF2,0xD7, 0xF4,0x43,0x78,0xFF,0x42,0xDB,
0x0A,0x2E,0x21,0xC1,0xF6,0x3B,0x3D,0x6B,0xF2,0x27, 0xEC,0x51,0xDA,0xEF,0x4A,0xFD,
0xCA,0x05,0x0A,0x0F,0x11,0xEA,0x00,0x50,0x2A,0xC7, 0xF9,0xFC,0xEE,0xF3,0xF5,0x89,
0x8B,0xD5,0x44,0x41,0x42,0xA9,0xAE,0x7D,0x23,0xB7, 0x96,0x93,0x4C,0xA4,0x64,0x5A,
0xEB,0x23,0x53,0xEA,0x2A,0x70,0xC7,0x1E,0xBD,0x85, 0x99,0x7D,0x8F,0x0F,0xB0,0x56,
0x6A,0x50,0x63,0x5A,0x64,0x44,0x79,0x4E,0x76,0x48, 0x4F,0x72,0x48,0x7C,0x4D,0x66,
0x52,0xA0,0x58,0x96,0x57,0x2A,0xEE,0xE5,0x10,0x04, 0x39,0x3C,0x1D,0x30,0x35,0x35,
0xB7,0x33,0xBC,0xD5,0xE2,0x84,0x00,0xB2,0x0E,0xBD, 0x74,0x49,0x4E,0x4B,0x8F,0xB8,
0xBB,0x8F,0x1B,0x1E,0x8C,0xB1,0xBE,0x61,0x62,0x5F, 0x40,0x45,0xBE,0x0C,0xC8,0x96,
0x0B,0x08,0x93,0x3B,0xFA,0x5B,0x64,0xA1,0xDD,0xB6, 0x5C,0x9D,0xE1,0x82,0x50,0x89,
0x0B,0xC3,0x44,0x5D,0xD3,0x22,0x3F,0x2A,0x42,0x2B, 0x37,0x3C,0x3A,0x36,0x26,0x29,
0x48,0x56,0x20,0x4E,0x55,0x5A,0x3C,0x62,0x7D,0x71, 0x9D,0xCB,0xD6,0xD6,0xF4,0x96,
0xFB,0x13,0xBE,0x19,0xA4,0x34,0x32,0x15,0xF0,0xD7, 0x54,0x82,0x32,0x81,0x2B,0x17,
0xD8,0xFF,0x8F,0xE4,0x32,0xEC,0x02,0xE6,0x0C,0x2F, 0xDF,0x33,0xD9,0x3D,0x04,0x01,
0xC3,0xD9,0xC9,0xD1,0xCF,0xA9,0x6E,0xF0,0xFD,0x7B, 0x98,0xCB,0xE1,0x59,0x5E,0xA2,
0x97,0x62,0x9D,0x66,0x9F,0x8A,0x67,0x6A,0xB3,0xB2, 0xF5,0xC8,0xCB,0xFE,0xC1,0x13,
0xC4,0xC0,0xE9,0x14,0x66,0x55,0x2E,0x51,0x5C,0x34, 0x2B,0x26,0x2D,0x20,0x2F,0xF0,
0xC7,0x70,0xF9,0x23,0x22,0x2B,0xC2,0xE8,0x9C,0x40, 0x7F,0x12,0x11,0xEE,0xA4,0xF9,
0x21,0x24,0xF8,0xD6,0xBC,0x41,0x72,0xD1,0xF7,0x92, 0xE4,0xAC,0x1B,0x8B,0xFC,0xB9,
0x52,0x9D,0x29,0xA8,0x4E,0xCC,0xEA,0xF1,0xBF,0x97, 0x14,0x79,0x41,0xB7,0x72,0xEC,
0x53,0xBB,0x7E,0x79,0xC0,0x2C,0x30,0x41,0xAA,0x11, 0x88,0x75,0xFE,0xE7,0x21,0x21,
0xAC,0x18,0x2D,0xD5,0x8E,0x1B,0x70,0x48,0x4E,0x1F, 0x30,0x21,0x86,0x21,0xFD,0x64,
0xE2,0x45,0x70,0x45,0x13,0x82,0x40,0x25,0x32,0xE3, 0x5E,0x98,0x07,0x87,0x2A,0xD5,
0x0C,0x45,0xCE,0x44,0x0E,0xD1,0xCC,0x53,0x87,0x3E, 0xD5,0xBC,0x8B,0x9A,0xE9,0xD8,
0xCF,0xB6,0xAD,0x84,0xF3,0xD2,0xE1,0x80,0x97,0xAE, 0xA5,0xCC,0xFB,0xEA,0x99,0x88,
0x9F,0xE6,0xFD,0xD4,0xA6,0xBB,0xBC,0xB1,0xB2,0xB7, 0x88,0x8D,0x8E,0x83,0xA4,0xB9,
0xBA,0xBF,0xB0,0xB5,0xB6,0x74,0x73,0x7E,0x7D,0x78, 0x67,0x62,0x61,0x6C,0x6B,0x16,
0x15,0x10,0x1F,0x1A,0x19,0x04,0x03,0x0E,0x20,0x80, 0xAA,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
0xF3,0xCD,0x52,0x00,0x3B,0x3B,0xC1,0x21,0x97,0x00, 0x09,0xEB,0x21,0x66,0x00,0x09,
0x73,0x23,0x72,0x21,0x7B,0x00,0x09,0x73,0x23,0x72, 0x21,0x89,0x00,0x09,0x73,0x23,
0x72,0x21,0xBE,0x00,0x09,0x11,0x00,0x40,0xD5,0xD9, 0x08,0x3E,0x03,0xB7,0x06,0x08,
0x48,0xE1,0x08,0xD9,0x7E,0xCB,0x7F,0x20,0x3A,0xE6, 0x07,0x4F,0x7E,0x0F,0x0F,0x0F,
0xE6,0x0F,0xC6,0x03,0x47,0x23,0x7B,0x96,0x23,0xE5, 0x6F,0x7A,0x99,0x67,0xE5,0x7C,
0xE6,0x58,0xFE,0x58,0x28,0x12,0x4F,0x7D,0xE6,0x07, 0xB1,0x4F,0x29,0x29,0x7C,0xE6,
0x1F,0x67,0x7D,0xE6,0xE0,0xB4,0x6F,0x61,0x7E,0xCD, 0xA6,0x74,0xE1,0x23,0x10,0xDE,
0xE1,0x18,0xC1,0xE6,0x7F,0x28,0x1D,0x23,0xCB,0x77, 0x20,0x0A,0x47,0x7E,0xCD,0xA6,
0x74,0x23,0x10,0xF9,0x18,0xAE,0xE6,0x3F,0xC6,0x03, 0x47,0x7E,0xCD,0xA6,0x74,0x10,
0xFB,0x23,0x18,0xA0,0xD9,0x21,0x58,0x27,0xD9,0xFB, 0xC9,0x13,0xD9,0x77,0x08,0x28,
0x19,0x24,0x10,0x1B,0x11,0x20,0xF8,0x19,0x0D,0x20, 0x12,0x11,0x01,0xFF,0x19,0xC6,
0x08,0x30,0x08,0x11,0xE0,0x07,0x19,0x3D,0x18,0x01, 0x23,0x0E,0x08,0x06,0x08,0x08,
0xD9,0xC9,0xC8,0x00,0x87,0x30,0xDC,0xEF,0xEB,0xEF, 0xEB,0x5C,0xCB,0x00,0x8F,0x3C,
0x5E,0xBF,0x9F,0xAF,0x95,0x42,0x3C,0x00,0x3A,0x74, 0xA8,0x96,0xAF,0x5D,0x18,0x06,
0x40,0x0C,0x88,0x00,0x00,0x01,0x03,0x07,0x07,0x0F, 0x0E,0xC0,0x1D,0x8B,0x2D,0x3E,
0x2F,0x2F,0x14,0x16,0x13,0x09,0x08,0x04,0x03,0x08, 0x56,0x00,0x16,0x8B,0x0F,0x08,
0x0F,0x61,0xB2,0x75,0x6B,0x57,0x2E,0x45,0x38,0x18, 0x68,0x81,0x27,0x30,0x6F,0x82,
0x7F,0x05,0xC1,0xFF,0x00,0x60,0xC3,0xFF,0x85,0x3C, 0x18,0x18,0xDB,0xDB,0x08,0x0C,
0x86,0x00,0x81,0xDB,0xE7,0x3F,0x05,0x00,0x19,0x8F, 0x00,0xC3,0xC3,0xE7,0xE7,0x24,
0xE7,0x86,0xCB,0xD7,0xAE,0x5D,0xBA,0x14,0xE3,0x20, 0x36,0x30,0xAF,0x82,0xFF,0x78,
0x10,0x40,0x89,0x04,0x00,0x00,0x80,0xC0,0xE0,0xE0, 0xF0,0x70,0xC0,0xB8,0x8B,0xBC,
0x7C,0xFC,0xFC,0x38,0x78,0xF8,0xF0,0xF0,0xE0,0xC0, 0x08,0xD6,0x00,0x16,0x8B,0xF0,
0x10,0xF0,0x18,0x2C,0x5D,0xBA,0x75,0xEB,0x51,0x8E, 0x20,0x36,0x81,0x3F,0x38,0xF0,
0x81,0xFC,0x10,0x80,0x41,0x00,0x87,0x0C,0x3B,0xF7, 0xD7,0xF7,0xD7,0x3A,0x59,0x00,
0x00,0xC0,0x83,0xEB,0xD7,0xAE,0x28,0xC0,0x81,0xFC, 0x00,0xB2,0x81,0x23,0x30,0x83,
0x60,0x40,0xD2,0x00,0x58,0xC0,0x08,0x81,0x81,0x83, 0x38,0x40,0x08,0xA8,0x83,0x06,
0x06,0x03,0xC0,0x06,0x84,0x00,0x38,0x7C,0x7C,0xC1, 0xFE,0x81,0x7C,0x68,0x52,0x58,
0xC0,0x00,0x74,0x83,0x00,0xFF,0x0F,0x38,0x0C,0x01, 0xBE,0x86,0x36,0xB6,0xE6,0xB7,
0xB7,0x36,0x78,0x40,0x78,0xC0,0x01,0xEB,0x81,0x1F, 0x08,0x40,0x81,0xFF,0x11,0x9F,
0x83,0x00,0x00,0xC0,0x10,0xFF,0x86,0x33,0x76,0xF0, 0xB0,0x36,0x33,0x78,0x80,0x78,
0xC0,0x18,0xF3,0x00,0x43,0x29,0x37,0x81,0xFD,0x0A, 0x3D,0x86,0xE6,0x36,0xE7,0x36,
0x36,0xE6,0x78,0xC0,0x78,0xC0,0x83,0x00,0x00,0x3F, 0xC4,0xFF,0x22,0x75,0x81,0xE8,
0x10,0xC0,0x84,0x36,0xF6,0x37,0x37,0x78,0xC0,0x79, 0x80,0x19,0x72,0x48,0x40,0x81,
0x40,0x12,0xB6,0x85,0x70,0xF0,0xB0,0x30,0x30,0x79, 0x40,0x79,0x80,0x02,0x2B,0x83,
0xFF,0xFF,0xFE,0x40,0x80,0x12,0xA6,0x82,0x04,0x06, 0xC3,0x02,0x83,0x06,0x04,0x07,
0x28,0x12,0x81,0x07,0x28,0x0B,0x71,0x80,0x02,0xB2, 0x84,0xF8,0xFF,0xFF,0xFC,0x43,
0x35,0x84,0xF0,0x08,0xE4,0x92,0xC1,0x8A,0x84,0x92, 0xE4,0x08,0xF0,0x1B,0x4C,0x85,
0x91,0x51,0x9D,0x55,0x9D,0x7A,0x40,0x20,0x81,0x29, 0xB7,0x1B,0x78,0x8D,0x20,0x60,
0xE3,0xA2,0xA2,0xA4,0xA8,0xB2,0xA6,0x8A,0x92,0xA2, 0xA2,0x22,0xE4,0x81,0x04,0x00,
0x80,0x02,0xD7,0x7A,0x40,0x0B,0xAB,0x81,0xC7,0x00, 0x72,0x2A,0x00,0x13,0xBB,0x84,
0x9F,0xA0,0xA7,0x98,0xC1,0x80,0x84,0x98,0xA7,0xA0, 0x9F,0x1B,0xCC,0x85,0x5F,0x50,
0xDE,0x50,0x5F,0x7A,0x40,0x20,0x71,0x03,0xF0,0x81, 0xB2,0x4B,0xE2,0x8A,0xE3,0x14,
0xD4,0x57,0x50,0xA0,0xA0,0x50,0x57,0xD4,0x2B,0x64, 0x85,0x39,0x45,0x41,0x45,0x39,
0x7B,0x00,0x2C,0x29,0x13,0xEF,0x82,0x0F,0x0F,0xC3, 0x1F,0x8D,0x0F,0x0F,0xFC,0x02,
0xFA,0x0A,0x0A,0x14,0x14,0x0A,0x0A,0xFA,0x02,0x11, 0x17,0x87,0xA0,0x00,0xF7,0x01,
0xE1,0x01,0xF1,0x7B,0x00,0x14,0x69,0x81,0x0F,0x2A, 0x02,0xC6,0xFF,0x8C,0xE1,0xA1,
0xA2,0xA4,0xA9,0xB3,0xA5,0x89,0x91,0xA1,0xA1,0xE1, 0x1C,0x8C,0x85,0xDF,0x10,0x1E,
0x10,0x1F,0x7B,0x00,0x14,0xA9,0x11,0xBE,0x50,0x43, 0x81,0xC0,0xC7,0x40,0x13,0xF6,
0x1A,0x17,0x12,0x1A,0x7B,0xC0,0x04,0x2D,0x88,0xE0, 0xF0,0xF8,0xF8,0xFC,0xFC,0xFE,
0xFE,0x1C,0xF8,0x82,0x06,0x07,0x7B,0x80,0x7B,0xC0, 0x43,0xC0,0x5D,0x1D,0x83,0x01,
0x03,0x8F,0x7B,0x80,0x7B,0xC0,0x34,0x80,0x81,0x9E, 0x3D,0x6E,0x83,0x40,0x40,0x60,
0x04,0xA0,0x82,0xF8,0xF8,0x7B,0x80,0x7C,0x80,0x2C, 0x80,0x81,0x03,0x7C,0x70,0x7B,
0x80,0x7C,0x80,0x35,0x40,0x6C,0xB0,0xC0,0x01,0x81, 0x03,0x7B,0x80,0x7C,0x80,0x25,
0x40,0x81,0x7F,0x65,0x30,0x85,0x08,0x08,0x1C,0x1C, 0xBE,0x7B,0x80,0x7D,0x40,0x25,
0x40,0x82,0xFF,0xFF,0x0B,0x22,0x83,0x10,0x10,0x28, 0x0C,0xEC,0x04,0xF0,0x85,0x7C,
0x7D,0x79,0x79,0x7B,0xDD,0x00,0x46,0x00,0x83,0xFF, 0xFF,0x01,0x25,0xA9,0x8A,0x0C,
0x1E,0x3F,0x00,0x1E,0x5C,0xDE,0xDC,0x9E,0x5C,0x41, 0x52,0x7E,0xC0,0x5D,0x40,0x81,
0x01,0x03,0xFB,0x08,0xB5,0x00,0xB6,0x82,0x1C,0x3E, 0xC2,0x1C,0x84,0xDD,0xED,0xF3,
0xF9,0x7E,0xC0,0x76,0xC0,0x26,0x00,0x0E,0xB0,0x2C, 0x18,0x02,0x75,0xC0,0xE0,0x84,
0xF0,0xF0,0xF9,0xD1,0x7E,0xC0,0x7E,0xC0,0x16,0xC0, 0x1C,0xFC,0x57,0x5D,0x84,0x80,
0x80,0xC0,0xC1,0x7E,0xC0,0x6E,0xC0,0x86,0x5C,0xBA, 0x74,0xEA,0x50,0x8E,0x24,0xFC,
0x81,0x01,0x21,0x03,0xD1,0x00,0x7E,0xC0,0x47,0xC0, 0x87,0x80,0x5C,0x2E,0x17,0x6B,
0xB5,0xBA,0x18,0x06,0x40,0x0C,0x7F,0xD2,0x7F,0xE4, 0x7F,0xF6,0x38,0x36,0xC1,0x00,
0x84,0x01,0x07,0x1F,0x3F,0x02,0x1D,0x82,0xFF,0xE0, 0x0F,0x76,0x05,0x20,0x0F,0xDA,
0x9C,0x5A,0x3D,0x92,0x09,0x40,0x44,0x4E,0x0C,0x15, 0x80,0x10,0x1A,0x3A,0x57,0x12,
0x80,0x28,0x0C,0x1C,0x2A,0x08,0x40,0x01,0x23,0x23, 0x35,0x63,0x05,0xC1,0x00,0x8A,
0x07,0x0B,0x15,0x0A,0x00,0x0B,0x0B,0x05,0x0E,0x1F, 0x08,0x3A,0xC2,0xFF,0x08,0x3F,
0x0F,0xB8,0x1E,0x25,0xA7,0x6F,0x92,0x44,0x91,0x88, 0x0A,0x23,0x22,0x70,0xA8,0x71,
0x31,0x2B,0x03,0x25,0x61,0x70,0xB0,0x68,0xA2,0x02, 0x07,0x06,0x8A,0x93,0x46,0x0A,
0x02,0x00,0x40,0x04,0xF0,0xFC,0xFC,0xB8,0x00,0x98, 0x98,0x90,0xC0,0x00,0x83,0x80,
0xC3,0xF7,0x0E,0x58,0x3D,0x96,0x81,0xE0,0x1E,0x67, 0x95,0xAB,0x57,0x8A,0x00,0x22,
0x30,0xA2,0x03,0x27,0x0A,0x02,0x88,0x61,0x23,0x61, 0xB0,0x24,0x06,0x0E,0x05,0xC4,
0xC0,0x00,0x8C,0x5E,0xAF,0x50,0x0F,0x2B,0x57,0x2A, 0x00,0x2E,0x1E,0x2E,0x14,0xC0,
0x00,0x84,0x40,0xE0,0xF0,0xFC,0x69,0x9B,0x18,0xC5, 0x8D,0x7F,0xAD,0x52,0x04,0x20,
0x02,0x00,0x10,0x80,0x00,0x08,0x18,0x9C,0x00,0xBF, 0x93,0x00,0x00,0x40,0x00,0x5C,
0xBE,0x00,0x74,0x74,0x00,0xC0,0xE0,0xF1,0xE3,0x00, 0x60,0x61,0x61,0x41,0x1A,0x92,
0x82,0x01,0x81,0x69,0xDB,0x81,0xF0,0x1E,0xEA,0x88, 0x6B,0x54,0xA9,0x02,0x10,0x00,
0x02,0x40,0x02,0xB9,0x86,0x2E,0x5F,0x00,0x2E,0x2E, 0x00,0x02,0xFF,0x8E,0x12,0x12,
0x42,0x02,0x00,0x00,0xFF,0xFF,0xA5,0x00,0xFF,0x39, 0x30,0x2B,0xC0,0x00,0x82,0xE0,
0xF3,0x0F,0x17,0x81,0xF8,0x5F,0xFA,0x17,0x2A,0x89, 0xFD,0xFF,0xAB,0x45,0x10,0x82,
0x08,0x00,0x04,0x03,0x36,0x87,0x30,0x38,0x5C,0x38, 0x34,0x52,0x10,0x0A,0x7B,0x81,
0x00,0x01,0x6F,0x87,0x95,0xC0,0xAE,0x2E,0x17,0x00, 0x00,0x16,0x8B,0x81,0xC0,0x09,
0x74,0xD2,0x00,0x90,0x01,0x01,0x6E,0x96,0x2A,0x00, 0x8A,0x02,0x10,0x84,0x00,0x04,
0x04,0x0E,0x96,0x0D,0x08,0xF0,0x0F,0xFA,0x86,0xE0, 0xF0,0x60,0x00,0x60,0x60,0x2D,
0x31,0x0D,0x17,0x45,0xDD,0x9D,0x1F,0x1F,0x3F,0x3F, 0x7F,0x5F,0xDF,0xAF,0xDF,0xAF,
0x9F,0x2F,0x5F,0x2B,0x5F,0x2F,0x57,0x2B,0x17,0x2A, 0x95,0x82,0x89,0x42,0x49,0x22,
0x20,0x11,0x08,0x23,0x1D,0xC0,0x00,0x82,0x01,0x03, 0x07,0x39,0x32,0x8F,0x2A,0x04,
0xD4,0xFF,0x8E,0xBF,0xFF,0x7F,0xAF,0x7F,0xAB,0x57, 0x2A,0x55,0x09,0x22,0x00,0xE0,
0x1C,0x03,0x60,0x83,0x3E,0xF7,0x0F,0x07,0x8D,0x82, 0x7E,0x3E,0xC1,0x00,0x81,0x02,
0x06,0x17,0x81,0xF8,0x7D,0xDB,0x2F,0xEE,0x83,0xFE, 0xD0,0xA0,0x15,0xE5,0x05,0xBC,
0x87,0xB0,0xFC,0x57,0xAA,0x55,0x80,0x01,0x0D,0xBE, 0x86,0x8F,0xBD,0x43,0x7F,0xBF,
0xBF,0x26,0xF4,0x81,0x83,0x07,0xD3,0x03,0x48,0x82, 0xF0,0xF8,0x05,0xDA,0x0F,0xE1,
0x82,0xE3,0xDD,0xC1,0xD8,0x8B,0xEE,0xF1,0xFF,0xFF, 0xF9,0xFC,0xFE,0x3F,0x1F,0x63,
0x81,0x1F,0xE2,0x87,0x09,0x03,0x0F,0xFD,0xBB,0x4E, 0x38,0x16,0x29,0x81,0x80,0x06,
0x07,0xC0,0xFC,0x0D,0x06,0x81,0x07,0x0E,0x96,0x4B, 0x97,0x81,0xCE,0x0B,0x93,0xC1,
0xF0,0x82,0xF8,0xF8,0x0F,0xD5,0x81,0xC0,0xC0,0xF8, 0x00,0x0F,0x96,0xE0,0xE0,0xC0,
};

// read sector
void read_sector()
{
if( side == 0)
{
byte i = 0, s = sector - 1;
while(1)
{
uint16_t w = pgm_read_word_near(track0[s] + i);
sector_data[i] = (uint8_t)w;
sector_data[i+1] = (uint8_t)(w >> 8);
if(i==254) break;
i += 2;
}
}
else
{
byte i = 0, s = sector - 1;
while(1)
{
uint16_t w = pgm_read_word_near(track1[s] + i);
sector_data[i] = (uint8_t)w;
sector_data[i+1] = (uint8_t)(w >> 8);
if(i==254) break;
i += 2;
}
}
}

int main() {
// init();

cli();
prepare_track_header();
prepare_sector_header();

// Setup USART in MasterSPI mode 500000bps
//DDRD |= (1 << DDD4);
UBRR0H = 0x00;
UBRR0L = 0x0F; // 500 kbps
UCSR0C = 0xC0;
UCSR0A = 0x00;
UCSR0B = 0x28; // enable USART

//INIT INT0 interrupt
EICRA = 0x03; // falling edge=2, rising edge=3
EIFR = 0x01; // clear interrupt flag
EIMSK = 0x01; // enable INT0

// AFTER TRD is MOUNTED

PORTC |= ((1 << MOTOR_ON) | (1 << DRIVE_SEL) | (1 << SIDE_SEL));

//SET INDEX,TRK00 AS OUTPUT AND HIGH, WP AS OUTPUT AND LOW
//PORTD |= ((1 << INDEX) | (1 << TRK00)); // set 1
//PORTD |= (1 << STEP) | (1 << DIR_SEL);
PORTD = 255;
//////PORTD &= ~(1 << READ_DATA); // set 0
PORTD &= ~(1 << WP); // set 0
DDRD |= ((1 << INDEX) | (1 << TRK00) | (1 << WP));

// ---------------------------------------------------

while (1)
{
while ((PINC & (1 << MOTOR_ON)) > 0);

// this part is after motor on and drive sel --------
PORTD &= ~(1 << TRK00); // set 0
tmp = 0;
state = 0;
b_index = 0;
prev_byte = 0x4E;
sector = 1;
track = 0;
side = 0;
data_sent = 0;

read_sector();


sei(); // ENABLE INTERRUPTS

do
{
while (data_sent != 1);
// read next half of sector
read_sector();

if (data_sent == 0) { cli(); while (1); } // speed test
while (data_sent != 0);
}
while ((PINC & (1 << MOTOR_ON)) == 0);
cli(); // DISABLE INTERRUPTS
PORTD |= (1 << TRK00);
}
}

PS: убрал маппинг регистров и ISR_NAKED, компилятор справляется нормально :)

Ура! С таким кодом у меня уже грузится бут с SD карты!

s_kosorev
31.03.2016, 00:56
NAKED имеет смысл для функций целиком из ассемблерных вставок

EvgenRU
31.03.2016, 01:27
Так, добился я загрузки бута с SD карты, но теперь другая проблема... не грузится нормально то что после 1-ой дорожки... завтра буду думать с чем это связано...

Abadonna
31.03.2016, 18:51
Позвольте тоже немного встрять. Слежу за Вашей разработкой с очень внимательным интересом, очень многообещающая идея. И, что примечательно, она движется. Аплодирую стоя на голове.

Ваш выбор платформы не собираюсь ни критиковать, ни поддерживать - каждый может по Вашим исходникам сделать свой вариант. Даже, возможно, я одолел бы :) STM, конечно, дал бы развернуться во всю ширь и все такое, но выбор сделан, ардуина куплена :) Если для экспериментов Вам нужна будет дунька мега - могу предложить свою - все равно валяется, место занимает, а у Вас может на благое дело пойти :)

Если все-таки будете присматриваться в сторону ARM, позволю себе порекомендовать серию Discavery от STM - распространенная платформа, имеет все необходимое для старта из коробки (еще бы кило мозгов прилагался, тогда и у меня бы заработала, наверное :)).

П.С. Извиняюсь, сразу забыл спросить - в чем Вы писали этот код, какая среда?

EvgenRU
01.04.2016, 00:18
Если для экспериментов Вам нужна будет дунька мега - могу предложить свою - все равно валяется, место занимает, а у Вас может на благое дело пойти :)
Да у меня она тоже есть, для второго 3D принтера брал, пока что не доделал, так что можно в крайнем случае её использовать :)


П.С. Извиняюсь, сразу забыл спросить - в чем Вы писали этот код, какая среда?
Код делался в Arduino 1.6.8, в принципе, легко переносится в AVR Studio

- - - Добавлено - - -

Так, ну что, в целом вроде SD нормально работает, то что часто читаются сектора - не проблема, т.к. чтение же идет не постоянно, а выключается при отключении мотора. Сделал так, что не делается lseek при переходе к 1 сектору дорожки с последнего, а просто подставляются значения кластера/сектора, которые были при переходе на дорожку. Основная проблема сейчас это передвижение указателя в файле при смене дорожек, очень долго это делается стандартной функцией. Придется делать таблицу кластеров при открытии файла. Это снимет все проблемы.

EvgenRU
01.04.2016, 13:37
Ура! Я загрузил дримтимовскую DIZZY 3.5 с microSD карты!!! Это успех! Правда пока что не все файлы грузит. Где-то что-то не успевает. Надеюсь, что сегодня доделаю!

UPD: теперь уже и ROBOCOP 3 грузится :)

newart
01.04.2016, 15:26
Жги!

AlexNN
01.04.2016, 16:48
Круто!

Уже можно задуматься над пользовательским интерфейсом)

Вариант пользовательского интерфейса без экрана - вслепую, например с тремя кнопками - [назад] [выбор] [вперёд].
Микроконтроллер генерит, если его ещё нет, на флешке файл с пронумерованным списком trd образов,
по которому можно последовательно перемещаться кнопками вперёд назад, кнопкой [выбор] образ становится активным.

Также можно расширить интерфейс со стороны спектрума, и например при длительным нажатием кнопки [выбор],
генерится образ содержащий программу - файловый менеджер со списком образов на карте и возможностью выбрать активный.

s_kosorev
01.04.2016, 17:59
Вариант покруче, бут специальный и несколько секторов данных, где список файлов и какой то простой протокол что бы выбрать файл

- - - Добавлено - - -

опередили, такой вариант наиболее вписывается в концепт самого простого и дешевого контролера

ALS
01.04.2016, 19:13
Как вариант индикации - двух/трехразрядная LED-матрица, на которой высвечивается номер из списка.
Кстати, саму матрицу можно взять из старых ПК (LO-HI, помните ?)

kox
01.04.2016, 19:29
Со своим уставом в чужой монастырь не ходят, но все же выскажусь- дисплей от Нокиа 3310 стоит копейки, подключается 4 проводами, и по любому есть библиотека под ардуино.

EvgenRU
01.04.2016, 19:30
Пока что на том же месте застрял, походу, когда переход между кластерами на карте происходит задержка, а так половина файлов уже загружается.
Интерфейс, я вот думаю, действительно, при первом обращении выдавать бут, который читает, допустим 200 дорожку, а вместо неё выдается список файлов на карте, ну и в буте выбирать образ, как-то так, но это уже потом, под ZX давно не программировал :)

s_kosorev
01.04.2016, 19:51
когда переход между кластерами на карте происходит задержка, а так половина файлов уже загружается.
цепочку кластеров на цилинд однозначно надо в буфер, если fatfs который 44 байта озу, он при произвольном доступе от начала файла всю цепочку шерстит
потом достаточно манипулировать только позицией в файле и текущем кластером, что бы не потрошить fatfs

EvgenRU
01.04.2016, 20:17
цепочку кластеров на цилинд однозначно надо в буфер, если fatfs который 44 байта озу, он при произвольном доступе от начала файла всю цепочку шерстит
потом достаточно манипулировать только позицией в файле и текущем кластером, что бы не потрошить fatfs

Я на нечетных секторах гружу 512 байт (сектор целиком), а на начале дорожки подставляю кластер из таблицы для всего TRD, вместе с кластером вычисляю смещение в кластере и LBA, проблема возникает при переходе между кластерами, т.к. он грузит номер следующего кластера из сектора на карте, а это целый сектор. надо подумать, может цепочку для дорожки тоже в память, но это очень много памяти.. т.к. там 32 бита.

Перегоню таблицу CRC во флеш наверное, а то 512 байт, сейчас у меня всего 96 байт срама осталось на локальные переменные :)))

UPD: перегнал, нормально работает. Теперь попробую генерить цепочку на четных секторах, когда данные не грузятся.

UPD2: ну вот, теперь уже почти все загружаются :) Ааа... это же у меня на эве то не идет 1 диззи, так что УРА!!! ВСЕ ГРУЗИТСЯ!!!


Выкладываю рабочий вариант, кидаем на флешку файл "default.trd" и всё, оно работает.
Проект для Arduino IDE удобный для дальнейшей доработки.

ВНИМАНИЕ! ИСХОДНИКИ ПРОЕКТА ПЕРЕНЕСЕНЫ НА GITHUB ссылка в первом сообщении!


PS: в турбе 7МГц работает отлично, на 14МГц иногда сбоит.

PS2: проверил работу с картой класса 4, тянет нормально!

ВНИМАНИЕ! В ПОСЛЕДНЕЙ РЕДАКЦИИ ПОМЕНЯЛ МЕСТАМИ WRITE GATE и DIR SELECT, А ТАК ЖЕ MOTOR_ON перенесен на PD4! Подключать как указано в исходнике!

s_kosorev
01.04.2016, 21:32
на начале дорожки подставляю кластер из таблицы для всего TRD, вместе с кластером вычисляю смещение в кластере и LBA, проблема возникает при переходе между кластерами, т.к. он грузит номер следующего кластера из сектора на карте, а это целый сектор. надо подумать, может цепочку для дорожки тоже в память, но это очень много памяти.. т.к. там 32 бита.
не совсем понял, грубо говоря по сигналу step или motor on, нужно lseek сделать на позицию дорожки в файле, далее что бы не сочинять что то хитрое, нужно сделать 16 lseek для следущих секторов и из стуктуры FATFS вытягивать номер текущего кластера и смещение, которое можно обрезать до 1-2 байт, (вдруг 128кб кластер будет), получатеся на цилиндр надо (4+2)*16секторов*2 строны = 192 байт, но учитывая что 2 соседних сектора TRD будут в худьшем случае в одном секторе FAT, смело хватит 96 байт

потом для чтения, тут можно уже без FatFs подавать карточке команды с LBA адресами по табличке, мне примерно чудится такой возможный вариант

EvgenRU
01.04.2016, 22:09
Я по сигналу MOTOR_ON (далее будет мотор + селект) открываю файл, делаю lseek потреково, т.е. через 4096 байт и сохраняю кластеры в таблицу. При переходе на другой трек беру кластер из таблицы, вычисляю LBA, далее по лба загружаю сектор с флешки (2 сектора дискеты). В случае перехода на другой кластер беру подготовленный в промежутке между чтениями секторов :)

Номер цилиндра и стороны сохраняю до вывода дорожки на первом секторе и потом с ними работаю, чтобы не было несогласованных данных, т.е. дорожка 1, сектор 1, а данные в ней из дорожки 2 сектор 1, т.к. CRC генерится для данных, то данные будут корректными, но не из той дорожки, так что пришлось вот так извратиться, пусть какое-то время присутствуют сектора другой дорожки, но они не будут восприняты контроллером.

костя
01.04.2016, 22:13
А для каких компов разрабатывается эмулятор,очень надо для ес1841 и искры 1030м....

EvgenRU
01.04.2016, 22:18
А для каких компов разрабатывается эмулятор,очень надо для ес1841 и искры 1030м....

Я делал для ZX-Spectrum, теоретически можно переделать под другие форматы, как доделаю можно будет заморочиться, но тогда от вас потребуется формат дорожки для этих компов. И, главное, чтобы сектор был не более 512 байт.


PS: если кто решит опробовать скетч с предыдущей страницы - просьба отпишитесь как оно у вас работает, нужно ли будет еще какие-то изменения в ядро эмулятора вносить или уже можно будет думать об интерфейсе. Я всё-таки за то, чтобы делать без экрана, с отдельным бутом, прописанным во FLASH атмеги, в связи с этим, хотелось бы найти энтузиастов, готовых заморочиться с написанием этого BOOT :)

PS2: или всё же проще с экраном и кнопками?

Планирую еще DIR_SEL перенести, либо под будущую поддержку записи, либо под кнопки на прерывание, хотя там можно вроде PCINT задействовать.

AlexNN
02.04.2016, 10:09
Как не крути, но экран в данном случае будет давать ущербный интерфейс, думаю две три кнопки и светодиоды, дадут не намного меньше свободы. т.е. кнопки это как на корпусе ТВ, для минимального управления, полноценное уже через бут. Как раз для начала сделать кнопки, а далее расширить до загрузчика в спектруме. список образов, который сгенерит на карту мк, можно сделать текстовым, так чтобы его легко распечатать и ориентироваться при переходе кнопками.

trader2k4
02.04.2016, 16:21
или всё же проще с экраном и кнопками?

Лучше конечно с кнопками и экраном (уже приготовил :)) более универсальное решение получится.
Хотя, если ресурсов не хватает - можно и без них обойтись.

EvgenRU
02.04.2016, 16:24
Ресурсов еще вагон :) 550 байт срама и 26к флеша, пинов тоже порядочно, во всяком случае подключить экран по I2С и 3 кнопки вполне хватит.


PS: у меня тут что-то проблема с дримтимовской дискетой, всё грузит кроме первого диззи, не пойму в чем проблема, в дискдокторе нормально трек читается, а при запуске почему-то читается всесто первой дорожки нулевая и при этом даже CRC правильное. Может еще проблема в эве и в том пульсирующем сайде или я с FAT32 что-то нахимичил... сейчас над этим бьюсь. Надо бы к другому ZX подключить проверить, но лееень )))

PS2: кстати, проверил даже на SD карте 4 класса с размером кластера 32к, всё отлично работает.

AlexNN
02.04.2016, 17:01
Кстати, есть признак для мк, по которому видно, что игра(программа) захочет что нибудь записать на "дискету"?

EvgenRU
02.04.2016, 17:10
Кстати, есть признак для мк, по которому видно, что игра(программа) захочет что нибудь записать на "дискету"?

Если WRITE_GATE установлено в 0, то идет запись, но, если WP установлено в 0, то записи не будет, а будет ошибка Read Only.

UPD: прикол, скопировал с эмулятора на дискету, там DIZZY 1 идет, а с эмулятора нет ))))

AlexNN
02.04.2016, 19:42
не пробовали измерить общее время загрузки одной и тойже игры с эмулятора и с дескеты?

EvgenRU
03.04.2016, 19:03
По времени не сильно отличается, т.е. время вращения диска не сильно отличается, у эмулятора немного побыстрее, т.к. в последних версиях я выкинул поле C2.

Два дня убил на то, чтобы выяснить, что проблема не в эмуляторе, а в самом DIZZY.1R, видимо его загрузчик какой-то не стандартный, поэтому на дисководе работает, а так - нет. Что там такого у него в загрузчике, что извращается над дисководом?

PS: всё упаковано в 1 бейсик, находится в трек 1, сектор 7, грузится и вылетает "0 OK, 256:2", вместо бейсика данные с 0 дорожки, те же сектора. При этом, бут, находящийся в 0 секторе 1 трека грузится нормально, без проблем, все остальные диззи, сеймуры и робокоп3 тоже грузятся нормально....

UPD: Так, прикол, удалил DIZZY1.R из TRD, потом закинул его в конец и всё, теперь он запускается.... ничего не понимаю...

UPD2: Теперь не запускается DIZZY2.R :))))) видимо проблема в первой дорожке... ладно, буду дальше ковыряться, раз проблема всё-таки в эмуляторе...

tank-uk
03.04.2016, 20:08
EvgenRU, может диззи привязан к проверке SN диска ? в эмуле его скорее всего нет
копирование идет линейное, а диззи скорее всего обращается к заголовку диска и не увидев его валится в еггог

EvgenRU
03.04.2016, 20:35
EvgenRU, может диззи привязан к проверке SN диска ? в эмуле его скорее всего нет
копирование идет линейное, а диззи скорее всего обращается к заголовку диска и не увидев его валится в еггог

Да нет, уже выяснилось, что не в этом дело, тут получается, если файл находится в середине первой дорожки, то облом... пока что :) Буду думать как побороть, с остальными дорожками вроде всё в порядке. У меня такое подозрение, что проблемы где-то в вычислении кластеров FAT32 потому что заголовок то нормальный получается, а данные из 0 дорожки.
Причем! Когда я копирую этот файл (с первой дорожки который) в рил командере, то он копируется нормально на дискету и потом запускается.


UPD: я вот сейчас пришел к такому выводу, как нужно организовывать передачу. После отправки дорожки отключаю передачу, делаю то что нужно, потом снова передаю новую или старую дорожку, появляется доп время на обработку в будущих задачах :)

UPD2: отформатировал карту с размером кластера 64к, та же фигня, всё грузит кроме файла из середины первого трека, значит проблема не в вычислении кластеров фат32... может в буфере старые данные или еще что... Может попробовать установить размер блока чтения в 256 байт.....

UPD3: подозреваю, что где-то присутствует проблема с согласованностью данных, но где, пока что не могу понять.

newart
04.04.2016, 01:25
UPD3: подозреваю, что где-то присутствует проблема с согласованностью данных, но где, пока что не могу понять
Может создать образ с тестовыми данными и загразщик контролирующий их?

EvgenRU
04.04.2016, 12:04
Всё, решил проблему первой дорожки хитрым костылем :)))) Проблема была в запаздывании изменения переменной стороны по сравнению с сигналом с контроллера дисковода, при генерации заголовка сектора, если сторона не равна текущей, то подставляю значение 2, CRC перестает совпадать контроллер переходит на второй круг, где данные уже нормальные.

kox
04.04.2016, 12:26
А какая arduino используется в вашем проекте?

EvgenRU
04.04.2016, 12:27
А какая arduino используется в вашем проекте?

Любая с Atmega328p

PS: можно использовать любые SD/MMC карты с FAT32 с размером кластера от 1к до 64к.

kox
04.04.2016, 12:38
такая подойдет?
http://www.ebay.com/itm/New-Pro-Mini-atmega328-5V-16M-Replace-ATmega128-Arduino-Compatible-Nano-HS-/111711794061?hash=item1a028ab38d:g:ypcAAOSw3ydVmiU n

AlexNN
04.04.2016, 12:58
А в чем трудность "не костылем"?

EvgenRU
04.04.2016, 13:31
такая подойдет?
http://www.ebay.com/itm/New-Pro-Mini-atmega328-5V-16M-Replace-ATmega128-Arduino-Compatible-Nano-HS-/111711794061?hash=item1a028ab38d:g:ypcAAOSw3ydVmiU n
Да, но лучше тут http://ru.aliexpress.com/item/1Pc-New-Pro-Mini-atmega328-5V-16M-Replace-ATmega128-Wholesale-Store/32607317006.html?spm=2114.30010708.3.146.XpJHol&ws_ab_test=searchweb201556_1,searchweb201602_1_301 _10034_10033_507_10032_10020_10017_10005_10006_100 21_10022_401_10007_10018_10019,searchweb201603_9&btsid=6faa3791-e136-4712-afca-d0c76608e90d


А в чем трудность "не костылем"?
В том, что нельзя в эмуляторе сменить сторону пока не отправлена вся дорожка, а в реале смена стороны может произойти в середине дорожки.

UPD: Теоретически, код эмулятора можно уместить в 168p, если использовать размер кластера на карточке 32/64k

kox
04.04.2016, 16:00
Я думаю что 328р- самый раз: в Китае платки с ними почти ничего не стоят.

zebest
04.04.2016, 16:07
Arduino c 328 уже готовый девайс, подключил шильд с SD у устройство без производства готово
А такой вариант, подойдет?. кпримеру.Ну пусть чуть дороже, зато sd в комплекте.
http://g02.a.alicdn.com/kf/HTB1XwMtJVXXXXbAXpXXq6xXFXXXD/UNO-Shield-Ethernet-Shield-W5100-R3-UNO-Mega-2560-1280-328-UNR-R3-only-W5100-Development.jpg

EvgenRU
04.04.2016, 16:10
Если там Atmega328p, то никаких проблем, заливайте скетч и подключайте вместо дисковода, заодно и проверите, а то пока что никто не подтвердил работу, хотя у меня работает, значит должно работать :)

PS: с текущим скетчем нужно кинуть в корень флешки файл default.trd

PS2: файлы с гитхаба нужно кинуть в папку FDD_Emulator

PS3:

к шлейфу подключаем к контактам напротив выемок, т.е. та сторона что полностью плоская на шлейфе, если смотреть на неё сверху дырками к себе, то INDEX будет 4-ым справа
Ардуино Сигнал FDD
pin A0, SIDE SELECT (FDD pin 32)
pin A1, DRIVE SELECT (FDD pin 14/A, 12/B)
pin 8, DIRECTION SELECT (FDD pin 18)
pin 1, READ_DATA (FDD pin 30)
pin 2, STEP (FDD pin 20)
pin 4, MOTOR ON (FDD pin 10/A, 16/B)
pin 5, INDEX (FDD pin 8)
pin 6, TRACK 00 (FDD pin 26)
pin 7, WRITE PROTECT (FDD pin 28)

zebest
04.04.2016, 16:25
К сожалению нет еще такой платы. Но если эта бУдет работать - готов заказать. Ибо с ардуинами никогда дело не имел, надо же на чем то тренироваться)Ах да, это тут (http://ru.aliexpress.com/item/UNO-Shield-Ethernet-Shield-W5100-R3-UNO-Mega-2560-1280-328-UNR-R3-only-W5100-Development/32309139083.html?spm=2114.03010208.3.207.z1pVwe&s=p&ws_ab_test=searchweb201556_6,searchweb201602_1_100 17_10005_10006_10034_10021_507_10022_10020_10007_1 0018_10019,searchweb201603_9&btsid=36f225a6-7838-4ab5-8477-b1a3767ac50a).
Попадалась также еще плата с полноразмерным SD вроде.

EvgenRU
04.04.2016, 16:32
Посмотрел описание, это аналог ардуино мега, не уверен, что данный скетч будет на ней работать, т.к. он сделан под Arduino Uno. Хотя, допилить можно будет, но там памяти в 4 раза больше, что позволит держать всю дорожку в памяти.
Вообще, ардуина то и не нужна, если есть программатор, достаточно самой атмеги 328p, её напрямую подключить в шлейф, ну и карточный модуль приделать.

andykarpov
04.04.2016, 16:42
Теоретически, если проект можно собрать с использованием внутреннего 8МГц генератора и с безболезненной заменой в исходниках PB0 на PB1 для сигнала DIR_SEL, то за основу можно взять схему и плату SD адаптера от vinxru (https://github.com/vinxru/86RKSD) для Радио-86РК без переделок (ну разве что вместо Atmega8 воткнуть Atmega328).

https://camo.githubusercontent.com/341c991a1355c6d614fe7e6a28eeb38b0156cc1c/68747470733a2f2f6661726d382e737461746963666c69636b 722e636f6d2f373530332f31353734383036363236325f3461 30353863363838365f632e6a7067

Если развить тему, то плату можно переразвести под 34-контактный разъем для того, чтобы втыкать ее прямо в контроллер дисковода.

EvgenRU
04.04.2016, 16:56
Пока заливал в ардуину программатором - всё работало, записал бут и залил через ком порт - перестало работать, придется еще с этим разбираться :)

А, нет, спокойствие, проблема не в этом, тут у меня лог анализатор был подключен, наверное настройку пинов нужно поправить.

UPD: когда пины переносил, забыл пуллап поменять на пинах, в этом собственно и все проблемы, обновил на гитхабе.

Теперь работает и с бутлоадером с заливанием через компорт на ардуине

trader2k4
04.04.2016, 17:19
А такой вариант, подойдет?. кпримеру.Ну пусть чуть дороже, зато sd в комплекте.

ЭТО не подойдет - это "Ethernet-Shield" на базе сетевого чипа W5100 - и собственно AtMega328 на нем нет! Вещь хорошая, но она работает В ПАРЕ с обычной Arduino Uno.

- - - Добавлено - - -

Ещё раз повторю - это вообще не Arduino, это плата расширения (т.е. shield !) для него! Смотрите внимательно!

newart
04.04.2016, 19:43
Теперь работает и с бутлоадером с заливанием через компорт на ардуине

А планируешь SCL поддержать? А то ведь большая часть именно в этом формате хранится.
Взять тот-же Virtual TR-DOS и сотни других коллекций.

tank-uk
04.04.2016, 20:06
надо бы еще прилепить управление и дисплей, и оформить это все в виде схемы и прошивки
только что купил такую http://www.ebay.com/itm/New-Pro-Mini-atmega328-5V-16M-Replace-ATmega128-Arduino-Compatible-Nano-HS-/111711794061?hash=item1a028ab38d:g:ypcAAOSw3ydVmiU n по Украине за $3 с доставкой, после завтра будет у меня и можно будет пробовать

EvgenRU
04.04.2016, 20:58
А планируешь SCL поддержать? А то ведь большая часть именно в этом формате хранится.
Взять тот-же Virtual TR-DOS и сотни других коллекций.

Вот с этим может быть проблема, TRD же это готовый образ, где одна дорожка 4к, можно читать посекторно с карты по 512 байт и сразу слать.
В SCL же формат такой
0-7 байт "SINCLAIR"
8 байт - кол-во файлов
далее по 14 байт заголовки из нулевой дорожки (обрезаны 2 байта, начальный сектор и дорожка)
Если блоки данных будут располагаться не на границе сектора, то придется читать в буфер из 2 секторов, а это увеличивает в 2 раза время чтения, в принципе с этим можно разобраться добавив пробелов между секторами.

Основная проблема - это нулевая дорожка, которую нужно генерировать налету, т.е. копируем 14 байт, вычисляем дорожку - сектор по длине, кладем в буфер 16 байт, и т.д. Теоретически, это можно сделать, практически же, при эмуляции без буфера дорожки, мне кажется очень проблематичным.


UPD: да и что мешает сконвертировать SCL в TRD? в том же FAR с плагинами или еще в какой программе.

Eltaron
04.04.2016, 21:03
что мешает сконвертировать SCL в TRD? в том же FAR с плагинами или еще в какой программе.
А что мешает сконвертировать SCL в TRD прямо на атмеге и положить во временную директорию на карте? Да, помойка, которую раз в год придётся чистить - но невелика плата.

tank-uk
04.04.2016, 21:42
SCL в TRD прямо на атмеге
тогда уже прикрутить к меге SPI-Flаsh и напихать туда конверторов из всего в TRD

Eltaron
04.04.2016, 21:58
тогда уже прикрутить к меге SPI-Flаsh и напихать туда конверторов из всего в TRD
Какое-то невероятное усложнение ради единичных защищенных релизов (которые после конвертации ещё и, очевидно, работать не будут). А SCL - это такой же распространенный формат, как и TRD (а то и более).

А если пихать конвертеры "из всего", то надо конвертировать не в TRD, а в теледисковый TD0, к примеру. Но это совсем другой проект уже получается.

newart
05.04.2016, 06:41
UPD: да и что мешает сконвертировать SCL в TRD?
То же что и мешало TRD в RAW ))

юзабилити

trader2k4
05.04.2016, 06:43
А что мешает сконвертировать SCL в TRD прямо на атмеге и положить во временную директорию на карте? Да, помойка, которую раз в год придётся чистить - но невелика плата.

Ответ, имхо, прост: если заливать на SD образы дисков всё равно прийдется на ПК, со всей его мощью - зачем напрягать этим Атмегу, которой и так ресурсов едва хватает на собственно эмуляцию? Тем более если операция разовая, залил и забыл - а пк это сделает явно быстрее! Лучше доделать выбор TRD-образа из имеющихся и индикацию, это нужнее.

newart
05.04.2016, 06:51
А SCL - это такой же распространенный формат, как и TRD (а то и более).
Как оказалось примерно поровну:

http://spectrum4ever.org/temp/scl.png

http://spectrum4ever.org/temp/trd.png

Но тут скорее важно, то что все новые и почти все старые релизы на Virtual TR-DOS лежат в SCL.

s_kosorev
05.04.2016, 08:21
Имхо хорошая практика чередовать этапы, фичи/стабилизация, фич уже валом, есть смысл стабилизировать, что бы более уверенно на следующую итерацию переходить

Eltaron
05.04.2016, 11:15
Ответ, имхо, прост: если заливать на SD образы дисков всё равно прийдется на ПК, со всей его мощью
Вспомни, как все вздохнули с облегчением, когда телефоны стало можно цеплять по USB и они стали видны как диски в системе. До этого, напомню, было несколько лет мучений со специализированными программами от Nokia, LG, Samsung, которые, в общем-то, позволяли делать всё то же - заливать видео и музыку. Но с лишним геморроем.

А кодирование видео под первые смартфоны и телефоны с большим экраном? Захотел посмотреть фильм в электричке - будь добр, сконвертируй его в 320x240 3gp проприетарным кодеком. Неудобно это всё, отбивает желание пользоваться.


зачем напрягать этим Атмегу, которой и так ресурсов едва хватает на собственно эмуляцию?
Так не надо напрягать атмегу. Это два разных процесса, никакая эмуляция во время конвертации не работает. Атмега смотрит на расширение, если scl, то запускает функцию из 20 строчек, конвертирующую scl в trd. Её работа займет несколько секунд, но это намного приемлимей для пользователя, чем пусть те же несколько секунд, но ручной работы при каждом залитии на SD новых образов.
Единственный ресурс тут - объем флэша, но его, думаю, хватит.

Petit FatFS, как я понимаю, не умеет создавать файлы, поэтому задача внезапно даже упрощается. Нужен один заранее созданный /.tmp/image.trd в 655360 байт, который будет перезаписываться новыми данными при каждом открытии SCL-файла.

AlexNN
05.04.2016, 13:08
Поддерживаю, что нет смысла засорять проект левыми конвертерами, тем более, что это требует не пяти минут труда,
да и большинству не особо нужно.

solegstar
05.04.2016, 14:56
Конвертер для винды уже написан, если что: http://zx-pk.ru/showthread.php?t=22360&p=663286&viewfull=1#post663286 Позволяет делать пакетное преобразование форматов. drag`n`drop поддерживается. :)

EvgenRU
05.04.2016, 21:22
Короче, сейчас я допиливаю ядро, это у меня займет какое-то время, уже добился быстрой загрузки даже из конца диска, т.е. быстрая смена дорожек происходит, как окончательно всё допилю, тогда за интерфейс возьмусь.

PS: сразу говорю, эмуляция предусмотрена будет только для TRD, остальное можно действительно налету в TRD и т.д. Впилить создание файла в петит не проблема, тем более что там от петита одно название осталось )))

tank-uk
06.04.2016, 05:56
наверное все таки TD0 было бы универсальнее , и CP/M, и IS-DOS, и не стандартную разметку можно было бы загружать с эмуля

Eltaron
06.04.2016, 20:48
наверное все таки TD0 было бы универсальнее
TD0 внутри представляет собой мешанину из заголовков и данных произвольной длительности. Поэтому любая попытка спозиционироваться на какой-либо сектор займет O(n), очень долго. Если бы было много RAM, можно было бы сгенерировать какой-нибудь индекс и брать смещения секторов оттуда, но на ардуине его просто негде хранить.

В TRD наоборот, любой сектор лежит по фиксированному смещению, которое моментально рассчитывается из номеров стороны, трека и сектора.

EvgenRU
07.04.2016, 00:06
Последние изменения:
- Быстрая генерация таблицы кластеров для треков без загрузки полного сектора для каждого нового кластера
- Инвертированная таблица MFM для быстрой выдачи сигнала
- Оказалось, что с таким сигналом от атмеги нет необходимости менять первый бит первого байта MFM :) Это прогресс!!! Сильно ускорило прерывание.

PS: уже подумываю над тем, чтобы прикрутить возможность записи.

PS2: если кто-то уже опробовал код, отпишитесь плз :)

newart
08.04.2016, 05:52
PS2: если кто-то уже опробовал код, отпишитесь плз
Хочу попробовать. Но не хватает схемы. В частности как цеплять SD. У меня есть шилда с 5100 и SD. Она пойдет?

И исходник не собирается.

вот такая ошибка: https://www.dropbox.com/s/n4tnl9gobvgefir/%D0%A1%D0%BA%D1%80%D0%B8%D0%BD%D1%88%D0%BE%D1%82%2 02016-04-08%2005.50.16.png?dl=0
ну и структура папок проблемная. Git же в имя папки добавляет master, и поэтому ардуина ide ругается и создает новую папку, в которую приходится кидать остальные файлы.

- - - Добавлено - - -

Если связался с ардуино, то обьяснять нужно как для дебилов. )
На уровне "этот проводочек туда, а этот сюда". ))

trader2k4
08.04.2016, 07:48
У меня тоже не собиралось, пока:
1) не обновил IDE до последней версии;
2) не пересоздал основной файл проекта, скопировав в него содержимое из оригинала.

Странновато, конечно - но после этих шаманств собирается успешно, в выходные попробую к Пентагону подключиться и потестить.
Подключение SD-карты вроде в исходниках описано:

#define SPI_CS PB2 // pin 10
#define SPI_MOSI PB3 // pin 11
#define SPI_MISO PB4 // pin 12
#define SPI_SCK PB5 // pin 13

EvgenRU
08.04.2016, 07:58
Хочу попробовать. Но не хватает схемы. В частности как цеплять SD. У меня есть шилда с 5100 и SD. Она пойдет?
И исходник не собирается.
Если шилд стандартный, то должен подойти, хотя в описании к нему говорится, что CS должно быть на пине 4, вот тут может быть проблема.
Не собирается, т.к. IDE староватое, 1.0 версия, сейчас уже 1.6.8


ну и структура папок проблемная. Git же в имя папки добавляет master, и поэтому ардуина ide ругается и создает новую папку, в которую приходится кидать остальные файлы.
Ну, тут проще слово master убрать из названия папки :)
Насчет подключения, я вроде бы все пины подписал в самом начале файла.
Насчет подключения к шлейфу, на 16 странице вроде писал.

artyr_n
08.04.2016, 08:22
С Git есть еще одна особенность он преобразует все перевод строки возврат каретки в перевод строки, решил проблему следующим образом
$ git config --global core.autocrlf true
ну и дальше клонирование, при этом git сам заменяет все LF на CRLF

EvgenRU
08.04.2016, 08:45
Или, как вариант, можно скачивать архив с гитхаба :)

PS: сейчас добавлю дефайнов, чтобы не нужно было обновлять Arduino IDE

Добавил дефайны, нормально скомпилировалось на версии 1.0.5, правда в ней код получился на 600 байт больше чем в 1.6.8.

kox
08.04.2016, 09:06
Лучше схему и прошивку готовую выложите:)

EvgenRU
08.04.2016, 09:13
Лучше схему и прошивку готовую выложите:)

Прошивку пожалуйста, с батником для avrdude (фьюзы уже прописаны) да и сделать её можно самостоятельно в Arduino IDE последней версии. Схему... пока что рановато, как на ардуино будет всё закончено, тогда можно будет и схему рисовать. Смотрите в исходниках какие пины куда, в дефайнах написано.

PS: проверил карту с размером кластера 1к, тоже нормально работает.
PS2: добавил поддержку кластера 512 байт, не очень актуально, но пусть будет :)

PS3: к сожалению, запись пока что сделать не получается, попробовал, но никак... непонятные данные считываются с флопика да и мороки с этим много, так что девайс будет RO :)

EvgenRU
08.04.2016, 22:16
В последнем обновлении скорость загрузки просто чумовая! Сам в шоке! :-D

PS: в ближайшее время планирую поменять пины так, чтобы было легко вывести на разъем FDD, ну и потом уже начну браться за интерфейс.

s_kosorev
08.04.2016, 22:59
PS3: к сожалению, запись пока что сделать не получается, попробовал, но никак... непонятные данные считываются с флопика да и мороки с этим много, так что девайс будет RO
а в чем загвоздка?

EvgenRU
08.04.2016, 23:14
а в чем загвоздка?

Ну, я делал как, поставил Write Gate на прерывание INT1, по Fallen Edge он выключал TX, включал RX (одновременно), в векторе USART_RX_vect принимал данные, по кейсам смотрел, фигня какая-то получалась, потом сделал получение 512 байт в буфер и вывод их при чтении секторов, в итоге там оказалась фигня какая-то, местами похожая на правду, местами нет. Я так понял, там шлется дорожка целиком после прихода сигнала на WG? Насколько точно получится синхронизироваться в Master SPI по битам? Получится ли считать данные так, чтобы было удобно из мини-таблицы раскодировать?

s_kosorev
09.04.2016, 02:11
там шлется дорожка целиком после прихода сигнала на WG? Насколько точно получится синхронизироваться в Master SPI по битам?
Мне кажется проще за другое устройство зацепиться, по WG включать обработчик прерывания на WData, обработчик должен реагировать на фрон к примеру, в обработчике перезапускать таймер, в общем получится поток замеров между импулсами, его уже вторым потоок анализировать или к примеру кидать быстро во временный файл на SD, и при смене дорожки анализировать, вытягивать mfm разметку итд и писать в образ

- - - Добавлено - - -

После того как был отправлен маркер, если появился WG передачу прерывать и запускать второй обработчик, который замеряет растояние между импулсями

- - - Добавлено - - -

Можно конечно извратиться и попробовать зацепиться за синхронизацию, но возможность подстраивать не будет, замерять расстояние между импульсами, более надежный способ, чем читать как SPI, нагрузка больше конечно, но временный файл может решить проблему, но есть еще момент, форматирование диска, это самый плотный поток, но думаю на него можно забить

- - - Добавлено - - -

О! самый четки вариант как мне кажется такой

Работаем в обычном режиме, посамтривая на WG, если он активируется, то программно синхронизируемся, подстраивая фазу таймера под источник, после этого таймер заставляем генерировать клок для SPI, который переключаем в slave
получается и прерывания не часто и словить фазу правильную можно, можно даже таймер подстраивать в теории

EvgenRU
10.04.2016, 09:21
Спасибо, завтра попробую, но не уверен что получится, хотя, в примере на http://firmware.altervista.org/Data%20Encoding%20and%20Decoding.htm вроде получилось по таймеру

- - - Добавлено - - -

Расчехлил я лог анализатор и решил посмотреть, что же там за сигнал идет с WRITE DATA и WRITE GATE, увиденное меня несколько озадачило... я надеялся увидеть что-то похожее на READ DATA, а там....

Это запись дорожки в которой во всех секторах нули в Real Commander
56772
Это подробности сигнала при записи дорожки
56771

Это запись с помощью команды SAVE "k" в тырдосе
56769

Как видите... сигнал существенно отличается... Что там передается - непонятно, есть ли там заголовки и поля не пойму, может там данные в чистом виде?

Судя по внешнему виду сигнал кодируется так
Пульс (HIGH) на 42нс, потом LOW на 4, 6, 8 мкс, но есть местами и 101 (все по 42 нс), а есть большие промежутки, больше чем 8 мкс.
В самом начале дорожки вообще какие-то непонятные сигналы.

PS: почитал еще информацию по контроллеру http://www.defence-force.org/computing/oric/hardware/microdisc/FDC-179x-datasheet.pdf
там есть 2 вида команд записи, запись дорожки и запись сектора.


------------------------

UPD: кажется разобрался
Вот запись 1 дорожки в Real Commander
56773
В предыдущем случае писалась 0 дорожка, а для нее RC использует 9 секторов, поэтому 9 записей было, а тут 16, всё норм.

Т.е. запись происходит записью секторов (Команда Write Sector контролера).
Сектора пишутся прям в область данных сектора.

Команда Write Track используется только при форматировании.

Т.е. схема такая
После отправки заголовка сектора проверяем Write Gate, если он LOW, то
1) отключаем передачу, запускаем чтение
2) ждем пока принимаемый байт равен нулю
3) пропускаем 8 принятых байт
4) получаем данные сектора (256 байт сектора = 512 байт MFM)
5) получаем CRC (2 байта = 4 байта MFM)
6) проверяем CRC
7) записываем 2 сектора старый и новый на SD, если CRC совпали

шаги 5,6 можно опустить для простоты
------------------------

UPD3: Снял диаграму на 1MHz, вроде похоже на правду
56775
т.е. пропускаем 12 байт, пропускаем маркер и читаем данные с CRC

EvgenRU
10.04.2016, 21:11
Всё-таки решил я окончательно, что не буду делать запись, очень сложно и почти нереально на ардуине. Чтения более чем достаточно, чтобы закинуть кучу образов на флешку и играться с ними :-D

В последнем обновлении поменял пины местами, чтобы удобно было подключаться к кабелю дисковода, использую теперь PCINT2 вместо INT0.

Картинка, как всё это дело подключать так же закинута на гитхаб, но и тут приложу на всякий.

56785

kox
10.04.2016, 21:49
А дисплей куда подключать?

EvgenRU
10.04.2016, 23:00
А дисплей куда подключать?

Дисплей пока что никуда, я еще думаю над ним :) пока что на карту кидается default.trd и с ним идет работа. Но, в целом, пинов еще достаточно и для дисплея и для кнопок.

PS: пока что свободные пины - PB1, PC0-PC5, итого 7 штук.


PS2: всё еще есть некоторые проблемы, связанные с переключением сторон в процессе чтения дорожки, надеюсь удастся окончательно побороть с новым подходом к чтению сектора.

EvgenRU
12.04.2016, 22:20
Итак, товарищи, есть проблема с переключением сторон, как я уже говорил, сторона может измениться для любого сектора дорожки, и это факт!
Таким образом, нужно хранить в памяти сектор одновременно для двух сторон, т.е. под это дело придется использовать целый 1К памяти!!! + грузить 1К с флешки после отправки двух секторов. Буду пытаться провернуть эту операцию, так что ожидайте. Тот вариант, что есть сейчас, работает, но не для всех файлов, т.е. попадаются такие, которые расположены в середине дорожки и они могут не грузиться.

AlexNN
12.04.2016, 23:10
Что если в момент смены стороны, заставить подождать контроллер дисковода (как будто не читается или более культурно),
а в это время подготовить данные для дугой стороны, такие ситуации видимо не часто происходят и не сильно замедлят в реале.

EvgenRU
12.04.2016, 23:52
Что если в момент смены стороны, заставить подождать контроллер дисковода (как будто не читается или более культурно),
а в это время подготовить данные для дугой стороны, такие ситуации видимо не часто происходят и не сильно замедлят в реале.

К сожалению, это именно текущий вариант, практика показала, что смена стороны может происходить довольно часто, видимо турбоформат сказывается или еще что.

Так что секторы обеих сторон должны быть в памяти на случай смены стороны. Я уже, в принципе, этот вариант сделал, он работает, осталось допилить и дооптимизировать, надеюсь завтра-послезавтра выложу на гитхаб. Но памяти осталось примерно 200 байт )

CodeMaster
13.04.2016, 10:18
т.е. попадаются такие, которые расположены в середине дорожки и они могут не грузиться.

Может как-то дефрагментировать образ диска перед использованием или это не универсальное решение?

kox
13.04.2016, 13:45
А можно прошивку новой версии скомпилированную сюда выложить- девайс спаял, не хватает карты памяти и прошивки.

s_kosorev
13.04.2016, 15:07
тоже не понимаю, если есть LBA всех секторов на треке, какая разница с какой стороный читать, дисковод не обязан вот так сразу нужный сектор подставлять по головку после смены, вполне законно оборот диска протормозить

- - - Добавлено - - -

в реальности же, прервать чтение текущего сектора с карты, начать чтение другого сектра с сдкарты (ну в холостую прощелкать еще полсектора если он во второй половине FAT32 сектора лежит), на первый взгляд вообще не критичная для работы задержка выходит

EvgenRU
13.04.2016, 20:32
Здесь проблема другого характера, контроллер, почему-то настолько тупой, что не проверяет в заголовке адресного поля значение стороны!!!!!!!!!!!!!!! Он считает, что данные должны быть с той стороны, которая выставлена на линии SIDE!!!! Это проверенный факт!!! В этом-то вся и проблема!!! Т.е. мы должны давать ему сектор той стороны, которая установлена на линии SIDE, если side в заголовке не совпадает с линией SIDE, то контроллер спокойно считывает такой сектор и думает, что он с нужной стороны.
ЭТО ГЛАВНАЯ ПРОБЛЕМА, почему нельзя держать данные только одной стороны!

PS: частично я эту проблему решил, подставляя неправильное CRC при смене стороны во время чтения дорожки или начиная новую дорожку.

s_kosorev
13.04.2016, 21:10
А просто выдачу адресного маркера нельзя блокировать при смене стороны? если нельзя останавливать данные, нет адресного маркера, контролер не зацепится

EvgenRU
13.04.2016, 23:40
Нашел вот материальчик

-------------------------------------------------------------------------------

ПРИЛОЖЕHИЕ 3

Параметры стандартного формата TR-DOS
(cracked from TR-DOS)


При форматировании дисков TR-DOS (дисковая система ZX Spectrum) использует
следующие особенности:


IAM (адресный маркер дорожки) отсутствует
Длина синхропробела = 12 байт
Число MFM-маркеров 0xA1 в IDAM и DATA AM = 3

Длина GAP4A = 0 байт
Длина GAP1 = 10 байт
Длина GAP2 = 22 байт
Длина GAP3 = 60 байт
Длина GAP4B = до конца дорожки

Содержимое заголовков секторов:
Отсчет номера цилиндра C начинается с 0.
Байт H (номер головки) всегда равен 0x00.
Отсчет номера сектора R начинается с 1.
Байт N (код длины сектора) равен 0x01 (т.е. сектор 256 байт).

16 секторов на дорожке с интерлейвом 8 (т.е. порядок следования
секторов на дорожке следующий 1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16).
Взято отсюда http://fido7.ru.dos.narkive.com/cxtGdUZQ/udi

Отсюда следует, что SIDE всегда равно нулю на дискете и регулируется исключительно сигналом SIDE.... вот оно! Если бы раньше это прочитать, сколько бы времени сэкономил :)

Блокирование адресного маркера и сектора аналогично замене CRC.

kox
14.04.2016, 09:56
Прошил эмулятор, закинул на карту Default.trd, в итоге имею Disk Error trk 0, esc 9.
При этом видно, что при обращении к диску A идет чтение с карты, на 8 пане появляется (index) появляются импульсы, на 30 пине (Read Data) появляется что-то похожее на данные. Если обратиться к диску, при отсутствующей карте памяти, то выдает No disk.
Все прозвонил, спаянно верно. В какую сторону копать?:)

EvgenRU
14.04.2016, 10:26
Попробуйте назвать файл с маленькой буквы

kox
14.04.2016, 10:43
Пробывал-не помогло(
А не могли бы вы выложить прошивку готовую и образ, с которым у вас все работает.
А то фиг знает-что я там накомпилировал- никогда не сталкивался с arduino.

EvgenRU
14.04.2016, 10:52
Пробывал-не помогло(
А не могли бы вы выложить прошивку готовую и образ, с которым у вас все работает.
А то фиг знает-что я там накомпилировал- никогда не сталкивался с arduino.

Пожалуйста

PS: это последняя версия, в которой сектора обеих сторон в памяти

kox
14.04.2016, 11:08
Такая же петрушка(
Я вот что думаю- у меня Arduino nano с микросхемой UART-USB CH340, по схеме этой платы UART используется в интерфейсе дисковода, и параллельно ему висит CH340, может она мешает нормальной работе?

EvgenRU
14.04.2016, 11:14
Такая же петрушка(
Я вот что думаю- у меня Arduino nano с микросхемой UART-USB CH340, по схеме этой платы UART используется в интерфейсе дисковода, и параллельно ему висит CH340, может она мешает нормальной работе?

Проверьте, что у вас там точно 328 атмега, а не 168, проверьте соединения все. Насколько я помню, у вас не ВГ93 ?

kox
14.04.2016, 11:24
Точно Atmega328р, программатор avrisp mk ii определяет ее именно как Atmega328p, на корпусе тоже самое написано.
Соединения проверил-все верно. У меня не ВГ93, а mb8877a, ее полный аналог, с дисководами работает на отлично.

А не могли бы вы чисто для отладки дописать немного код- если карта с файловой системой проинициализирована без ошибок, то на неиспользуемый вывод A0 подать 1, если при инициализации происходит ошибка, то на вывод A1 подать 1? Хочу выяснить-может у меня проблема с картой.

EvgenRU
15.04.2016, 07:27
Если бы карта не инициализировалась, то на выходе READ DATA не было бы сигнала. Скорее всего ваш контроллер более "правильный" и не хочет понимать такой сигнал. В последней версии на гитхабе я поправил этот момент, попробуйте, возможно заработает. На всякий случай HEX выложу.

kox
15.04.2016, 08:35
Попробовал- та же самая ошибка, но теперь она выскакивает через 3 секунды после команды LIST, с предыдущей прошивкой ошибка выскакивала секунд через 10.

solegstar
15.04.2016, 09:47
EvgenRU, а плата ардуины расчитана на довольно жесткие подтяжки её выходов к +5В в контроллере дисковода? напомню, что как выходы контроллера дисковода, так и выходы самого дисковода сделаны с "открытым коллектором".

s_kosorev
15.04.2016, 10:04
Кстати звон на side мог быть из за этого
Анализатор ловил помехи источника питания в перемешку с полезным сигналом

EvgenRU
15.04.2016, 18:44
Так вроде я PullUp на всех входных пинах включил, так что проблем с этим быть не должно.

2kox, раз он так реагирует, тут или INDEX можно попробовать подтянуть или как-то поправить MFM сигнал, может конденсатором с сопротивлением, возможно ваш контроллер в таком виде не воспринимает...

Насчет SIDE, я так полагаю, что тырдос пытается последовательно считать файл переключая стороны, если он расположен на двух сторонах. Т.е. он пытается считать сектор с другой стороны, а т.к. проверки на сторону нет (при установке бита не проверять сторону), то она определяется по сигналу SIDE, что эмулятор обеспечить не может в процессе трансляции дорожки.

kox
15.04.2016, 19:09
Сигнал index у меня подтянут в контроллере , на осциллографе четкие отрицательные импульсы 5гц, а вот про конденсатор и резистор можно поподробнее?

EvgenRU
15.04.2016, 19:34
Сигнал index у меня подтянут в контроллере , на осциллографе четкие отрицательные импульсы 5гц, а вот про конденсатор и резистор можно поподробнее?

http://zx-pk.ru/threads/26328-planiruyu-sdelat-fdd-emulyator-na-atmega8.html?p=864795&viewfull=1#post864795

kox
15.04.2016, 21:50
Это получается так- с ноги ардуино через конденсатор, пан контроллер, и в точке соединения конденсатора с контроллер ос под тянуть на 5в?

EvgenRU
15.04.2016, 21:51
Вроде да, судя по лог анализатору сигнал нормальный, но у меня так не заработало.

kox
15.04.2016, 22:00
Инвертировать не надо с последней прошивкой?
Теперь только в понедельник попробую- все это колдунство на работе.:v2_dizzy_coder:

EvgenRU
15.04.2016, 22:16
Не, инвертировать не надо, там уже инвертированный программно сигнал

UPD: В последней версии поправил MFM кодирование, попробуйте её, может у вас заработает.

kox
18.04.2016, 10:25
С последней прошивкой все заработало- только вы писали, что быстрее, чем обычный флоп, а у меня на мой взгляд работает чуть медленнее.
И некоторые игры с вашего образа не грузятся- может еще подкрутить что-нибудь?

EvgenRU
18.04.2016, 16:17
Да нет, подкручивать ничего не надо, в настоящий момент есть проблема, большинство файлов грузится нормально, а на некоторых почему-то перестает изменяться сигнал SIDE и они подвисают на одной дорожке, не пойму пока что почему, то ли сектор вычитать не могут, то ли еще что, причем это не зависит ни от расположения файла в TRD, ни от размера кластера. Они просто, то читаются, то нет.... уже несколько дней с этим мучаюсь ) надеюсь удастся победить в итоге.

Собственно, из-за попыток это побороть он и работает медленнее немного.


UPD: залил последнее обновление, вернулся обратно к буферу 512 байт, теперь работает постабильнее, еще несколько костылей поставил для более стабильной работы :)

kox
19.04.2016, 09:25
Отлично! Завтра залью- отпишусь.:v2_dizzy_punk:

- - - Добавлено - - -

Попробывал новую версию- субъективно быстрее, но по прежнему не все игры запускаются.

EvgenRU
20.04.2016, 00:00
Кажется я понял в чем проблема

56913

Буду смотреть в этом направлении :)


UPD: не, фигня, оно всегда HIGH...

UPD2: всё-таки придется поменять немного пины, не успевает PCINT оперативно реагировать на STEP, изменения будут такие PD4,PD5 переместятся на PD3,PD4, а PD3 пойдет на PD5

kox
20.04.2016, 10:51
Ну что ж....ждемс...:)
Обновите тогда схему на гитхабе.:)

EvgenRU
20.04.2016, 11:22
Больших улучшений это не дало, так что оставлю пока как было :) Продолжаю эксперименты и изучение документации...

UPD: тщательно проанализировал сигналы с реального дисковода, нашел много недочетов, буду переделывать, чтобы соответствовало, может тогда будет работать как надо :)

UPD2: выяснился один приятный момент, можно спокойно делать паузы между секторами, это снимает все проблемы :)

EvgenRU
21.04.2016, 21:41
Залил новую версию.

1. Используется всего 800 байт SRAM, так что может пойти и на Atmega168p
2. Новый подход к генерации дорожки с остановкой прерывания после каждого сектора.
3. Генерируется таблица секторов для кластера, для быстрого переключения сторон, так же сектора идут с интерливом, как в оригинальном TRDOS формате, т.е. 1,9,2,10.....
4. Работает немного медленее чем раньше, но очень стабильно.
5. При таком подходе гораздо проще сделать режим записи :)

UPD: НАКОНЕЦ!!! решил проблему с подвисанием загрузки некоторых игр! Банально, забыл очистить флаг прерывания перед запуском прерывания STEP :) Теперь 99.9% успешно грузится то, что раньше часто зависало.

kox
22.04.2016, 09:11
З А П И С Ь хооооотееееть!!!!:v2_dizzy_christmas:
Завтра попробую новую паршивку.:)

- - - Добавлено - - -

Залил новую прошивку- у меня не идут все те же игры, но по ходу это у меня проблемы со спеком, а не с эмулятором.

А когда экран с кнопками планируется?

EvgenRU
22.04.2016, 20:29
Ура! Докумекал я до того, что решил избавиться от прерывания для отправки данных, а слать всё в цикле по 16 секторам, т.е. остается только прерывание по сигналу STEP на который нужно реагировать очень оперативно (собственно оперативности сильно мешало прерывание по отправке данных)
Опробовал данный вариант, работает отлично! Всё грузится, ничего не глючит! Всё, вот его сейчас дооптимизирую, выложу, и на этом с режимом чтения можно будет закончить и переходить к очередной попытке реализации режима записи :)

UPD: последняя залитая версия работает на 100% стабильно! уже несколько раз проверил, пока что ни одного сбоя! Завтра еще погоняю на разных образах, если будет всё ОК то можно на этом заканчивать с чтением :)

UPD2: Ну что ж, я всё проверил, работает отлично, никаких проблем не замечено! В самой последней версии сделал очень качественное MFM кодирование! Т.е. поднял частоту USART в 2 раза до 1000кбит/с и время импульса теперь составляет 1мкс как в настоящем MFM а не как раньше 2мкс.

UPD3: для полноты картины выкладываю картинки с лог анализатора, первая - вид текущего MFM кодирования, вторая - загрузка DIZZY.1R


PS: с записью заморачиваться не буду, начну потихоньку приделывать экран и кнопки.

EvgenRU
24.04.2016, 20:53
Вот как-то так будет выглядеть работа после подключения TRD образа. Дисплей подключен по I2C (TWI) через стандартную китайскую платку.

Если кто-то планирует делать в последствии данное устройство, рекомендую заранее обзавестись I2C модулем
http://i3.ardunn.ru/1/2103/21023801/afacdb/i2clcd-jpg.jpg

И еще энкодером для перемещения по файлам и папкам и монтирования/отмонтирования TRD.

UPD: добавил нативную поддержку I2C LCD без внешних библиотек, размер прошивки уменьшился на 3кб и памяти свободной больше стало. Так же в FAT32 будет поддержка только коротких имен файлов т.е. 8 - имя + 3 расширение.

trader2k4
25.04.2016, 13:03
А может, всё-таки предусмотреть вариант с кнопками? Тем более есть такие варианты экранов: http://ru.aliexpress.com/item/Free-Shipping-LCD-Keypad-Shield-of-the-LCD1602-LCD1602A-V2-0-character-LCD-input-and-output/910879989.html?spm=2114.14010208.99999999.701.Bo6Q gk

EvgenRU
25.04.2016, 14:25
А может, всё-таки предусмотреть вариант с кнопками? Тем более есть такие варианты экранов: http://ru.aliexpress.com/item/Free-Shipping-LCD-Keypad-Shield-of-the-LCD1602-LCD1602A-V2-0-character-LCD-input-and-output/910879989.html?spm=2114.14010208.99999999.701.Bo6Q gk

Экран можно и не ставить, просто вы не увидите то, что выбираете.

Указанный вами вариант экрана не подойдет, т.к. он использует минимум 8 пинов, да еще и 10 пин, который используется под SD карту.

PS: на мой взгляд энкодер гораздо удобнее чем простые кнопки, да и не так уж он дорого стоит

Trol73
25.04.2016, 14:26
Главное - предусмотреть поддержку записи :) А экран с кнопками потом всегда можно будет прикрутить. Причём, экран желательно графический чтобы сделать нормальное удобное человеческое управление.
p.s. экран с кнопками, что по ссылке даже не получится впихнуть в 5" отсек

EvgenRU
25.04.2016, 14:29
Главное - предусмотреть поддержку записи :) А экран с кнопками потом всегда можно будет прикрутить. Причём, экран желательно графический чтобы сделать нормальное удобное человеческое управление.
p.s. экран с кнопками, что по ссылке даже не получится впихнуть в 5" отсек

С записью я решил не заморачиваться, всегда можно подключить рамдиск для этих целей или второй дисковод.
Кстати, никиевский экран тоже не войдет в 5.25, а вот OLED войдет, но уж как-то дороговато выйдет.

UPD: 16x2 экрана вполне достаточно будет, т.к. файлы будут 8.3 (короткие имена) + энкодером можно вращать 2 строки с произвольной скоростью, а кнопка на нем будет для выбора/отключения TRD образа и захода/выхода из каталогов.

Trol73
25.04.2016, 14:40
Вот такой должен влезать http://www.ebay.com/itm/1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Module-Display-Replace-Nokia-5110-LCD-/310876068105?hash=item4861a85909:g:9LoAAOSwpzdWqdY ~
И цветной, и чуть меньше нокиевского, и стоит не дорого.
А на счёт записи, может, ещё передумаете в будущем ) Ну и проект опенсорсный, если оно в принципе реализуемо на AVR 16Мгц, то рано или поздно, кто-нибудь подхватит.

EvgenRU
25.04.2016, 14:49
Ну да, мне уже надоело, что это макароны из проводов пол стола занимают, хочется уже что-то доделать :)
В принципе, там на поддержку записи ресурсы еще есть, но провода будут неудобно расположены, а так прям все параллельно.
Насчет дисплея, думаю модуль LCD можно будет сделать под поддержку разных экранов в будущем, если будет желание после того как это доделаю )

gdv2002
25.04.2016, 15:00
А ссылку на энкодер даст кто?
И еще, а на кнопки трудно переделать? Я программить совсем не умею :)
Хочу лицевую эмулятора под стандартное посадочное дискогрыза сделать.

Trol73
25.04.2016, 15:17
Печатную плату девайсу надо. Маленькую, аккуратную, специально заточенную. Возможно, две платы - дисплей + клава отдельно. Иначе, придётся иметь дело с макаронным монстром, который есть большой враг всякому энтузиазму :)
Я верно понимаю, что сейчас девайс работает на 16МГц и в принципе, ничего не мешает заменить МК на atmega128?

gdv2002
25.04.2016, 15:25
Печатную плату девайсу надо.
Согласен, чуть позже планирую сделать платку под НАНО, дисплей 16х2 и все-же кнопки хочу, но видно будет.

EvgenRU
25.04.2016, 15:32
Я верно понимаю, что сейчас девайс работает на 16МГц и в принципе, ничего не мешает заменить МК на atmega128?

Уже обсуждалось, у 128 атмеги нет MasterSPI в USART. Теоретически конечно можно попробовать через SPI его сделать, но это переделывать половину эмулятора :) Зато, тогда может заработать и на 8 атмеге :)


UPD: просьба к kox проверить последнюю прошивку на своем контроллере, т.к. я немного оптимизировал MFM кодирование.

kox
25.04.2016, 17:58
Завтра на работе проверю и отпишу:v2_dizzy_army:

newart
25.04.2016, 21:45
Так же в FAT32 будет поддержка только коротких имен файлов т.е. 8 - имя + 3 расширение.
Длинные будут обрезать или не будут видимы и выбираемы вообще?

EvgenRU
25.04.2016, 22:46
Да нет, там будет использоваться короткое имя файла для простоты, типа как было в Win95 в свое время
например, вместо "Program Files" было "PROGRA~1", ну и тут так же. Т.е. в фат32 есть 2 типа имени файла, короткое и длинное. Данный девайс не будет поддерживать длинные имена. Это, конечно, можно сделать при желании, но мне лень, да и памяти много жрать будет. А так норм папка "GAMES", а в ней файлы GAME0001.TRD и т.д.

AlexNN
25.04.2016, 23:52
На лицо лёгкий передоз от программирование, мотивация несколько затерялась, но тут ведь проект штучный, не сказать что супер актуальный,
но уверен, что не забудут многие в узких кругах, так что вы совсем на запись так уж не зарекайтесь, вдохновение должно ещё прийти второй или какой там волной! ))

Alex_LG
26.04.2016, 09:34
у 128 атмеги нет MasterSPI в USART
Насколько я понял, в данной разработке используюется "MasterSPI в USART" только из-за того, что позволяет ставить произвольную скорость SPI?
Если так, то используя кварц на 16МГц и учитывая, что сейчас скорость SPI 1000кбит/с это можно и на Меге8 сделать, установив скорость SCK=Fosc/16
Или я что-то не понял?

s_kosorev
26.04.2016, 10:02
только из-за того, что позволяет ставить произвольную скорость SPI?
16bit умеет spi в 328, на прерываниях позволяло нагрузку понизить

Запись имхо это V2, как по мне тут переосмысливать нужно, писать сложнее, думается, что скорее всего временный файл для быстрого сбрасывания захваченых данных нужен, если оставаться в рамках текущего чипа или даже даунгрейд на мегу8, как стояла задача первоначально, самое интересное, первоначально казалась практически невозможной

EvgenRU
26.04.2016, 12:00
Насколько я понял, в данной разработке используюется "MasterSPI в USART" только из-за того, что позволяет ставить произвольную скорость SPI?
Если так, то используя кварц на 16МГц и учитывая, что сейчас скорость SPI 1000кбит/с это можно и на Меге8 сделать, установив скорость SCK=Fosc/16
Или я что-то не понял?

MasterSPI в USART позволяет отключить старт/стоп биты при передаче, где этого режима нет, их отключить нельзя, поэтому выход только использовать таймер для передачи, теоретически ресурсов может хватить, нужно только переделать функцию send_byte для отправки по таймеру или через PWM. (насчет PWM не уверен, но теоретически возможно)

PS: насчет записи, я тут вижу только вариант считывания данных по таймеру, как описано здесь http://firmware.altervista.org/Data%20Encoding%20and%20Decoding.htm

PS2: энкодер уже прикрутил, работает отлично, остался только небольшой геморрой с перемещением по файловой системе ))))

UPD: на всякий случай, если кто-то не в курсе, как работает энкодер
https://i.ytimg.com/vi/CpwGXZX-5Ug/maxresdefault.jpg
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTRCQa_P3OGsKlOsIISCLlqwAT_r2fvX gHdT4nWuKd6jVZudMp8


Для тех кто загружает программатором, последняя версия без энкодера для заливки через avrdude
57003

Alex_LG
26.04.2016, 12:18
перемещением по файловой системе

Вот здесь сделано и перемещение и считывание каталога на ходу, правда для ПИКа, но на Си
http://zx-pk.ru/threads/19685-radio-86rk-na-novyj-lad.html?p=670310&viewfull=1#post670310

EvgenRU
26.04.2016, 23:48
В последней версии добавлена поддержка энкодера и перемещение по файловой система с монтированием/отмонтированием образов по нажатию на кнопку энкодера. Пока что заход во вложенные папки не поддерживается.

kox
27.04.2016, 14:29
Просьба к EvgenRU выложить последнюю прошивку без дисплея и энкодера, а то были дела и не успел ее слить с гитхаба, а дисплей еще не пришел, да и переходник i2c только заказал,ждать месяц.

EvgenRU
28.04.2016, 21:01
Гитхаб тем и хорош, что можно любую версию с него скачать, жмете на "66 commits" выбираете версию и жмете справа на значок "<>"
Вам нужен последний коммит от 23 апреля, на всякий случай, вот ссылка https://github.com/EvgeniyRU/ZX_FDD_Emulator/archive/8989759dfd685901e37172c33d6475514a9853af.zip

- - - Добавлено - - -

Всё, я кончил....

В смысле с программной частью, полная поддержка вложенных каталогов до 10 уровня (можно поменять в конфиге)
Дальше только ловля возможных багов, оптимизация и может какие-то украшения интерфейса и поддержка еепром для установки образа после перезапуска. Желающие могут придумать платку для 5.25 дырки :-D

kox
28.04.2016, 21:06
Отлично!
Может теперь запись? а?:)

kox
29.04.2016, 11:32
Проверил последнюю прошивку без поддержки дисплея-работает шустро, но образ выбирает не default.trd, а первый попавшийся на карте.

CodeMaster
30.04.2016, 08:42
Может теперь запись? а?

А может быть поддержку какого-то универсального формата дампов дисков, а не только TRD?

fifan
02.05.2016, 13:10
А может быть поддержку какого-то универсального формата дампов дисков, а не только TRD?
Поддерживаю. Меня интересует формат odi для Ориона/Специалиста.

s_kosorev
02.05.2016, 13:24
имхо с универсальными фоматами, запись если будут реализовывать, будет труба, trd все же проще на порядок, синхронизация, генерируется при чтении и её смело можно скипать при записи, на затраты как по мне, влияет существенно

- - - Добавлено - - -

я бы на месте автора, не распылялся бы на всякую фигню, придерживался бы первоначального плана, идеально было бы вообще спуститься на mega8
для всяких других форматов, есть всякие другие эмуляторы, этот позиционируется как предельно простой, все хотелки кроме записи trd скипать