Info Guide
#05
30 апреля 2004 |
|
Sofтинка - обзор экранных упаковщиков для ZX Spectrum.
ASCLZPAK, MSP1.6, Lazy Pack ASC Screen Crusher Один из первых серьёзных экранных паке- ров, ASCLZPAK (1991) определил основные идеи структуры большинства последующих фо- рматов и соответствующих им депакеров. А именно, хотя данные в файле пока и лежат только байтами,но впервые реализова- на довольно оптимальная последовательность просмотра экрана - ломаными столбцами. При этом экран логически разбивается на 3 тре- ти и атрибуты,где атрибуты линейны,а трети состоят из столбцов байт. Этот способ даёт возможность сжатия незначительно хуже спо- соба с полными столбцами, зато здесь проще пересчёт линейной модели в реальный экран. Познакомим читателя с идеей линейной модели ZX экрана. Заключается она в том,что каждому адре- су на экране взаимно однозначно соответст- вует виртуальный адрес в линейной модели, причём последовательность адресов экрана, порождаемая порядком просмотра (в данном случае - ломаными столбцами) выглядит на линейной модели последовательностью подряд идущих виртуальных адресов. Т.е.при после- довательном переборе виртуальных адресов линейной модели - адреса на реальном экра- не будут перебираться ломаными столбцами. Разумеется, для этого нужно использовать процедуры пересчета виртуальных адресов в реальные. Как правило, начальные адреса реального и виртуального экранов совпадают, чтобы адреса атрибутов не пересчитывались. Вот как выглядит пересчёт экранного ад- реса из виртуального в реальный по ASC'у (страшновато,но примите во внимание,что он первый!): ────────────────────────────────────────── LD A,H AND #58 CP #58 JR Z,atr LD C,A LD A,L AND 7 OR C LD C,A ADD HL,HL ADD HL,HL LD A,H AND #1F LD H,A LD A,L AND #E0 OR H LD L,A LD H,C atr ────────────────────────────────────────── Распаковщик ASCLZPAK, согласно тради- ции,перемещаем и для этого настраивает три пары ячеек программы под текущий адрес. Опасного использования стека нет. Перемещение по экрану ведётся в реаль- ных адресах, и для координации этого (нес- тандартное решение) применено 3 регистра- счётчика: A' = 8·номер столбца + 3-номер трети; B' = строка внутри знакоместа; C' = номер ряда знакомест внутри трети. Упакованные данные располагаются непос- редственно после программы.Формат простой: %0bbbbHHH,LLLLLLLL - ссылка назад, disp= =HHHLLLLLLLL, puts=bbbb+3 %10000000 - конец файла %10bbbbbb,байты - bbbbbb байт взять из потока %11bbbbbb,байт - повторить байт bbbbbb+3 раз (можно повторить байт до 66 раз, т.е. больше, чем через ссылку) Maxsoft Screen Packer 1.6 Упаковщик Maxsoft Screen Packer 1.6 поддерживает 3 режима распаковки и в связи с этим 3 различных распаковщика: 1. Непосредственно на экран, ломаными столбцами; 2. Через буфер ломаными столбцами; 3. Непосредственно на экран в экранной структуре. Последний вариант наиболее прост, но имеет,что понятно, худшее качество сжатия. Распаковка же через буфер ничем принципиа- льно не отличается от распаковки на экран. Поэтому ниже будет рассматриваться именно режим распаковки на экран (1) - RTD в терминологии автора программы (RealTime Depack). Следует отметить, что распаковщик MSP1.6 является наиболее запутанным экран- ным распаковщиком из всех, с которыми мы будем иметь дело. Если же сравнивать еще и с кодовыми, то рядом можно поставить разве что deHrust 1.x. В упакованных данных имеется два потока - битовый и байтовый. Выборка битов из по- тока производится парами байт (ADD HL,HL: DJNZ:POP HL:LD B,C), c использованием двух дополнительных регистров: B - счетчик, C - константа 16. Начало байтового потока (DEC SP:POP AF) приходится на третий байт фай- ла,после двух первых байт битового потока. В дальнейшем потоки чередуются в зависимо- сти от структуры файла.Битовый поток - уп- равляющий. Для перемещаемости депакера указатель основного стека сохраняется в регистре IY, а не в памяти. Также две смежных яче- йки программы подстраиваются под адрес её расположения: ────────────────────────────────────────── DI CALL #52 DEC SP,SP POP DE LD HL,#110 ADD HL,DE EX DE,HL LD BC,#98 ;адрес ldto ADD HL,BC ;(см.ниже) LD (HL),E INC HL LD (HL),D ────────────────────────────────────────── Таким образом реализуется подобие вызо- ва подпрограммы nxtde, которая, как вполне понятно, делает обычную операцию перевода указателя DE на следующий байт экрана по структуре ломаных столбцов: ────────────────────────────────────────── nxtde INC DE LD A,D CP #58 JR NC,atr DEC DE INC D LD A,D AND 7 JR NZ,atr LD A,E ADD A,#20 LD E,A JR NC,sub8 INC E BIT 5,E RES 5,E JR NZ,atr sub8 LD A,D SUB 8 LD D,A atr JR ... ;смещение в этом JR ;может принимать 2 разл.знач. ────────────────────────────────────────── (атрибуты - линейно). Вызов происходит так: ────────────────────────────────────────── LD A,#8B ;смещение exjr ldto=$+1 ldjr LD (atr+1),A JR nxtde exjr EX DE,HL LD A,#90 ;смещение okjr JR ldjr okjr EX DE,HL ────────────────────────────────────────── Указанный фрагмент всегда проходится насквозь, то есть решалась задача именно смещения ОБОИХ указателей - HL и DE (вход- ного и выходного при копировании, соответ- ственно).Это связано с тем,что перемещение по экрану ведётся в реальных адресах,как в ASCLZPAK. Заголовка у файла нет, следует он непо- средствено за распаковщиком. Первый байт байтового потока (3-й байт файла) является первым байтом экрана,далее по битовому по- току: %0 - просто байт (из байтового потока) %100 - puts=3 %1010 - puts=2 (обратите внимание, код длиннее предыдущего. Это должно означать, что ссылки длиной 2 встречаются реже ссы- лок с длиной 3 ) %1011,байт: -1 =конец файла, -2 =16-битное значение puts (POP BC), иначе puts=байт+ +10 (puts=10..263) %1100 - puts=4 %1101 - puts=5 %11100 - puts=6 %11101 - puts=7 %11110 - puts=8 %11111 - puts=9 Если puts не равен 2, то производится декодирование старшего байта смещения (по- ложительного disp): %1 - 0 %0000 - 1 %0001 - 2 %00100 - 3 %00101 - 4 %00110 - 5 %00111 - 6 %010000 - 7 %010001 - 8 %010010 - 9 %010011 - 10 %010100 - 11 %010101 - 12 %010110 - 13 %0101110 - 14 %0101111 - 15 %0110000 - 16 %0110001 - 17 %0110010 - 18 %0110011 - 19 %0110100 - 20 %0110101 - 21 %0110110 - 22 %0110111 - 23 %0111000 - 24 %0111001 - 25 %0111010 - 26 %0111011 - 27 %0111100 - 28 %0111101 - 29 %0111110 - 30 %0111111 - 31 (ссылки с длиной 2 все короткие, т.е. dispH=0 ) Коды dispH>27 нельзя использовать в эк- ране,и это придаёт формату некоторую неже- лательную избыточность. Далее байт из байтового потока опреде- ляет младший байт смещения. Вычитание сме- щения из текущего адреса в виртуальном эк- ране ( IX адресует его в линейной модели) реализовано достаточно остроумно: ────────────────────────────────────────── DEC SP POP AF SUB LX CPL CCF LD L,A LD A,HX SBC A,H LD H,A ────────────────────────────────────────── После этого виртуальный адрес в HL пе- ресчитывается в экран и происходит копиро- вание блока. Затем всё описанное повторяе- тся и т.д. Lazy Pack 2.0 К сожалению, этим упаковщиком экранов могут воспользоваться не все - по непонят- ным причинам на большинстве версий TR-DOS программа при сохранении уничтожает ката- лог диска. Но формат заслуживает рассмот- рения. В формате использованы почти все хоро- шие идеи по сжатию экранов, какие только реализованы в LC5.2, но по длине распако- вщика Lazy 2.0, безусловно, проигрывает LC 5.2. Имеются битовый и байтовый потоки в простейшем варианте: битовый поток извле- кается побайтно в регистр D', B'=счётчик, C'=константа 8 для помещения в B'. Первый байт файла принадлежит битовому потоку. Виртуальный адрес экрана в линейной мо- дели содержится в IX, реальный адрес - в DE. Распаковщик не привязан к экрану, вызы- вается с параметром: HL=адрес упакованного экрана. Не использует стек (входные данные в HL' ). Распаковывает на экран #4000, но это число легко исправить на любое кратное #2000. Если немного изменить код, то и на любое кратное #800. Распаковщик достигает перемещаемости, организуя в области MEMBOT системных переменных бейсика три JP на три внутренние подпрограммы распаковщика,усло- вно назовём их get,down и bit. Определение своего адреса распаковщик делает через DEC SP,SP, поэтому нужно проследить,чтобы пре- рывания были выключены. get (+#aa, #5c97) - извлекает из бито- вого потока в аккумулятор число 0...23 по следующему дереву: %1 - 0 %01 - 1 %0010 - 2 %0011 - 3 %000100 - 4 %000101 - 5 %000110 - 6 %000111 - 7 %00001000 - 8 %00001001 - 9 %00001010 - 10 %00001011 - 11 %00001100 - 12 %00001101 - 13 %00001110 - 14 %00001111 - 15 %00000000 - 16 %00000001 - 17 %00000010 - 18 %00000011 - 19 %00000100 - 20 %00000101 - 21 %00000110 - 22 %00000111 - 23 down (+#cc,#5c9a) - пересчитать адрес в DE, чтобы он соответствовал следующему байту на экране (в порядке ломаных столб- цов). bit (+#ea, #5c94) - взять один бит из битового потока (результат во флаге пере- носа). Формат: %1 - просто взять байт (из байтового пото- ка); %0 - вызываем get. Если результат =7: Читаем некий byte из байтового потока. Если он не -1, то puts=byte+25, иначе вызываем get (putsH), потом извлекаем из байтового потока putsL. Если результат <7: Прибавляем 2, получаем puts=2..8. Если результат >7: Прибавляем 1, получаем puts=9..24. Далее вызываем get (dispH) и берём байт dispL из байтового потока.Реализуем полу- ченную ссылку и т.д. Специального кода выхода из распаковщи- ка не предусмотрено. Распаковщик сам конт- ролирует окончание экрана. подготовил А. Кодер
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября