PDA

Просмотр полной версии : Архиватор с самым быстрым распаковщиком



Alex Rider
16.09.2013, 17:15
Ткните, пожалуйста, носом где почитать про сравнение архиваторов в разрезе скорости распаковки. Пакую рыхлую графику, процент сжатия не так важен, как скорость распаковки. Подозреваю, что мне подойдет банальный RLE, но хочется почитать умные мысли на сей счет.

alone
16.09.2013, 17:38
Если это спектрумовская графика, то хранить по столбцам, запаковать медноноговским пакером, распаковывать в буфер, потом перебрасывать кодом типа pop de:ld (hl),e:inc h:ld (hl),d:inc h.

jerri
16.09.2013, 17:39
Alex Rider, MegaLZ, BitBuster, ASCLzpak (он же медноноговский пакер)

Titus
16.09.2013, 17:49
Похоже, самый быстрый в распаковке был мой деархиватор, применявшийся в 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 знакомест в ширину, памяти хватает, поэтому читаю и пишу на экран стеком. Задача - распаковать картинку очень быстро. Непакаванная графика не лезет в память совсем на чуть-чуть.

Wlodek
16.09.2013, 18:51
[b]ASCLzpak (он же медноноговский пакер)

Здрассьте...

Vitamin
16.09.2013, 19:11
У меня графика - 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 байт, а самый большой оптимизирован на скорость распаковки.

jerri
16.09.2013, 21:10
Здрассьте...

Здрааасте. А что не так?

Titus
17.09.2013, 01:35
А где можно позырить на сырцы пакера и депакера?

Где-то исходники, конечно, лежат, но сходу не найдешь. А позырить можно в любой игре от Кодемастерс Коллекшн. Помню, что скорость распаковки практически сравнима с простым перебросом памяти через LDIR.

psb
17.09.2013, 03:33
Помню, что скорость распаковки практически сравнима с простым перебросом памяти через LDIR.
да ну ладно...

daniel
17.09.2013, 06:31
Здрааасте. А что не так?
Судя по названию автор Андрей Сендецкий.

Alex Rider
17.09.2013, 10:54
А позырить можно в любой игре от Кодемастерс Коллекшн.
Думается мне, там только распаковщик :) Предлагаешь отреверсить и пакер по нему?

jerri
17.09.2013, 11:01
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

Titus
17.09.2013, 11:48
Думается мне, там только распаковщик :) Предлагаешь отреверсить и пакер по нему?

Упаковщик есть в виде утилиты, и даже работает)

Alex Rider
17.09.2013, 17:05
Упаковщик есть в виде утилиты, и даже работает)
А поделишься? Распаковщик попробую выдрать сам если не найдется у тебя в закромах.

tiboh
18.09.2013, 00:05
ZX7 основан на BitBlister и может рассматриваться как его улучшенная современная модификация.


Попробовал в работе ZX7, он проиграл по сжатию компрессору Pletter (который тоже сделан на основе Bitbuster).

introspec
18.09.2013, 00:12
Попробовал в работе ZX7, он проиграл по сжатию компрессору Pletter (который тоже сделан на основе Bitbuster).
Сильно проиграл? понятно ли, хотя бы примерно, на данных какого рода? Я не экспериментировал с Pletter, спасибо, посмотрю обязательно.

Лично у меня для ZX7 случается 2 вида применений: когда мне нужен очень компактный распаковщик, и когда мне нужен распаковщик, оптимизированный по скорости. Т.е. когда возникают различные доп. требования, помимо коэффициента сжатия.

tiboh
18.09.2013, 00:22
Сильно проиграл? понятно ли, хотя бы примерно, на данный какого рода? Я не экспрериментировал с Pletter, спасибо, посмотрю обязательно.

Лично у меня для ZX7 случается 2 вида применений: когда мне нужен очень компактный распаковщик, и когда мне нужен распаковщик, оптимизированный по скорости. Т.е. когда возникают различные доп. требования, помимо коэффициента сжатия.

ZX7 на pt3 музыке проиграл сильно. На стандартной картинке немного. На коде ничья.
У pletter тоже компактный распаковщик, раз уж он из семейства bitbuster. По скорости не измерял...

Shadow Maker
18.09.2013, 02:01
daniel, если не ошибаюсь Сендецкий делал свой пакер под Спек
А вот товарищ Медноногов писал свои творения на ПЦ, и паковал тамже. не?
Ну вроде в сорцах, то ли к Уфо то ли к Ворону есть этот пакер, и работает нормально.

Titus
18.09.2013, 03:04
А поделишься? Распаковщик попробую выдрать сам если не найдется у тебя в закромах.

Вот нашел дискету с исходником, которой сам пользовался для запаковки.

Краткая аннотация:
Выбор файла курсор джойстиком (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 года.

Titus
18.09.2013, 03:10
Да, декомпрессор есть внутри.

---------- Post added at 03:10 ---------- Previous post was at 03:07 ----------

Кстати, из декомпрессора можно совершенно безболезненно выкинуть одну команду, при этом он будет работать так же. Подсказал в свое время Ивамото. Кто найдет, тому респект)

Vitamin
18.09.2013, 13:43
p.p.s.: Исходник депакера не нашел, может он есть внутри исходника пакера, не листал. Но, в любом случае, он масенький и может быть найдет в любой моей игре после лета 1995 года.
Он всегда использовался отдельно или были прецеденты приклеивания в начало сжатого блока (типа hrust/hrum etc)?

Titus
18.09.2013, 13:53
Он всегда использовался отдельно или были прецеденты приклеивания в начало сжатого блока (типа hrust/hrum etc)?
В основном отдельно, т.к. блоков для распаковки обычно бывало много, зачем хранить несколько копий распаковщика. А так можно сперва интро распаковать, потом картинку, потом игру. И все одним распаковщиком.

Распаковщик есть в исходнике, как отдельный фрагмент, даже помечен, что вот это распаковщик.

newart
18.09.2013, 13:57
Titus, а за счет чего распаковщик такой быстрый?

Результат оптимизации кода или данных?

Titus
18.09.2013, 14:14
Titus, а за счет чего распаковщик такой быстрый?

Результат оптимизации кода или данных?

Результат оптимизации как кода распаковщика, так и самого формата хранения данных, чтобы он был наиболее оптимален для быстрого извлечения из потока.

Т.е. сперва было прикинуто, что нужно два окна, длинное и короткое, размер которых, и длины копируемых фрагментов были бы оптимальны прежде всего для распаковщика, но при этом отвечали бы критериям хорошей упаковки данных.

А уже после распаковщика и утверждения формата данных был написан упаковщик.

Hrumer
18.09.2013, 14:33
M6:
and #c0
xor 2
просто на
and #c2?

Titus
18.09.2013, 14:37
M6:
and #c0
xor 2
просто на
and #c2?

А я не помню) Надо восстановить смысл декомпрессора, подписать комменты к исходнику, тогда станет понятно)

Hrumer
18.09.2013, 14:41
А можно и по другому - скомпилить, если на тестовых файлах, чем больше, тем лучше - пройдет, значит, возможно и да. :)

Titus
18.09.2013, 14:41
А можно и по другому - скомпилить, если на тестовых файлах, чем больше, тем лучше - пройдет, значит, возможно и да. :)
Это метод 'на авось', это не наши методы)

palsw
18.09.2013, 14:42
Titus, попробовал в эмуляторе запустить - работает только в режиме пятногона.Режим Скорпа и Феникса - вешает

Titus
18.09.2013, 14:45
Titus, попробовал в эмуляторе запустить - работает только в режиме пятногона.Режим Скорпа и Феникса - вешает

потому что OUT (FD),A

Hrumer
18.09.2013, 14:46
Согласен :) У меня не на авось. Я тут скачал, сделал поиск по "deco", и пробежался по первым командам rlca, jr c... их было три штуки, так что вроде 0,1,2 биты в А включены. Пора тестировать :)

palsw
18.09.2013, 14:52
потому что OUT (FD),A


