Просмотр полной версии : Архиватор с самым быстрым распаковщиком
Alex Rider
16.09.2013, 17:15
Ткните, пожалуйста, носом где почитать про сравнение архиваторов в разрезе скорости распаковки. Пакую рыхлую графику, процент сжатия не так важен, как скорость распаковки. Подозреваю, что мне подойдет банальный RLE, но хочется почитать умные мысли на сей счет.
Если это спектрумовская графика, то хранить по столбцам, запаковать медноноговским пакером, распаковывать в буфер, потом перебрасывать кодом типа pop de:ld (hl),e:inc h:ld (hl),d:inc h.
Alex Rider, MegaLZ, BitBuster, ASCLzpak (он же медноноговский пакер)
Похоже, самый быстрый в распаковке был мой деархиватор, применявшийся в Great Codemasters Collection.
Alex Rider
16.09.2013, 18:51
Похоже, самый быстрый в распаковке был мой деархиватор, применявшийся в Great Codemasters Collection.
А где можно позырить на сырцы пакера и депакера?
Если это спектрумовская графика, то хранить по столбцам, запаковать медноноговским пакером, распаковывать в буфер, потом перебрасывать кодом типа pop de:ld (hl),e:inc h:ld (hl),d:inc h.
У меня графика - 20 знакомест в ширину, памяти хватает, поэтому читаю и пишу на экран стеком. Задача - распаковать картинку очень быстро. Непакаванная графика не лезет в память совсем на чуть-чуть.
[b]ASCLzpak (он же медноноговский пакер)
Здрассьте...
У меня графика - 20 знакомест в ширину, памяти хватает, поэтому читаю и пишу на экран стеком. Задача - распаковать картинку очень быстро. Непакаванная графика не лезет в память совсем на чуть-чуть.
Можешь попробовать мой BitPack.
Вырезалка спрайтов SPack из http://zxdocs.fatal.ru/myworks/bge_plugs.zip
Описание формата- http://zxdocs.fatal.ru/formats/formats.php?file=BIT&type=html
introspec
16.09.2013, 20:59
psndcj делал несколько лет назад сравнение нескольких популярных упаковщиков общего назначения (Hrust, MegaLZ, BitBlister): http://psndcj.blogspot.co.uk/2010/09/blog-post.html
Кроме упаковщиков, рассмотренных psndcj, я бы обратил ещё внимание на Exomizer и ZX7. По моему субъективному опыту, Exomizer, в среднем, обеспечивает самое большее сжатие из этих пяти компрессоров и при этом сопоставим по скорости. ZX7 основан на BitBlister и может рассматриваться как его улучшенная современная модификация.
По моему личному опыту, Hrust чаще всего проигрывает по сжатию и MegaLZ, и ZX7. ZX7 хорош для легко жмущихся данных, типа графики. LVD писал где-то, уже не вспомню сейчас где, что его данные лучше жмуться хрустом. На смешанных данных (графика+код) ZX7 чаще проигрывает MegaLZ (даже если принять во внимание длину распаковщика). ZX7 имеет один большой плюс: у него есть выбор из трёх декомпрессоров, самый маленький из которых занимает всего 69 байт, а самый большой оптимизирован на скорость распаковки.
Здрассьте...
Здрааасте. А что не так?
А где можно позырить на сырцы пакера и депакера?
Где-то исходники, конечно, лежат, но сходу не найдешь. А позырить можно в любой игре от Кодемастерс Коллекшн. Помню, что скорость распаковки практически сравнима с простым перебросом памяти через LDIR.
Помню, что скорость распаковки практически сравнима с простым перебросом памяти через LDIR.
да ну ладно...
Здрааасте. А что не так?
Судя по названию автор Андрей Сендецкий.
Alex Rider
17.09.2013, 10:54
А позырить можно в любой игре от Кодемастерс Коллекшн.
Думается мне, там только распаковщик :) Предлагаешь отреверсить и пакер по нему?
daniel, если не ошибаюсь Сендецкий делал свой пакер под Спек
А вот товарищ Медноногов писал свои творения на ПЦ, и паковал тамже. не?
кто по распаковщику имеет желание написать пакер?
Это не наши писали :)
;
; +-------------------------------------------------------------------------+
; | This file has been generated by The Interactive Disassembler (IDA) |
; | Copyright (c) 2011 Hex-Rays, <support@hex-rays.com> |
; | License info: 48-327F-7274-B7 |
; | ESET spol. s r.o. |
; +-------------------------------------------------------------------------+
;
; =============== S U B R O U T I N E =======================================
depack: ; CODE XREF: ROM:03DBp sub_1BAA+DAp ...
push de
jr dep_beg
; ---------------------------------------------------------------------------
dep_end: ; CODE XREF: depack+53j
pop bc
inc hl
ret
; ---------------------------------------------------------------------------
loc_7096: ; CODE XREF: depack+49j
ld b, a
loc_7097: ; CODE XREF: depack+4Dj
ld a, e
sub (hl)
inc hl
ld c, (hl)
push hl
ld l, a
ld a, d
sbc a, b
ld h, a
dec hl
ld a, c
ldi
ldi
ldi
ld c, a
ld b, 0
inc bc
jr loc_70CB
; ---------------------------------------------------------------------------
loc_70AE: ; CODE XREF: depack:loc_70DAj
ld b, a
and 0Fh
add a, 2
ld c, a
ld a, b
and 30h ; '0'
rlca
rlca
rlca
rlca
cpl
ld b, a
ld a, (hl)
push hl
cpl
add a, e
ld l, a
ld a, d
adc a, b
ld h, a
dec hl
loc_70C6: ; CODE XREF: depack+68j
ld b, 0
inc c
ldi
loc_70CB: ; CODE XREF: depack+21j
ldir
pop hl
inc hl
ex af, af'
jr dep_00
; ---------------------------------------------------------------------------
loc_70D2: ; CODE XREF: depack+A8j
cp 0Fh
jr nz, loc_7096
ld b, (hl)
inc hl
jr loc_7097
; ---------------------------------------------------------------------------
loc_70DC: ; CODE XREF: depack+9Bj
cp 0FFh
jr z, dep_end
and 60h ; '`'
rlca
rlca
rlca
inc a
ld c, a
ld a, (hl)
push hl
and 1Fh
add a, c
cpl
add a, e
ld l, a
ld a, d
adc a, 0FFh
ld h, a
jr loc_70C6
; ---------------------------------------------------------------------------
dep_000: ; CODE XREF: depack+93j
ldi
dep_beg: ; CODE XREF: depack+1j
scf
dep_02: ; CODE XREF: depack:dep_03j
ld a, (hl)
inc hl
adc a, a
jr c, dep_03
ldi
dep_00: ; CODE XREF: depack+45j depack+C5j ...
add a, a
jr c, dep_03
ldi
add a, a
jr c, dep_03
ldi
add a, a
jr c, dep_03
ldi
add a, a
jr c, dep_03
ldi
add a, a
jr c, dep_03
ldi
add a, a
jr c, dep_03
ldi
add a, a
jr nc, dep_000
dep_03: ; CODE XREF: depack+70j depack+75j ...
jr z, dep_02
ex af, af'
loc_7123: ; CODE XREF: depack:loc_719Fj
ld a, (hl)
;depack_code #80-#fe
cp 80h ; 'Ђ'
jr nc, loc_70DC
inc hl
sub 70h ; 'p'
jr nc, loc_715B
add a, 10h
jr c, loc_716F
add a, 10h
jr c, loc_70D2
add a, 30h ; '0'
jp c, loc_70AE
add a, 10h
jr nc, loc_7187
ld b, 0
sub 0Fh
jr z, loc_7152
add a, 11h
loc_7145: ; CODE XREF: depack+CBj depack+CEj
ld c, a
push hl
ld l, e
ld h, d
dec hl
ldir
pop hl
ex af, af'
jr dep_00
; ---------------------------------------------------------------------------
loc_7152: ; CODE XREF: depack+B6j
ld a, (hl)
inc hl
add a, 11h
jr nc, loc_7145
inc b
jr loc_7145
; ---------------------------------------------------------------------------
loc_715B: ; CODE XREF: depack+A0j
sub 0Fh
jr nz, loc_7161
ld a, (hl)
inc hl
loc_7161: ; CODE XREF: depack+D2j
add a, 11h
ld b, a
dec de
ld a, (de)
inc de
loc_7167: ; CODE XREF: depack+DFj
inc a
ld (de), a
inc de
djnz loc_7167
ex af, af'
jr dep_00
; ---------------------------------------------------------------------------
loc_716F: ; CODE XREF: depack+A4j
add a, 3
ld b, a
ld a, (hl)
push hl
cpl
scf
adc a, e
ld l, a
ld a, d
adc a, 0FFh
ld h, a
loc_717C: ; CODE XREF: depack+F5j
dec hl
ld a, (hl)
ld (de), a
inc de
djnz loc_717C
pop hl
inc hl
ex af, af'
jp dep_00
; ---------------------------------------------------------------------------
loc_7187: ; CODE XREF: depack+B0j
ld b, 0
inc a
jr z, loc_71A1
add a, 17h
ld c, a
loc_71AE: ; CODE XREF: depack+120j depack+134j ...
ldir
jr loc_7123
; ---------------------------------------------------------------------------
loc_71C9: ; CODE XREF: depack+119j
ld c, (hl)
inc hl
ld b, (hl)
inc hl
jr loc_71AE
loc_71A1: ; CODE XREF: depack+FFj
ld a, (hl)
inc hl
inc a
jr z, loc_71C9
add a, 1Dh
ld c, a
jr nc, loc_71AE
inc b
ldir
jp loc_7123
; ---------------------------------------------------------------------------
; End of function depack
Думается мне, там только распаковщик :) Предлагаешь отреверсить и пакер по нему?
Упаковщик есть в виде утилиты, и даже работает)
Alex Rider
17.09.2013, 17:05
Упаковщик есть в виде утилиты, и даже работает)
А поделишься? Распаковщик попробую выдрать сам если не найдется у тебя в закромах.
ZX7 основан на BitBlister и может рассматриваться как его улучшенная современная модификация.
Попробовал в работе ZX7, он проиграл по сжатию компрессору Pletter (который тоже сделан на основе Bitbuster).
introspec
18.09.2013, 00:12
Попробовал в работе ZX7, он проиграл по сжатию компрессору Pletter (который тоже сделан на основе Bitbuster).
Сильно проиграл? понятно ли, хотя бы примерно, на данных какого рода? Я не экспериментировал с Pletter, спасибо, посмотрю обязательно.
Лично у меня для ZX7 случается 2 вида применений: когда мне нужен очень компактный распаковщик, и когда мне нужен распаковщик, оптимизированный по скорости. Т.е. когда возникают различные доп. требования, помимо коэффициента сжатия.
Сильно проиграл? понятно ли, хотя бы примерно, на данный какого рода? Я не экспрериментировал с Pletter, спасибо, посмотрю обязательно.
Лично у меня для ZX7 случается 2 вида применений: когда мне нужен очень компактный распаковщик, и когда мне нужен распаковщик, оптимизированный по скорости. Т.е. когда возникают различные доп. требования, помимо коэффициента сжатия.
ZX7 на pt3 музыке проиграл сильно. На стандартной картинке немного. На коде ничья.
У pletter тоже компактный распаковщик, раз уж он из семейства bitbuster. По скорости не измерял...
Shadow Maker
18.09.2013, 02:01
daniel, если не ошибаюсь Сендецкий делал свой пакер под Спек
А вот товарищ Медноногов писал свои творения на ПЦ, и паковал тамже. не?
Ну вроде в сорцах, то ли к Уфо то ли к Ворону есть этот пакер, и работает нормально.
А поделишься? Распаковщик попробую выдрать сам если не найдется у тебя в закромах.
Вот нашел дискету с исходником, которой сам пользовался для запаковки.
Краткая аннотация:
Выбор файла курсор джойстиком (8, 9), упаковка - клавиша 'C'. Файл сам упакуется и запишется обратно на диск. Клавишу '0' не нажимать, она отмечает файлы, как файловом менеджере, но это не используется. Упаковщик достаточно быстрый, хотя работает алгоритмом 'в лоб', простым поиском одинаковых фрагментов без всяких деревьев и т.д. Зато очень сильно оптимизирован по скорости. При упаковке файл загружается в конец 48кб-памяти, а упакованный файл пишется с начала памяти. Если они встретятся на середине... то файл не упаковался) Иными словами, очень большие файлы, упаковать нельзя. И еще, даже в финальной версии упаковщика нашел один баг из-за которого иногда(!) самый последний байт упаковывался неправильно. Не было времени и/или усидчивости с этим разобраться, и просто напросто записывал один лишний байт в конец исходного файла, или же после распаковки проверял, если файл совпадает с исходным, значит упаковалось правильно.
Краткая история:
Летом 1995 года, когда Софтстар предложил сделать Great Codemasters Collection, я решил сделать из этого конфетку, и помимо восстановления и обработки всех игр, сделать еще очень быстрый, но эффектный распаковщик. Чтобы раз - и игра очень быстро загрузилась и мгновенно распаковалась, в противовес набирающим тогда моду медленным депакерам с нудной надписью 'decrunching, please wait...'. На это и делался упор. В итоге, по тому времени (а может и до сих пор) это был самый быстрый распаковщик, а качество сжатия не меньше, а может и чуть больше, чем у популярного тогда архиватора Сендецкого LZSS. Так же следует преобразовать графику по столбцам, что дает максимальное сжатие, что так же сделано было в Great Codemasters Collection.
Кому интересно, можете загрузить любую игру из этой коллекции и посмотреть, как быстро она распакоывается, хотя после загрузки сперва идет распаковка, потом преобразование ВСЕЙ графики в игре из столбцового типа в нативный для конкретной игры формат.
http://s002.radikal.ru/i199/1309/51/4e19deefee00.png
p.s.: Как пользоваться TASM'ом 3.0:
C - каталог
W - загрузка файла (PROBA18)
A - ассемблирование
E - редактирование
R - запуск
p.p.s.: Исходник депакера не нашел, может он есть внутри исходника пакера, не листал. Но, в любом случае, он масенький и может быть найдет в любой моей игре после лета 1995 года.
Да, декомпрессор есть внутри.
---------- Post added at 03:10 ---------- Previous post was at 03:07 ----------
Кстати, из декомпрессора можно совершенно безболезненно выкинуть одну команду, при этом он будет работать так же. Подсказал в свое время Ивамото. Кто найдет, тому респект)
p.p.s.: Исходник депакера не нашел, может он есть внутри исходника пакера, не листал. Но, в любом случае, он масенький и может быть найдет в любой моей игре после лета 1995 года.
Он всегда использовался отдельно или были прецеденты приклеивания в начало сжатого блока (типа hrust/hrum etc)?
Он всегда использовался отдельно или были прецеденты приклеивания в начало сжатого блока (типа hrust/hrum etc)?
В основном отдельно, т.к. блоков для распаковки обычно бывало много, зачем хранить несколько копий распаковщика. А так можно сперва интро распаковать, потом картинку, потом игру. И все одним распаковщиком.
Распаковщик есть в исходнике, как отдельный фрагмент, даже помечен, что вот это распаковщик.
Titus, а за счет чего распаковщик такой быстрый?
Результат оптимизации кода или данных?
Titus, а за счет чего распаковщик такой быстрый?
Результат оптимизации кода или данных?
Результат оптимизации как кода распаковщика, так и самого формата хранения данных, чтобы он был наиболее оптимален для быстрого извлечения из потока.
Т.е. сперва было прикинуто, что нужно два окна, длинное и короткое, размер которых, и длины копируемых фрагментов были бы оптимальны прежде всего для распаковщика, но при этом отвечали бы критериям хорошей упаковки данных.
А уже после распаковщика и утверждения формата данных был написан упаковщик.
M6:
and #c0
xor 2
просто на
and #c2?
M6:
and #c0
xor 2
просто на
and #c2?
А я не помню) Надо восстановить смысл декомпрессора, подписать комменты к исходнику, тогда станет понятно)
А можно и по другому - скомпилить, если на тестовых файлах, чем больше, тем лучше - пройдет, значит, возможно и да. :)
А можно и по другому - скомпилить, если на тестовых файлах, чем больше, тем лучше - пройдет, значит, возможно и да. :)
Это метод 'на авось', это не наши методы)
Titus, попробовал в эмуляторе запустить - работает только в режиме пятногона.Режим Скорпа и Феникса - вешает
Titus, попробовал в эмуляторе запустить - работает только в режиме пятногона.Режим Скорпа и Феникса - вешает
потому что OUT (FD),A
Согласен :) У меня не на авось. Я тут скачал, сделал поиск по "deco", и пробежался по первым командам rlca, jr c... их было три штуки, так что вроде 0,1,2 биты в А включены. Пора тестировать :)
потому что OUT (FD),A
Единственное из того, что надо было бы сделать и не сделано на плате Turbo+ , это возможность блокировки порта 1FFDh при обращении к другим системным портам по укороченному адресу FDh. Не будем здесь долго останавливаться на том, как правильно обращаться к порту, имеющему адрес 7FFDh, и как будут работать программы, использующие укороченную адресацию, на фирменных компьютерах ZX Spectrum +2, +2A, +3. Пусть это останется на совести тех наших программистов , которые экономят байты там, где в этом нет ни малейшей необходимости. Поскольку, на наш взгляд, от этого не должен страдать пользователь компьютера, то наряду с призывами к программистам использовать правильную адресацию, мы хотим порекомендовать тем, кто уже имеет Scorpion или еще только думает о его приобретении собрать одну из уже многочисленного количества опубликованных схем блокировки порта 1FFDh. Прежде всего, советуем обратиться к журналу ZX Format N1(Раздел “Железо”) Поскольку свободного места для расширений доработок и исследований на плате Scorpion Turbo+ оставлено предостаточно, то такого рода доработки при наличии подробной документации ( см.ниже) не составят труда для тех, кто пожелает их сделать.
:)
:)
Говорить сейчас можно все, что угодно. Но тогда коньюктура рынка была такова, что большинство тачек корректно работало с OUT (FD),A, кроме того, это давало при грамотном подходе значительную экономию и прирост быстродействия при использовании страниц.
Кроме того, этот пакер был вообще для внутреннего пользования.
А то, что делалось на релиз, там было всегда (если это возможно) 7FFD.
кроме того, это давало при грамотном подходе значительную экономию и прирост быстродействия
даешь холивар! а то скучновато:)
так мне менять в асме все out (FD) на out(7ffd) или в unreale есть галочка блокировать порт?
PS:сори за назойливость - очень хочется попробовать в деле пакер.
---------- Post added at 14:05 ---------- Previous post was at 14:03 ----------
даешь холивар! а то скучновато:)
обсуждалось тут http://zx-pk.ru/showthread.php?t=20766&highlight=%28%23FD%29%2Ca и еще в 100500+ темах
так мне менять в асме все out (FD) на out(7ffd) или в unreale есть галочка блокировать порт?
PS:сори за назойливость - очень хочется попробовать в деле пакер.
Я анрилом не пользуюсь. Но, думаю, если режим пентагона включить, то все будет окейно.
Titus, режим пятногона мне не приемлим.у меня нет реального пятногона и в эмулях этот режим не использую.моя задача дома запустить упаковщик на Фениксе реальном :)
Titus, режим пятногона мне не приемлим.у меня нет реального пятногона и в эмулях этот режим не использую.моя задача дома запустить упаковщик на Фениксе реальном :)
В компрессоре-то точно нельзя OUT (FD),A заменить на OUT (C),x, ибо регистровая пара BC явно используется активно, и поэтому и сделана адресация по FD. Один вариант - загнать феникс в режим совместимости с FD, если у него такой предусмотрен.
очень хочется попробовать в деле пакер
Прогнал на тесте сжатия ПЗУ ТР-доса (16384 байта) и сравнил с тестами других пакеров (не полный список, привел только те, что тестировались на этих же данных):
MEGALZ: 8849/8776 (110)
HRUM: 8928 (145)
PTC: 9625 (0)
TLZ: 9711 (67)
TLZP: 9750 (136)
LZH2: 9865 (85)
LZS: 9917 (131)
LZH1: 10211 (87)
ESV: 14262/14108/14018/14039/14130 (186)
PACK2: 11626 (56)
В скобках- размер депакера, через дробь- результат в разных режимах, если таковые имеются.
если у него такой предусмотрен.
а если нет - предусмотреть! :)
Один вариант - загнать феникс в режим совместимости с FD, если у него такой предусмотрен.
Можно еще делать OUT (#FD),A с установленным 6-м битом. Тогда будет работать на Скорпионе/Фениксе/Кае и не будет на Пентагоне 512.
Alex Rider
18.09.2013, 15:41
MEGALZ: 8849/8776 (110)
HRUM: 8928 (145)
PTC: 9625 (0)
TLZ: 9711 (67)
TLZP: 9750 (136)
LZH2: 9865 (85)
LZS: 9917 (131)
LZH1: 10211 (87)
ESV: 14262/14108/14018/14039/14130 (186)
PACK2: 11626 (56)
Что это за буквы? Я знаю тока MegaLZ и Hrum. Где из них титусовский?
---------- Post added at 15:41 ---------- Previous post was at 15:39 ----------
А, чорт. Выделен болдом.
Где из них титусовский?
PTC - Pro Turbo Cruncher (титусовский)
TLZ - TurboLZ
TLZP - TurboLZ for internal usage
у остальных название соответствует коду
Alex Rider
18.09.2013, 15:49
Еще бы узнать за сколько тактов каждый из депакеров этих пакеров теперь раскукожит ПЗУ обратно.
Интересно. Стал рассматривать депакер, и увидел там ниббловый метод декодирования, хотя совершенно не помню, чтобы я его оставлял в финальной версии. Скорее всего депакер, который в исходнике, это не финальный депакер, а чуть более ранний. Надо сравнить с тем, что в кодемастерс коллекшн.
Еще бы узнать за сколько тактов каждый из депакеров этих пакеров теперь раскукожит ПЗУ обратно.
Это уж сами. Сжатые блоки в соответствующих папочках находятся тут: https://code.google.com/p/zxtune/source/browse/#svn%2Ftrunk%2Fsrc%2Fformats%2Ftest
Alex Rider
18.09.2013, 16:02
Скорее всего депакер, который в исходнике, это не финальный депакер, а чуть более ранний. Надо сравнить с тем, что в кодемастерс коллекшн.
А он будет работать именно с этой версией пакера нормально?
А он будет работать именно с этой версией пакера нормально?
То, что я этой версией пакера жал свои программы - это точно, т.к. именно этой дискетой пользовался. Другое дело, что депакер мог потом урезать, и использовать более маленький. Надо сравнить.
---------- Post added at 16:42 ---------- Previous post was at 16:07 ----------
Согласен :) У меня не на авось. Я тут скачал, сделал поиск по "deco", и пробежался по первым командам rlca, jr c... их было три штуки, так что вроде 0,1,2 биты в А включены. Пора тестировать :)
Ответ верный)
---------- Post added at 16:44 ---------- Previous post was at 16:42 ----------
Пробежался по исходнику декомпрессора, и сделал комменты:
; Pro Turbo Cruncher v2.1
; Decompressor
; HL - Адрес начала упакованного фрагмента
OPUL: ; DE - Адрес для распаковки
LD A,(HL) ; A' = (HL) ; Взять первый байт из потока
EX AF,AF' ;
LD B,0 ; B = 0
LD IX,DECO ; IX = DECO ; Константа для быстрого перехода
CALL DECO-1 ; ==> DECO-1 ; В цикл депакера
EX AF,AF' ;
LD (DE),A ; (DE) = A' ; Сохранить последний байт
RET ; Выход
;--------------------------
M5:
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
JR C,M6 ; Если C = 1, то --> М6 ;
; Метод: LZ, смещение 0..8192, длина 0..255
LD A,(HL) ; A = (HL) ; Получить тот же байт из потока
AND #1F ; A = A and $1F ;
LD B,A ; B = A ; B = 0..31 (старший байт смещения)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LD C,(HL) ; C = (HL) ; Взять байт из потока (C - длина 0..255)
JR IYP ; --> IYP ; --> Копирование со смещением
M6:
; Метод: LZ, смещение 2048..3071, длина 3..10
AND #C0 ; A = A and 0xC0 ; Оставить старшие 2 бита
XOR 2 ; A = A + 2 ; Бит 1 равен 1
JR M7 ; --> M7 ; --> Подготовка копирования со смещением
LZMET:
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
JR C,M5 ; Если C = 1, то --> М5 ;
; Медод: LZ, смещение 0..2047, длина 3..10
AND #E0 ; A = A and 0xE0 ; Оставить в A старшие 3 бита
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
M7: RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
LD B,A ; B = A ; B - старший байт смещения (2 или 3 бита)
LD A,(HL) ; А = (HL) ; Получить тот же байт из потока
AND 7 ; A = A and 7 ; Оставить в A младшие 3 бита
ADD A,3 ; A = A + 3 ;
LD C,A ; C = A ; C - 3..10 (длина копируемого фрагмента)
IYP:
INC HL ; HL = HL + 1 ; Перейти к следующему байту
PUSH HL ; Сохранить HL
LD A,E ; A = E ; HL = DE - B.m(HL)
SUB (HL) ; A = A - (HL) ;
LD L,A ; L = A ;
LD A,D ; A = D ;
SBC A,B ; A = A - B - c ;
LD H,A ; H = A ;
LD B,0 ; B = 0 ;
DACO: LDIR ; (HL)->(DE), len BC ; Копирование фрагмента из (HL) в (DE)
POP HL ; Восстановить HL ;
; ; --> Вход
INC HL ; HL = HL + 1 ; Перейти к следующему байту
; Начало главного цикла
DECO: LD A,(HL) ; A = (HL) ; Взять байт из потока
RLCA ; C<-А-< ; Сдвинуть A влево, получить бит из потока
JR C,LZMET ; Если C = 1, то --> LZNET
RLCA ; C<-A-< ; Сдвинуть A влево на 2 бита, получить
RLCA ; C<-A-< ; два младших бита
AND 3 ; A = A and 3 ;
JR NZ,M1 ; Если A <> 0, то --> M1 ; Если A <> 0, то --> M1
; Метод: копирование блока длиной 1..32
LD C,(HL) ; C = (HL) ; Взять тот же байт из потока (длина фрагмента)
INC C ; C = C + 1 ; Коррекция длины 1..32
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LDIR ; (HL)->(DE), len BC ; Скопировать C байт из (HL) в (DE)
JP (IX) ; --> DECO ; в цикл --> DECO
M1:
DEC A ; A = A - 1 ; A - 0..2
JR NZ,M2 ; Если A <> 0, то --> M2 ; Если A <> 0, то --> M2
XOR (HL) ; A = (HL) ; Взять тот же байть из потока
AND #1F ; A = A and 0x1F ; Сбросить в A бит 5
RET Z ; Если A = 0, то выход --> ; Если A = 0, то конец распаковки -->
; Метод: ниббловое копирование длиной 1..31
LD B,A ; B = A ; B - счетчик (1..31)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LD C,(HL) ; C = (HL) ; Взять байт из потока (C - базовая константа)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
ML:
XOR A ; A = 0
RLD ; A <- (HL) <- 0 (нибблы) ; Получить ниббл из потока
ADD A,C ; A = A + C ; Сложить байт с базовой константой
LD (DE),A ; (DE) = A ; Записать байт
INC DE ; DE = DE + 1 ; Перейти к следующему байту
XOR A ; A = 0
RLD ; A <- (HL) <- 0 (нибблы) ; Получить ниббл из потока
ADD A,C ; A = A + C ; Сложить байт с базовой константой
LD (DE),A ; (DE) = A ; Записать байт
INC DE ; DE = DE + 1 ; Перейти к следующему байту
INC HL ; HL = HL + 1 ; Перейти к следующему байту
DJNZ ML ; Цикл на B итераций --> ML ;
JP (IX) ; --> DECO ; в цикл --> DECO
M2:
DEC A ; A = A - 2 ; A - 0..1
LD A,(HL) ; A = (HL) ; Взять байт из потока
JR Z,M4 ; Если A^ = 0, то --> M4 ; Если А^ = 0, то --> M3
AND #1F ; A = A and 0x1F ;
LD C,A ; C = A
INC C ; C = C + 1 ; C в диапазоне 1..32
M3: INC HL ; HL = HL + 1 ; Перейти к следующему байту
PUSH HL ; Сохранить HL
LD A,(HL) ; A = (HL) ; Взять байт из потока
LD H,D ; H = D
LD L,E ; L = E ; HL = адрес приемника
INC DE ; DE = DE + 1 ; DE = адрес приемника + 1
LD (HL),A ; (HL) = A ; Записать байт для заливки в (HL)
JR DACO ; --> DACO ; Заливка фрагмента
M4:
AND #1F ; A = A and #1F
LD B,A ; ; B в диапазоне 0..31 (B - старший байт длины)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LD C,(HL) ; C = (HL) ; Взять байт из потка (C - младший байт длины)
JR M3 ; --> M3 ; --> Заливка фрагмента
Alex Rider
18.09.2013, 16:49
Проинтегрил депакер Титуса в свой проект. Графику я не конвертил в столбцы, память позволяет, а лишние тормоза при конвертации/выводе не нужны совсем. В общем, мой результат по сравнению с megalz: сжатые файлы весят на 12% больше, скорость распаковки в 4-5 раз выше (действительно, сопоставимо с ldir).
Спасибо Titus'у огромное!
А зачем вообще сжимать? Несжатая картинка с карточки быстрее загрузится.
Alex Rider
18.09.2013, 17:25
А зачем вообще сжимать? Несжатая картинка с карточки быстрее загрузится.
Несжатые картинки не лезут в 128к.
Залез в Great Codemasters Collection, и действительно - ниббловый метод убран, т.к. видимо признан неэффективным, и занимал лишние байты в депакере. Фактически депакер ничем не отличается, только выкинут один фрагмент. Также соптимизировал то, что подсказал Ивамото. Итого, размер депакера 101 байт.
; Pro Turbo Cruncher v2.1
; Decompressor
;
; HL - Адрес начала упакованного фрагмента
; DE - Адрес для распаковки
OPUL:
LD A,(HL) ; A' = (HL) ; Взять первый байт из потока
EX AF,AF' ;
LD B,0 ; B = 0
LD IX,DECO ; IX = DECO ; Константа для быстрого перехода
CALL DECO-1 ; ==> DECO-1 ; В цикл депакера
EX AF,AF' ;
LD (DE),A ; (DE) = A' ; Сохранить последний байт
RET ; Выход
;--------------------------
M5:
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
JR C,M6 ; Если C = 1, то --> М6 ;
; Метод: LZ, смещение 0..8192, длина 0..255
LD A,(HL) ; A = (HL) ; Получить тот же байт из потока
AND #1F ; A = A and $1F ;
LD B,A ; B = A ; B = 0..31 (старший байт смещения)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LD C,(HL) ; C = (HL) ; Взять байт из потока (C - длина 0..255)
JR IYP ; --> IYP ; --> Копирование со смещением
M6:
; Метод: LZ, смещение 2048..3071, длина 3..10
AND #C2 ; A = A and 0xC2 ; Оставить старшие 2 бита
; Бит 1 равен 1
; Соптимизировано
; AND #C0 ; A = A and 0xC0 ; Оставить старшие 2 бита
; XOR 2 ; A = A + 2 ; Бит 1 равен 1
JR M7 ; --> M7 ; --> Подготовка копирования со смещением
LZMET:
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
JR C,M5 ; Если C = 1, то --> М5 ;
; Медод: LZ, смещение 0..2047, длина 3..10
AND #E0 ; A = A and 0xE0 ; Оставить в A старшие 3 бита
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
M7: RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
RLCA ; C<-A-< ; Сдвинуть A влево, получить бит из потока
LD B,A ; B = A ; B - старший байт смещения (2 или 3 бита)
LD A,(HL) ; А = (HL) ; Получить тот же байт из потока
AND 7 ; A = A and 7 ; Оставить в A младшие 3 бита
ADD A,3 ; A = A + 3 ;
LD C,A ; C = A ; C - 3..10 (длина копируемого фрагмента)
IYP:
INC HL ; HL = HL + 1 ; Перейти к следующему байту
PUSH HL ; Сохранить HL
LD A,E ; A = E ; HL = DE - B.m(HL)
SUB (HL) ; A = A - (HL) ;
LD L,A ; L = A ;
LD A,D ; A = D ;
SBC A,B ; A = A - B - c ;
LD H,A ; H = A ;
LD B,0 ; B = 0 ;
DACO: LDIR ; (HL)->(DE), len BC ; Копирование фрагмента из (HL) в (DE)
POP HL ; Восстановить HL ;
; ; --> Вход
INC HL ; HL = HL + 1 ; Перейти к следующему байту
; Начало главного цикла
DECO: LD A,(HL) ; A = (HL) ; Взять байт из потока
RLCA ; C<-А-< ; Сдвинуть A влево, получить бит из потока
JR C,LZMET ; Если C = 1, то --> LZNET
RLCA ; C<-A-< ; Сдвинуть A влево на 2 бита, получить
RLCA ; C<-A-< ; два младших бита
AND 3 ; A = A and 3 ;
JR NZ,M1 ; Если A <> 0, то --> M1 ; Если A <> 0, то --> M1
; Метод: копирование блока длиной 1..32
LD C,(HL) ; C = (HL) ; Взять тот же байт из потока (длина фрагмента)
INC C ; C = C + 1 ; Коррекция длины 1..32
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LDIR ; (HL)->(DE), len BC ; Скопировать C байт из (HL) в (DE)
JP (IX) ; --> DECO ; в цикл --> DECO
M1:
DEC A ; A = A - 1 ; A - 0..2
; С этого момента изменения
RET Z ; Если A = 0, то выход --> ; Если A = 0, то конец распаковки -->
; Конец изменений
M2:
DEC A ; A = A - 2 ; A - 0..1
LD A,(HL) ; A = (HL) ; Взять байт из потока
JR Z,M4 ; Если A^ = 0, то --> M4 ; Если А^ = 0, то --> M3
; Метод: Заливка 1..32
AND #1F ; A = A and 0x1F ;
LD C,A ; C = A
INC C ; C = C + 1 ; C в диапазоне 1..32
M3: INC HL ; HL = HL + 1 ; Перейти к следующему байту
PUSH HL ; Сохранить HL
LD A,(HL) ; A = (HL) ; Взять байт из потока
LD H,D ; H = D
LD L,E ; L = E ; HL = адрес приемника
INC DE ; DE = DE + 1 ; DE = адрес приемника + 1
LD (HL),A ; (HL) = A ; Записать байт для заливки в (HL)
JR DACO ; --> DACO ; Заливка фрагмента
M4:
; Метод: Заливка 1..8192
AND #1F ; A = A and #1F
LD B,A ; ; B в диапазоне 0..31 (B - старший байт длины)
INC HL ; HL = HL + 1 ; Перейти к следующему байту
LD C,(HL) ; C = (HL) ; Взять байт из потка (C - младший байт длины)
JR M3 ; --> M3 ; --> Заливка фрагмента
---------- Post added at 18:22 ---------- Previous post was at 18:18 ----------
Думаю, что можно и еще соптимизировать депакер по размеру, хотя особого смысла нет.
А если переписать пакер на Си, то можно добиться более хорошего сжатия при том же депакере. Да и большие файлы тоже можно сжимать. А также не бояться глюков последнего байта.
Проинтегрил депакер Титуса в свой проект.
замерь анрилом сколько тактов распаковывает?
Alex Rider
18.09.2013, 19:00
замерь анрилом сколько тактов распаковывает?
Нда, поторопился я с оценкой "сопоставимо с ldir"... Картинка размером 3200 байт распаковывается за ~128к тактов - в 2 раза медленнее ldir.
Нда, поторопился я с оценкой "сопоставимо с ldir"... Картинка размером 3200 байт распаковывается за ~128к тактов - в 2 раза медленнее ldir.
Все зависит от контента. Если сильно разбито на мелкие фрагменты, то может быть медленней, а если более крупные куски, то быстрее.
Прикинул примерно.
Метод копирования данных:
Экстракция заголовка, подготовка данных и переход в главный цикл - 65 тактов. Плюс собственно LDIR. Т.е. если копирование идет маленькими блоками по 3 байта, то тогда это будет в два раза медленнее LDIR.
ну даже в 2 раза медленнее - это неплохо. я ожидал еще хуже, на полпорядка хотя бы.
Alex Rider
18.09.2013, 20:23
Т.е. если копирование идет маленькими блоками по 3 байта, то тогда это будет в два раза медленнее LDIR.
Мои картинки и не репрезантативны для оценки алгоритма, потому как я не конвертил картинку в столбцы. В моем случае, если бы законвертил, может быть, было би и еще быстрее, но к этому "быстрее" надо было бы добавить время на обратную переконвертацию картинки, ибо стеком быстрее выводить строчки, чем столбцы.
shurik-ua
19.09.2013, 00:47
Не уверен насчёт правильности замены конструкции
and C0
xor 2
на
and c2
в первом варианте у нас гарантированно установлен 1-ый бит, во втором же случае такой уверенности нет.
P.S.и я бы XOR заменил на OR чтобы более наглядно было видно что нужно именно установить определённый бит, а не проинвертировать.
в первом варианте у нас гарантированно установлен 1-ый бит, во втором же случае такой уверенности нет.
P.S.и я бы XOR заменил на OR чтобы более наглядно было видно что нужно именно установить определённый бит, а не проинвертировать.
Первый бит установлен. Это будет понятно, если внимательно посмотреть исходник, и комментарии.
XOR ставился специально для запутывания)
XOR ставился специально для запутывания)
лол:) запутать одним лишь ксором? :)
лол:) запутать одним лишь ксором? :)
Конечно) Но не одним) Там их было два)
Просто мелкое запутывание между делом) Так, для развлечения, можно сказать)
Не исключено, что ниббловый метод - это как раз не устаревший метод, который я потом выкинул, а наоборот дополнительный метод, который написал в депакере, а в пакере еще не поддержал.
Суть этого метода, что, если на отрезке данных присутствует постоянная составляющая, вокруг которой колеблятся данные в диапазоне 0..15, то каждый такой байт кодируется всего 4 битами. В коде такое встретить сложно, а вот во всевозможных блоках данных, таблицах - вполне. Таким образом подобный участок данных сжимается сразу в два раза (плюс байт на константу постоянки), чем если б он был просто переброшен методом простого копирования.
Скорость распаковки этого метода вполне высока - 48.5 тактов на байт, что тоже лишь в 2.3 раза медленнее LDIR.
Для релиза Dizzy Extended Edition (https://zx-pk.ru/threads/32932-dizzy-1-48k-extended-version-2021.html) пришлось поднять исходники моего старого компрессора, обсуждаемого в этой ветке. Напомню, я его написал в 1995 году специально для Great Codemasters Collection. Цель тогда была добиться максимальной скорости распаковки и приемлемого качества упаковки.
Так как упаковщик был написан на Спектруме, и имел ограничения по длине упаковываемого файла (исходный плюс упакованный файлы не должны были превышать 48Кб), пришлось побыстрому набросать на Си упаковщик. При этом удалось улучшить качество упаковки, и даже немного оптимизировать распаковщик.
Выкладываю чисто для тестов, потому что вполне возможно, что упаковщик где-то сыроват, т.к. написан на скорую руку. Но для проверки упакованный файл внутри распаковывается и сравнивается с оригиналом. Если будет расхождение, то он напишет об ошибке. Исходный файл ограничен 64Кб (это естественно для Спектрума).
Использовать в консольном окне, скормив ему имя файла для упаковки.
С исторической точки зрения интересно, но если без скидок, то сейчас LZSA (https://github.com/emmanuel-marty/lzsa/releases)(1) чемпион в лиге быстрых распаковщиков (и он сжимает сильнее и есть более компактный распаковщик). У lzsa нет упаковщика для z80, возможно эта ниша для ProTurboCruncher.
С исторической точки зрения интересно, но если без скидок, то сейчас LZSA(1) чемпион в лиге быстрых распаковщиков
Есть ли пример кода с этим распаковщиком? По твоей ссылке есть исходник, но у меня не чем его скомпилировать.
lzsa_win32_1.3.6.zip и lzsa_win64_1.3.6.zip - это архивы с exeшниками
lzsa_win32_1.3.6.zip и lzsa_win64_1.3.6.zip - это архивы с exeшниками
Это я видел.
Мне нужен скомпилированный распаковщик под Z80. Ибо исходник в неудобоваримом виде, состоящем из многокомандных строк и макросов.
Мне нужен скомпилированный распаковщик под Z80
Под какой стартовый адрес?
Под какой стартовый адрес?
Любой выше 0x4000.
Бинарники (https://disk.yandex.ru/d/9oNmgAw19hshHA) (small и fast без unroll) со стартовым адресом 0F000h
Бинарники (small и fast без unroll) со стартовым адресом 0F000h
Бегло глянул. Вряд ли он быстрее распаковывает, чем мой. А по эффективности да, вполне может быть лучше.
- - - Добавлено - - -
Сравнил качество упаковки на нескольких файлах.
У LZSA на 1-3% лучше, чем у моего.
А по скорости распаковки, как я уже упоминал выше, вряд ли LZSA быстрее, а скорее всего медленнее. Но это все равно примерно один порядок скорости.
И надо не забывать, моему пакеру 25 лет)))
вряд ли LZSA быстрее
Быстрее, и small и тем более fast.
Быстрее, и small и тем более fast.
Посмотрел внимательно.
Да, очень хороший и быстрый декомпрессор, как по алгоритму, так и по реализации.
Вряд ли можно к нему что-то добавить или убавить.
Я правильно понял, что из-за того, что завершающая последовательность имеет большой размер (4 байта), исходный файл не может быть выровнен по верхнему адресу с распаковываемым?
Т.е. если я пакую область, допустим, 0x4000..0xFFFF, то я не смогу разместить упакованный файл с верхним адресом тоже 0xFFFF из-за этого?
исходный файл не может быть выровнен по верхнему адресу с распаковываемым?
Да, это вряд ли получится. С опцией -v lzsa печатает safe distance - минимальное расстояние от адреса распаковки до адреса начала упакованного файла. Надо бы проверить по исходнику, но похоже что SafeDistance=UnpackedLen-PackedLen+5, т.е. минимальное сближение в финале распаковки - 5 байт.
Если задача не полностью затереть упакованный файл, а распаковать с перекрытием до FFFF включительно, то можно упаковать с опцией -b и воспользоваться обратными распаковщиками.
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot