Всплыли интересные вещи относительно точности эмуляции. Как известно, импульс маскируемого прерывания длится некоторое фиксированное время, за которое может произойти подтверждение прерывания и вход в процедуру его обработки. Длительность этого импульса в тактах z80 полагается эталонно равной 32. Так вот, существует программа тестирования эмуляторов minfo.tap, которая показывает длину фрейма, длину импульса прерывания и признак правильности эмуляции команды EI (об этом далее). Выяснилось, что эмулятор, который я считал эталонным, Spectaculator, некорректно эмулирует импульс прерывания. Программа показывает длину импульса прерывания = 0, что скорее всего означает, что эмуль считает возможным подтверждение прерывания строго после команды z80, на которой завершается фрейм. Правильно эмулируют импульс прерывания Fuse, ZXMAK2 и SpecEmu (возможно, и другие). ZXSPin определяет длину импульса прерывания = 37 тактам, а EmuzWin этот тест проваливает.
Относительно команды EI выяснилось, что она разрешает прерывания не сразу после своего выполнения, а после выполнения следующей за ней команды (чтобы предотвратить закольцовывание входа в процедуру прерывания и дать выполниться команде RET). Некоторые эмули этот факт игнорируют. Кстати, это означает, что команда EI запрещает прерывание сразу после себя. Таким образом, если импульс прерывания придёт во время выполнения цепочки из команд EI, он будет проигнорирован.
Следующая информация будет интересна скорее разработчикам эмуляторов, так как касается поддержки формата RZX. Его спецификация несколько размыто определяет поведение эмулятора в конце проигрывания rzx-фрейма. Базовый алгоритм по завершению фрейма имеет блок "Генерировать прерывание", а как вы его интерпретируете, ваше личное дело.
Большинство эмулей интерпретируют его так: если на момент окончания проигрывания rzx-фрейма IFF1=1, эмулируется подтверждение прерывания. Однако, таким образом игнорируются некоторые особые случаи :
1) последней командой фрейма может быть команда EI, соответственно, прерывания будут запрещены после её выполнения;
2) команда EI может быть предпоследней командой фрейма, а последняя будет на границе окончания импульса прерывания, соответственно, несмотря на то, что IFF1=1 (прерывания разрешены), и после последней команды могло бы быть подтверждение прерывания, его не будет, так как импульс прерывания на ней завершён. А эмуль, проигрывающий rzx-файл, посчитает, что вход в прерывание есть, сэмулирует его, и это приведёт к рассинхронизации дальнейшего проигрывания rzx-файла.
3) самый редкий, и самый сложный случай. как известно, длина команд с префиксами DD/FD может быть произвольной (повторные префиксы), и во время выполнения такой длинной команды прерывание не может произойти. Импульс прерывания может прийти во время выполнения такой команды, и закончиться за это время, а прерывания до неё - разрешены. Очень сложно корректно оформить конец rzx фрейма при записи rzx файла в такой ситуации. Единственным возможным вариантом, который видится мне, будет разрыв выполнения команды по приходу импульса прерывания, причём эмуль-проигрыватель rzx должен корректно такую ситуацию обработать.
Основным требованием к эмулятору-проигрывателю rzx-файла будет в таких случаях то, что эмуль должен учитывать не только состояние триггера IFF1 в конце rzx-фрейма, но и то, не запрещены ли прерывания, несмотря на то, что IFF1=1 (из-за EI или префиксов DD/FD). Увы, здесь поведение известных эмуляторов оставляет желать лучшего. Spectaculator, SpecEmu, ZXSpin, и EmuZWin, например, в случае, если фрейм заканчивается командой EI, делают вход в процедуру обработки прерывания, что приводит к потере синхронизации rzx. А вот Fuse и ZXMAK2 ведут себя корректно - так как прерывания сразу после EI запрещены, если фрейм заканчивается этой командой, они считают, что подтверждения прерывания не было.
Подытожим, как должен вести себя эмулятор для корректной обработки вышеприведённых особых случаев:
а) если на момент окончания фрейма выполняется команда с цепочкой префиксов DD/FD, эмуль должен корректно обработать разрыв её выполнения (считать все префиксы, кроме последнего, чем-то вроде отдельных команд NOP, запрещающих прерывания сразу после себя);
б) соответственно, если фрейм rzx заканчивается командой EI или префиксом DD/FD, эмуль должен считать, что подтверждения прерывания после фрейма нет, независимо от состояния IFF1.
Особый случай 2) при таком раскладе можно будет не слишком сложно обработать при записи RZX файла, завершив rzx фрейм не на команде после команды EI, а на самой этой команде EI.
Прилагаю архив с программой minfo.tap и rzx-файлом, на котором спотыкаются Spectaculator, ZXSpin, SpecEmu, и EmuZWin, но Fuse и ZXMAK2 успешно его проигрывают. Игра Jumping Jack в этом плане - находка для тестирования поддержки rzx файлов. Во время её выполнения прерывания в основном запрещены, но звук генерируется процедурой ПЗУ BEEPER, которая разрешает прерывания перед выходом из неё. Сразу после её вызова прерывания запрещаются, но - этого достаточно, чтобы время от времени прерывание срабатывало (после выполнения команды RET процедуры BEEPER перед командой DI в коде игры), и появлялась неоднозначность при записи/чтении rzx-файлов.
ints_tests.zip