В инете удалось найти документик, в котором описывался протокол взаимодействия имеющейся у меня версии LPT-программатора и софта. Скорее всего, алгоритмы, содержавшиеся в документе, были получены путём анализа схемы программатора, поэтому очень многое оставалось неясным.
Я решил, что мне вполне по силам написать свою утилитку управления, реализующую алгоритм программирования для интересующей меня микросхемы. Исходников старых версий оригинального софта найти уже не удалось, да они бы и не помогли наверняка из-за серьёзных изменений в железяке. Так как заниматься этой затеей пришлось в свободное от основной работы время, процедуры управления программатором были готовы только через две недели. Настало время реализации самого алгоритма взаимодействия с микросхемой.
Процедуры чтения и стирания были реализованы без особых затруднений, а вот на самом главном — записи — всё чуть не рухнуло. Проблема была в том, что данные для записи надо было успевать отправлять в жёстко ограниченный промежуток времени — 200 мкс. Такой расторопности не способствовали ни Windows с её многозадачностью, ни мой кривой код на Delphi (скорее всего, в большей степени). Доставляло и то, что если снизить искусственные временные задержки между формированием импульсов, то их не успевала отрабатывать логика LPT-порта и программатора.
Так как оригинальный софт успешно писал микросхемы с похожим принципом записи, было понятно, что задача выполнима, а значит, предстоит оптимизация. Хоть мне и не хотелось использовать многопоточность в простой программе, но пришлось. Выигрыш по времени выполнения это дало небольшой, зато исчезло заклинивание GUI при выполнении длительных операций. Пришлось заняться оптимизацией процедур управления программатором. Самой затратной оказалась процедура передачи в программатор адреса. Необходимо было адрес очередной ячейки, выраженный 24-битным числом, делить на три части по восемь битов и побитно сдвигать в три линии передачи, сопровождая каждую посылку формированием строб-импульса. Сложность заключалась в том, что Delphi 7 позволял осуществлять операции битовой арифметики только над восьмибитными переменными, к тому же используемые линии вывода были подвязаны к битам регистра LPT-порта не по порядку.
Первоначальный вариант алгоритма формирования адреса тормозил из-за использования операций возведения в степень и округления (с его помощью удалось обойти часть ограничений на битовую арифметику). Первая пришедшая в голову идея: перенести часть кода в ASM-вставку и использовать для возведения двойки в нужную степень команду FPU FSCALE. Какой-то выигрыш это дало, но временной интервал в 200 мкс продолжал нарушался с завидной регулярностью. Когда до меня дошло, что во вставке мне никто не мешает использовать операции сдвига над DWORD, удалось полностью избавиться от операции возведения в степень, но выигрыш по времени всё равно был недостаточным. Более-менее приемлемый результат удалось получить после шести переписываний куска кода с нуля. К этому времени за пределами ASM-вставки остались только вызовы процедур формирования импульсов и временных задержек, полностью исчезли операции возведения в степень, сдвиг DWORD тоже оказался ненужным, везде, где можно, использовались предварительно рассчитанные константы. Количество ошибок, возникающих из-за нарушения предельного интервала, свелось к минимуму, что позволяло реализовать коррекцию неправильно записанных блоков при контрольном чтении. В принципе, на этом можно было бы и остановиться, так как программа уже позволяла решить поставленную задачу, но мне захотелось сделать всё красиво.
В процессе листания справочников я наткнулся на упоминание о том, что по возможности нужно выносить большие ASM-вставки в отдельные процедуры, так как наличие ассемблера внутри обычного кода вызывает дополнительные потери времени. Так как вставка являлась большей частью процедуры, легче было перенести вызов функции формирования импульсов внутрь неё. С помощью встроенного отладчика удалось подсмотреть, что параметры этим функциям передаются смешанным образом: часть через регистры, часть через стек. Нормально посчитать смещения в стеке я поленился и просто подглядел их в отладчике, зная, какие значения у какой переменной должны быть.