Lethargeek, для плис можно увеличить количество уровней, а блоки флагов во внешней памяти уменьшить хоть до байта, остальные флаги хранить в блоках памяти внутри плис, скажем на нижнем уровне 8192 блока по 8 флагов, остальное уже в плис - 512 блоков по 16 флагов, далее 32 блока по 16 флагов, а на верхнем уровне регистр в 32 бита. Доступ к памяти без клонирования будет требовать дополнительно(кроме операций внутри плис) только прочитать байт флагов, а запись с клонированием будет требовать RW для флагов и RWW или RWWW(если пишет Z80) для данных, то есть 5 или 6 операций. Цифра на первый взгляд дикая, но столько операций делает только один из клонов, остальные только две, поэтому если поделить на троих, получится в среднем около 3х операций.

Что касается количества клонов Z80 влезающих в плис, то реально требуется один полноценный клон, полноценный в том смысле, что выполняет программу параллельно с Z80, мы всегда знаем что у него в регистрах и можем создавать в нужный момент еще два клона CPU0 и CPU1 которые будут рисовать на фоне из 0 и 1 соответственно. Можно попробовать обойтись и одним клоном, который будет рисовать на инверсном фоне, и считать что к спрайту относятся совпавшие точки, но в этом случае будут сложности с определением спрайтов рисуемых в режиме XOR. Что касается того, насколько быстро должен работать клон, то это требуется только если из-за изменения фона выполнение программы пойдёт другим путём, например после сдвига перенос бита в другой регистр делается не через ADC, а через условный переход и INC, хорошо если к моменту записи на экран клоны тоже успели до этого дойти и мы знаем какие из записанных точек фон, а какие спрайт.

В реальности такой путь боли конечно не нужен, поскольку есть zx-poly и spec256, а эмуляция двух десятков клонов позволит отслеживать точки и раскрашивать для них спрайты прямо на экране. Можно даже попробовать отслеживать точки не изучая код игры:

0) запоминаем начальное состояние нашей системы
1) эмулятор выполняет программу и записывает в лог все выполненные инструкции и обращения к памяти(чтобы потом было проще, можно записывать полный адрес, с учётом всяких страниц)
2) далее начиная с начального состояния, эмулятор запускается в режиме воспроизведения лога, выполняя только операции записи в память, а когда в буфере экрана появится интересная нам картинка воспроизведение останавливаем
3) создаём 32 клона и в каждый бит записываем его номер (кроме тех областей из которых судя по логу выполнялся код) умноженный на некоторую константу, допустим на 419, чтобы нумерация поместилась в 32 бита, но не имела в памяти клонов регулярной структуры
4) в памяти сначала располагаем нулевые байты всех клонов, потом первые, вторые и так далее до конца их адресного пространства
5) запускаем воспроизведение лога, при этом для всех клонов повторяем указанные в логе команды используя SSE регистры, но для команд читающих и записывающих память используем адреса из лога
6) из флагов при воспроизведении можно эмулировать только флаг переноса, поскольку нужен для всяких ADC, а остальное слишком сложно поэтому нафиг
7) когда мы дойдём до интересной нам точки, то для каждого бита извлекаем из памяти клонов его номер умноженный на нашу магическую константу 419 и если полученное число нацело не делится, значит нельзя сказать откуда оно взялось, если число не менялось, значит в этот бит программа еще ничего не записывала, ну а если число изменилось, но делится на 419, значит мы точно знаем откуда оно здесь взялось
8) конечно, при таком упрощённом подходе, спрайт отражённый через таблицу отследить мы не сможем, но с другой стороны где-то он наверно выводился и в нормальном виде и воспроизведя лог до другой точки может получиться раскрасить и его