Единственное из того, что надо было бы сделать и не сделано на плате Turbo+ , это возможность блокировки порта 1FFDh при обращении к другим системным портам по укороченному адресу FDh. Не будем здесь долго останавливаться на том, как правильно обращаться к порту, имеющему адрес 7FFDh, и как будут работать программы, использующие укороченную адресацию, на фирменных компьютерах ZX Spectrum +2, +2A, +3. Пусть это останется на совести тех наших программистов , которые экономят байты там, где в этом нет ни малейшей необходимости. Поскольку, на наш взгляд, от этого не должен страдать пользователь компьютера, то наряду с призывами к программистам использовать правильную адресацию, мы хотим порекомендовать тем, кто уже имеет Scorpion или еще только думает о его приобретении собрать одну из уже многочисленного количества опубликованных схем блокировки порта 1FFDh. Прежде всего, советуем обратиться к журналу ZX Format N1(Раздел “Железо”) Поскольку свободного места для расширений доработок и исследований на плате Scorpion Turbo+ оставлено предостаточно, то такого рода доработки при наличии подробной документации ( см.ниже) не составят труда для тех, кто пожелает их сделать.



:)

Titus
18.09.2013, 14:55
:)
Говорить сейчас можно все, что угодно. Но тогда коньюктура рынка была такова, что большинство тачек корректно работало с OUT (FD),A, кроме того, это давало при грамотном подходе значительную экономию и прирост быстродействия при использовании страниц.

Кроме того, этот пакер был вообще для внутреннего пользования.
А то, что делалось на релиз, там было всегда (если это возможно) 7FFD.

psb
18.09.2013, 14:56
кроме того, это давало при грамотном подходе значительную экономию и прирост быстродействия
даешь холивар! а то скучновато:)

palsw
18.09.2013, 15:05
так мне менять в асме все 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+ темах

Titus
18.09.2013, 15:06
так мне менять в асме все out (FD) на out(7ffd) или в unreale есть галочка блокировать порт?

PS:сори за назойливость - очень хочется попробовать в деле пакер.

Я анрилом не пользуюсь. Но, думаю, если режим пентагона включить, то все будет окейно.

palsw
18.09.2013, 15:12
Titus, режим пятногона мне не приемлим.у меня нет реального пятногона и в эмулях этот режим не использую.моя задача дома запустить упаковщик на Фениксе реальном :)

Titus
18.09.2013, 15:18
Titus, режим пятногона мне не приемлим.у меня нет реального пятногона и в эмулях этот режим не использую.моя задача дома запустить упаковщик на Фениксе реальном :)

В компрессоре-то точно нельзя OUT (FD),A заменить на OUT (C),x, ибо регистровая пара BC явно используется активно, и поэтому и сделана адресация по FD. Один вариант - загнать феникс в режим совместимости с FD, если у него такой предусмотрен.

Vitamin
18.09.2013, 15:28
очень хочется попробовать в деле пакер

Прогнал на тесте сжатия ПЗУ ТР-доса (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)

В скобках- размер депакера, через дробь- результат в разных режимах, если таковые имеются.

psb
18.09.2013, 15:31
если у него такой предусмотрен.
а если нет - предусмотреть! :)

Blade
18.09.2013, 15:33
Один вариант - загнать феникс в режим совместимости с 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 ----------

А, чорт. Выделен болдом.

Vitamin
18.09.2013, 15:41
Где из них титусовский?
PTC - Pro Turbo Cruncher (титусовский)
TLZ - TurboLZ
TLZP - TurboLZ for internal usage

у остальных название соответствует коду

Alex Rider
18.09.2013, 15:49
Еще бы узнать за сколько тактов каждый из депакеров этих пакеров теперь раскукожит ПЗУ обратно.

Titus
18.09.2013, 15:56
Интересно. Стал рассматривать депакер, и увидел там ниббловый метод декодирования, хотя совершенно не помню, чтобы я его оставлял в финальной версии. Скорее всего депакер, который в исходнике, это не финальный депакер, а чуть более ранний. Надо сравнить с тем, что в кодемастерс коллекшн.

Vitamin
18.09.2013, 15:57
Еще бы узнать за сколько тактов каждый из депакеров этих пакеров теперь раскукожит ПЗУ обратно.
Это уж сами. Сжатые блоки в соответствующих папочках находятся тут: https://code.google.com/p/zxtune/source/browse/#svn%2Ftrunk%2Fsrc%2Fformats%2Ftest

Alex Rider
18.09.2013, 16:02
Скорее всего депакер, который в исходнике, это не финальный депакер, а чуть более ранний. Надо сравнить с тем, что в кодемастерс коллекшн.
А он будет работать именно с этой версией пакера нормально?

Titus
18.09.2013, 16:44
А он будет работать именно с этой версией пакера нормально?

То, что я этой версией пакера жал свои программы - это точно, т.к. именно этой дискетой пользовался. Другое дело, что депакер мог потом урезать, и использовать более маленький. Надо сравнить.

---------- 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'у огромное!

Blade
18.09.2013, 16:57
А зачем вообще сжимать? Несжатая картинка с карточки быстрее загрузится.

Alex Rider
18.09.2013, 17:25
А зачем вообще сжимать? Несжатая картинка с карточки быстрее загрузится.
Несжатые картинки не лезут в 128к.

Titus
18.09.2013, 18:22
Залез в 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 ----------

Думаю, что можно и еще соптимизировать депакер по размеру, хотя особого смысла нет.
А если переписать пакер на Си, то можно добиться более хорошего сжатия при том же депакере. Да и большие файлы тоже можно сжимать. А также не бояться глюков последнего байта.

psb
18.09.2013, 18:37
Проинтегрил депакер Титуса в свой проект.
замерь анрилом сколько тактов распаковывает?

Alex Rider
18.09.2013, 19:00
замерь анрилом сколько тактов распаковывает?
Нда, поторопился я с оценкой "сопоставимо с ldir"... Картинка размером 3200 байт распаковывается за ~128к тактов - в 2 раза медленнее ldir.

Titus
18.09.2013, 19:05
Нда, поторопился я с оценкой "сопоставимо с ldir"... Картинка размером 3200 байт распаковывается за ~128к тактов - в 2 раза медленнее ldir.

Все зависит от контента. Если сильно разбито на мелкие фрагменты, то может быть медленней, а если более крупные куски, то быстрее.

Прикинул примерно.
Метод копирования данных:
Экстракция заголовка, подготовка данных и переход в главный цикл - 65 тактов. Плюс собственно LDIR. Т.е. если копирование идет маленькими блоками по 3 байта, то тогда это будет в два раза медленнее LDIR.

psb
18.09.2013, 19:19
ну даже в 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 чтобы более наглядно было видно что нужно именно установить определённый бит, а не проинвертировать.

Titus
19.09.2013, 01:15
в первом варианте у нас гарантированно установлен 1-ый бит, во втором же случае такой уверенности нет.

P.S.и я бы XOR заменил на OR чтобы более наглядно было видно что нужно именно установить определённый бит, а не проинвертировать.

Первый бит установлен. Это будет понятно, если внимательно посмотреть исходник, и комментарии.

XOR ставился специально для запутывания)

psb
19.09.2013, 02:33
XOR ставился специально для запутывания)
лол:) запутать одним лишь ксором? :)

Titus
19.09.2013, 06:47
лол:) запутать одним лишь ксором? :)
Конечно) Но не одним) Там их было два)

Просто мелкое запутывание между делом) Так, для развлечения, можно сказать)

Titus
19.09.2013, 11:44
Не исключено, что ниббловый метод - это как раз не устаревший метод, который я потом выкинул, а наоборот дополнительный метод, который написал в депакере, а в пакере еще не поддержал.

Суть этого метода, что, если на отрезке данных присутствует постоянная составляющая, вокруг которой колеблятся данные в диапазоне 0..15, то каждый такой байт кодируется всего 4 битами. В коде такое встретить сложно, а вот во всевозможных блоках данных, таблицах - вполне. Таким образом подобный участок данных сжимается сразу в два раза (плюс байт на константу постоянки), чем если б он был просто переброшен методом простого копирования.

Скорость распаковки этого метода вполне высока - 48.5 тактов на байт, что тоже лишь в 2.3 раза медленнее LDIR.

Titus
24.02.2021, 05:04
Для релиза Dizzy Extended Edition (https://zx-pk.ru/threads/32932-dizzy-1-48k-extended-version-2021.html) пришлось поднять исходники моего старого компрессора, обсуждаемого в этой ветке. Напомню, я его написал в 1995 году специально для Great Codemasters Collection. Цель тогда была добиться максимальной скорости распаковки и приемлемого качества упаковки.

Так как упаковщик был написан на Спектруме, и имел ограничения по длине упаковываемого файла (исходный плюс упакованный файлы не должны были превышать 48Кб), пришлось побыстрому набросать на Си упаковщик. При этом удалось улучшить качество упаковки, и даже немного оптимизировать распаковщик.

Выкладываю чисто для тестов, потому что вполне возможно, что упаковщик где-то сыроват, т.к. написан на скорую руку. Но для проверки упакованный файл внутри распаковывается и сравнивается с оригиналом. Если будет расхождение, то он напишет об ошибке. Исходный файл ограничен 64Кб (это естественно для Спектрума).
Использовать в консольном окне, скормив ему имя файла для упаковки.

ivagor
24.02.2021, 17:05
С исторической точки зрения интересно, но если без скидок, то сейчас LZSA (https://github.com/emmanuel-marty/lzsa/releases)(1) чемпион в лиге быстрых распаковщиков (и он сжимает сильнее и есть более компактный распаковщик). У lzsa нет упаковщика для z80, возможно эта ниша для ProTurboCruncher.

Titus
24.02.2021, 17:12
С исторической точки зрения интересно, но если без скидок, то сейчас LZSA(1) чемпион в лиге быстрых распаковщиков
Есть ли пример кода с этим распаковщиком? По твоей ссылке есть исходник, но у меня не чем его скомпилировать.

ivagor
24.02.2021, 18:01
lzsa_win32_1.3.6.zip и lzsa_win64_1.3.6.zip - это архивы с exeшниками

Titus
24.02.2021, 18:48
lzsa_win32_1.3.6.zip и lzsa_win64_1.3.6.zip - это архивы с exeшниками
Это я видел.
Мне нужен скомпилированный распаковщик под Z80. Ибо исходник в неудобоваримом виде, состоящем из многокомандных строк и макросов.

ivagor
24.02.2021, 20:02
Мне нужен скомпилированный распаковщик под Z80
Под какой стартовый адрес?

Titus
24.02.2021, 22:01
Под какой стартовый адрес?

Любой выше 0x4000.

ivagor
24.02.2021, 22:31
Бинарники (https://disk.yandex.ru/d/9oNmgAw19hshHA) (small и fast без unroll) со стартовым адресом 0F000h

Titus
25.02.2021, 00:28
Бинарники (small и fast без unroll) со стартовым адресом 0F000h
Бегло глянул. Вряд ли он быстрее распаковывает, чем мой. А по эффективности да, вполне может быть лучше.

- - - Добавлено - - -

Сравнил качество упаковки на нескольких файлах.
У LZSA на 1-3% лучше, чем у моего.
А по скорости распаковки, как я уже упоминал выше, вряд ли LZSA быстрее, а скорее всего медленнее. Но это все равно примерно один порядок скорости.

И надо не забывать, моему пакеру 25 лет)))

ivagor
25.02.2021, 07:04
вряд ли LZSA быстрее
Быстрее, и small и тем более fast.

Titus
26.02.2021, 04:06
Быстрее, и small и тем более fast.

Посмотрел внимательно.
Да, очень хороший и быстрый декомпрессор, как по алгоритму, так и по реализации.
Вряд ли можно к нему что-то добавить или убавить.

Я правильно понял, что из-за того, что завершающая последовательность имеет большой размер (4 байта), исходный файл не может быть выровнен по верхнему адресу с распаковываемым?
Т.е. если я пакую область, допустим, 0x4000..0xFFFF, то я не смогу разместить упакованный файл с верхним адресом тоже 0xFFFF из-за этого?

ivagor
26.02.2021, 06:29
исходный файл не может быть выровнен по верхнему адресу с распаковываемым?
Да, это вряд ли получится. С опцией -v lzsa печатает safe distance - минимальное расстояние от адреса распаковки до адреса начала упакованного файла. Надо бы проверить по исходнику, но похоже что SafeDistance=UnpackedLen-PackedLen+5, т.е. минимальное сближение в финале распаковки - 5 байт.

ivagor
26.02.2021, 10:26
Если задача не полностью затереть упакованный файл, а распаковать с перекрытием до FFFF включительно, то можно упаковать с опцией -b и воспользоваться обратными распаковщиками.