PDA

Просмотр полной версии : Упаковщики



grf
03.08.2021, 11:21
Какие есть упаковщики графики и кода для БК, кроме KOMP2?

gid
03.08.2021, 13:10
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.

grf
03.08.2021, 13:47
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.

Спасибо, попробую найти и заюзать)

Manwe
03.08.2021, 15:10
Какие есть упаковщики графики и кода для БК, кроме KOMP2?Советую LZSA (https://github.com/ivagorRetrocomp/DeLZSA/tree/main/PDP11)

grf
03.08.2021, 15:51
Советую LZSA (https://github.com/ivagorRetrocomp/DeLZSA/tree/main/PDP11)

Спасибо! Но это только распаковщик. Упаковывать предполагается на PC?

jerri
03.08.2021, 18:20
Спасибо! Но это только распаковщик. Упаковывать предполагается на PC?

а в чем проблема - это же удобно.

могу предложить еще вот такой упаковщик. zx0 (https://github.com/einar-saukas/ZX0)

распаковщик есть и под PDP11

reddie
03.08.2021, 18:25
распаковщик правда под z80
но переписать как мне кажется трудностей не составит
Интересующимся могу предложить глянуть Спектрумовские жамкалки скринов и данных, работали неплохо.
Для данных вообще была прога, создающая sfx-архивы - Hrust. Упаковщик картинок, по памяти - ASC Screen Crasher.
В свое время Писишники переделывали Hrust/Dehrust для распаковки интрух, настолько мало он весил =)

Manwe
03.08.2021, 19:29
распаковщик есть и под PDP11
75927
Исходники распаковщиков LZSA1, LZSA2, ZX0, ZX1 для БК0010

grf
04.08.2021, 15:58
BKPACK дал хорошие результаты, буду юзать его )

jerri
04.08.2021, 20:28
BKPACK дал хорошие результаты, буду юзать его )

насколько хорошо жмет?
https://introspec.retroscene.org/compression/pareto_20210128.png
лучше чем Shrinker?

grf
05.08.2021, 06:21
Файлы заставок, которые мне нужно сжать, жмет в среднем в два раза:

hallblnk было 40000, стало 22053
mainhall 40000 -> 23502
titr1 40000 -> 15004
titr2 40000 -> 14631
titr3 40000 -> 14573
titr4 40000 -> 12642
tmaincl 40000 -> 30615

Для пробы сжал код:
main.exe 36724 -> 27223

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

reddie
05.08.2021, 08:52
Файлы заставок, которые мне нужно сжать
а можно сюда их выложить? поковыряюсь на досуге с переделкой спектрумовского.
Для сравнения результатов, чтоб было понятней, кто как жмет.

grf
05.08.2021, 11:05
а можно сюда их выложить? поковыряюсь на досуге с переделкой спектрумовского.
Для сравнения результатов, чтоб было понятней, кто как жмет.

https://cloud.mail.ru/public/5NuJ/UDEP6T154

ivagor
05.08.2021, 11:13
ZX0
TITR1.PIC - 3890dec байт=7462oct байта
TITR2.PIC - 3784dec байт=7310oct байт
+распаковщик 102dec=146oct байт

Manwe
05.08.2021, 20:49
в PONG Charged (https://r-games.net/bk001x/games/48297-pong-charged.html) я использовал LZSA2 и очень доволен

ivagor
05.08.2021, 21:19
LZSA2
Если распаковщик мой, то вариант для pdp11 был совсем неудачный, даже не стал его выкладывать на github. Но и при наличии более эффективного распаковщика актуальность lzsa2 после появления zx0/1 сильно уменьшилась. lzsa1 - быстрый; zx0 - сильно сжимает; zx2 - компактный распаковщик; zx1 - степень сжатия немного уступает zx1, зато скорость почти как у lzsa2, а в варианте для pdp11 даже быстрее, что правда больше говорит о недоработанности того распаковщика lzsa2.

Manwe
05.08.2021, 21:38
zx1 - степень сжатия немного уступает zx1Вот этого я не понял :)
zx0 я попробовал, но он не сильней чем lzsa2 сжал.

grf
06.08.2021, 01:49
в PONG Charged (https://r-games.net/bk001x/games/48297-pong-charged.html) я использовал LZSA2 и очень доволен

Мне вполне хватит BKPACK, тем более он полностью БКшный - и упаковщик и распаковщик :)

ivagor
06.08.2021, 07:03
Вот этого я не понял
Пардон, "zx1 - степень сжатия немного уступает zx0".

zx0 я попробовал, но он не сильней чем lzsa2 сжал.
Для редких отдельных файлов это возможно (кстати, пока не находил примеров таких файлов, можно куда-нибудь выложить тот самый?), но в среднем по больнице он заметно опережает.

grf
06.08.2021, 08:39
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.

Распаковщик BKPACK существует в версии, которая пригодна к многократной распаковке архива и не портит сама себя?

Manwe
06.08.2021, 08:56
Если распаковщик мой, то вариант для pdp11 был совсем неудачный, даже не стал его выкладывать на github.Не подскажешь как в LZSA2 это устроено? Read a nibble... then read a byte. После чтения токена (байта) нужно прочитать ниббл (4 бита), а потом байт. Получается, этот байт сдвинут на 4 бита? То есть расположение данных в памяти выглядит так (побитно, где | означает границы байтов в памяти)?

| tokenmmm | niblbyte | byte.... |
^^^^ ^^^^

Sandro
06.08.2021, 09:06
Распаковщик BKPACK существует в версии, которая пригодна к многократной распаковке архива и не портит сама себя?

Насколько я помню, он вообще ничего в себе не изменяет, поэтому можно хранить в памяти кучу данных и распаковывать им по мере надобности. Благо алгоритм неожиданно удачный. Он близок по степени сжатия к ZIP/DEFLATE, и при этом вообще не использует побитовой упаковки!

ivagor
06.08.2021, 09:42
близок по степени сжатия к ZIP/DEFLATE
Спорное утверждение, например TITR1.PIC и TITR2.PIC zip/deflate сжал в полтора раза лучше, чем bkpack.

как в LZSA2 это устроено
Про формат lzsa2 я вряд ли напишу лучше автора, но если ограничиться нибблами, то можно сказать, что есть как бы параллельный поток нибблов (это как поток битов во многих других упаковщиках), перемежающийся с потоком байтов. Если нужен ниббл, то мы проверяем текущее состояние "буфера нибблов", и
1. если там пусто, читаем следующий байт, берем оттуда один ниббл, а второй - в буфер нибблов.
2. если там не пусто, берем ниббл и помечаем, что "буффер нибблов" пуст.

Manwe
06.08.2021, 09:54
Про формат lzsa2 я вряд ли напишу лучше автора, но если ограничиться нибблами, то можно сказать, что есть как бы параллельный поток нибблов (это как поток битов во многих других упаковщиках), перемежающийся с потоком байтов. Если нужен ниббл, то мы проверяем текущее состояние "буфера нибблов", и
1. если там пусто, читаем следующий байт, берем оттуда один ниббл, а второй - в буфер нибблов.
2. если там не пусто, берем ниббл и помечаем, что "буффер нибблов" пуст.То есть нибблы всегда хранятся парами, чтобы занимать ровно байт?

P.S. мне кажется, обсуждение распаковки - НЕ оффтопик в теме про упаковку, так что можно не прятать обсуждение в спойлер.

ivagor
06.08.2021, 10:13
То есть нибблы всегда хранятся парами, чтобы занимать ровно байт?
да

grf
06.08.2021, 10:16
Насколько я помню, он вообще ничего в себе не изменяет, поэтому можно хранить в памяти кучу данных и распаковывать им по мере надобности. Благо алгоритм неожиданно удачный. Он близок по степени сжатия к ZIP/DEFLATE, и при этом вообще не использует побитовой упаковки!

Распаковщик изначально выглядит так:
75933

Он пересылает часть кода в назначенную рабочую область, потом делает JMP на начало этого кода, и первым делом затирает свое начало, пересылая туда 572 байта из конца архива:

75934

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

jerri
06.08.2021, 11:01
Таким образом, повторный запуск уже не имеет смысла, потому что там нет изначального кода.

можно было бы использовать 1 распаковщик на все файлы.
Но нет так нет.

Sandro
06.08.2021, 12:59
Распаковщик изначально выглядит так:
Таким образом, повторный запуск уже не имеет смысла, потому что там нет изначального кода.

Но сам же себя он не ломает? Что мешает эту пересылку отрезать? Она нужна только для того, чтобы можно было запускать программу со стандартного адреса 1000, и одновременно там в начале был бы распаковщик. если этого требования нет, то и так фокусничать не надо.

grf
06.08.2021, 13:07
Но сам же себя он не ломает? Что мешает эту пересылку отрезать? Она нужна только для того, чтобы можно было запускать программу со стандартного адреса 1000, и одновременно там в начале был бы распаковщик. если этого требования нет, то и так фокусничать не надо.

Он ломает себя не тем, что пересылает куда-то кусок своего кода, а тем, что пересылает кусок данных из конца архива в свое начало уже после этого. И архив начинает распаковывать уже после этого. Понятно, что его можно переделать. Но это необратимое таскание своих кусков совсем не вяжется с "он вообще ничего в себе не изменяет". Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.

Sandro
06.08.2021, 13:18
Он ломает себя не тем, что пересылает куда-то кусок своего кода, а тем, что пересылает кусок данных из конца архива в свое начало уже после этого. И архив начинает распаковывать уже после этого. Понятно, что его можно переделать. Но это необратимое таскание своих кусков совсем не вяжется с "он вообще ничего в себе не изменяет". Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.

Вопрос понятен. У нас, похоже, несколько разное понимание вопросов изменения. Пусть будет так. Так вот, версию распаковщика без этих манипуляций я совершенно точно видел в работе. И упаковать можно было в непрерывный поток, а не так вот с перекидкой.
Попробую вспомнить.

gid
06.08.2021, 13:40
Но сам же себя он не ломает? Что мешает эту пересылку отрезать?
Алгоритм мешает. Он возвращает в начало, взамен модуля автораспаковщика, тот участок упакованных данных, которые должны там находится.
Чтобы всё это исправить, надо по сути написать новую версию упаковщика.


Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.
Нет. Основное назначение бкпака - сжатие исполняемых файлов, т.е. файл загрузился, распаковался в памяти и запустился.
Если нужно многократное использование сжатых массивов, то в случае бкпака делали так - копировали сжатый массив в нужное место, и запускали автораспаковщик. Там у него был режим "сжатие данных", когда после распаковки делался не запуск, а просто возврат из п/п RTS PC.
Ну и существенный минус - нужна область для таблиц распаковки.

Для данных, особенно, если массив надо распаковать куда-то в определённое место, на БК использовали самарский Crunch/Decrunch.

Или, как тут советуют, использовать ZXn/DZXn, правда сперва придётся написать нужный упаковщик конкретно для БК.

ivagor
06.08.2021, 14:15
использовать ZXn/DZXn, правда сперва придётся написать нужный упаковщик конкретно для БК.
Чем не устраивает имеющиеся (https://github.com/ivagorRetrocomp/DeZX)? Проверял их в том числе в эмуляторе БК, работали. Или какие-то проблемы на реале?

Manwe
06.08.2021, 14:16
даСпасибо! А можешь объяснить что такое "match"? Просто документация автора рассчитана на тех, кто знаком с другими его алгоритмами - описаны только особенности lzsa2, а базовые понятия не описаны.
Про биты LL (literals length) я понял: сколько байт из входного потока копировать в выходной поток. Но не понял как при этом используется XYZ (offset). И что делать когда literals length = 0 - пропускать этот токен или разбирать биты MMM?
Про биты MMM (match length) вообще не врубился: что если задано значение и LL, и MMM? Выполнять и то, и другое? Если да, то в каком порядке? Чем match length отличается от literals length и что делать если match length = 0?

ivagor
06.08.2021, 14:26
Возможно несколько запутывает то, что автору пришлось объединить в "токене", с которого начинается каждый отдельный фрагмент все сразу - и информацию о литералах и о ссылках, все чтобы избежать дробления служебной информации на более мелкие небайтовые куски.
LL отдельно, сколько литералов скопировать, там может быть и 0.
XYZ и MMM отдельно, соответственно смещение и длина ссылки в уже раскодированном блоке, чтобы взять оттуда фрагмент и скопировать его в текущую позицию. Конечно по 3 бита мало на все случаи жизни, поэтому он там расписал, когда и как берутся дополнительные байты для длинных совпадений и дальних ссылок.

Manwe
06.08.2021, 14:50
LL отдельно, сколько литералов скопировать, там может быть и 0.А что если LL=1 и MMM=1? Сначала копируем один байт из входного потока, а потом применяем оффсет (1+2)?


XYZ и MMM отдельно, соответственно смещение и длина ссылки в уже раскодированном блоке, чтобы взять оттуда фрагмент и скопировать его в текущую позицию.Спасибо. По названию "match" я догадывался, но в описании прямо об этом не сказано. Мне кажется немного странным, что нужно устанавливать старшие биты в 1, а потом прибавлять оффсет. Было бы логично биты не трогать и отнимать оффсет. Может быть так и сделаю. Тогда, вроде, надо предварительно увеличить оффсет на 1 (преобразование отрицательных чисел в положительные).

ivagor
06.08.2021, 15:10
А что если LL=1 и MMM=1? Сначала копируем один байт из входного потока, а потом применяем оффсет (1+2)?
Да, ну и смещение из XYZ (и при необходимости из следующих байт) надо взять.

Мне кажется немного странным, что нужно устанавливать старшие биты в 1, а потом прибавлять оффсет. Было бы логично биты не трогать и отнимать оффсет.
Для pdp11 это без разницы, а вот для z80 и особенно 8080 это очень важная оптимизация. У z80 команда 16 битного вычитания длиннее и медленнее 16 битного сложения, а у 8080 нет команды 16 битного вычитания. Раньше я даже кое-какие упаковщики переделывал на эту тему.

Manwe
06.08.2021, 15:43
У z80 команда 16 битного вычитания длиннее и медленнее 16 битного сложения, а у 8080 нет команды 16 битного вычитания.Было у меня такое подозрение.


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

gid
06.08.2021, 17:00
Чем не устраивает имеющиеся?
Тем, что по данной вами ссылке нету упаковщиков под pdp-11, только распаковщики. А самому писать лень. Ибо не приспичило.
Не, может, где-то когда-то кто-то давал ссылки на упаковщики zx0..2, lzsa2, написанные для pdp-11, но это как-то мимо меня прошло.

ivagor
06.08.2021, 17:05
нету упаковщиков
Ошибся. Для lzsa2 еще можно представить упаковщик для pdp-11, а вот для zxов нет, соответствующие упаковщики были бы или невыносимо медленны или уступали бы имеющимся для ПК. Все же фишка оптимальных упаковщиков в том, что они опираются на мощь современных компьютеров.

jerri
06.08.2021, 17:19
Тем, что по данной вами ссылке нету упаковщиков под pdp-11, только распаковщики. А самому писать лень. Ибо не приспичило.
Не, может, где-то когда-то кто-то давал ссылки на упаковщики zx0..2, lzsa2, написанные для pdp-11, но это как-то мимо меня прошло.

Ну они изначально существуют только под ПЦ
вот исходники (https://github.com/einar-saukas/ZX0/tree/main/src) - можно в С собрать.
есть С под БК?

Manwe
06.08.2021, 17:45
Хм, похоже, при распаковке LZSA2 нужно сперва обрабатывать LL, а только потом всё остальное (в документации об этом, конечно, не сказано). Странно и неудобно, ведь MMM и XYZ по краям байта, проще и короче с них начать. Неоптимальный формат, однако.

ivagor
06.08.2021, 18:11
нужно сперва обрабатывать LL, а только потом всё остальное
Не скажу про все случаи, но например в начале распаковки это потенциально экономит токен, скопировали затравочный фрагмент и потом еще можем сослаться в него ссылкой, и все в одном токене.

Неоптимальный формат
"LZSA is a collection of byte-aligned compression formats that are specifically engineered for very fast decompression on 8-bit systems.", на pdp11 они не замахивались.

Manwe
06.08.2021, 18:34
"LZSA is a collection of byte-aligned compression formats that are specifically engineered for very fast decompression on 8-bit systems.", на pdp11 они не замахивались.На 8-битках тоже оптимальней доставать LL с краю байта, а не из середины.

ivagor
06.08.2021, 21:05
В токене три компонента и не получится все расположить с краю. Насколько я понимаю, они набрали статистику на типичных файлах, какие токены встречаются чаще и оптимизировали разбор наиболее частых. Автор бывал на форуме или можно написать ему напрямую, если что.

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

Вспомнил пример exomizera, когда автор выбрал формат битового потока удобный для 6502, не очень удобный для z80 и совсем неудобный для 8080. В том случае я даже не стал пересобирать упаковщик, а сделал отдельный постобработчик, который переставлял биты. Но я конечно был не один такой умный и вскоре автор добавил опцию для изменения формата битового потока в упаковщик. Аналогично можно поступить и с lzsa, или изменить упаковщик или сделать отдельную утилиту для постобработки сжатых файлов, которая будет переставлять биты в токене или где угодно и как угодно.

Manwe
06.08.2021, 22:43
Аналогично можно поступить и с lzsa, или изменить упаковщик или сделать отдельную утилиту для постобработки сжатых файлов, которая будет переставлять биты в токене или где угодно и как угодно.Да, тоже задумался об этом.
Пока вот как получилось: на 26 байт короче (перемещаемый вариант - на 16 байт короче) и на 5.4% быстрей. Потестируйте, пожалуйста, на сложных файлах.

; LZSA2 PDP-11 decompressor by Manwe/SandS
; Thanks to Ivan Gorodetsky
; Usage:
; MOV #src_adr,R1
; MOV #dst_adr,R2
; CALL Unpack


Unpack: MOV PC,Table+2 ; correct table address
ADD #XYZ-Unpack-2,Table+2
CLR R4 ; no nibbles sign
Token: MOVB (R1)+,R3 ; read token

Liter: MOV R3,R0
ASR R0
ASR R0
ASR R0
BIC #177774,R0 ; get 2 bits
BEQ Decode
CMP R0,#3 ; literals length
BNE Copy
MOV #239.,Limit
CALL Extend
Copy: MOVB (R1)+,(R2)+ ; literals length in R0
SOB R0,Copy

Decode: MOV R3,-(SP)
COM R3 ; invert for faster detect
ROLB R3 ; get 2 bits
ROL R0
ROLB R3
ROL R0
Table: MOVB XYZ(R0),R0
ADD R0,PC ; run subroutine
Save: MOV R0,(PC)+ ; save offset for future
Offset: .WORD 0

Match: MOV (SP)+,R0
BIC #177770,R0 ; get 3 bits
CMP R0,#7
BNE Clone
MOV #233.,Limit
CALL Extend
Clone: ADD #2,R0 ; match length
TSTB R0
BEQ Exit

MOV R2,R3
ADD Offset,R3
1: MOVB (R3)+,(R2)+
SOB R0,1
BR Token


XYZ: .BYTE oOther-Save, o13bit-Save, o9bit-Save, o5bit-Save

o5bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
BIS #177740,R0 ; set bits 5-15
BR Save

o9bit: ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0
BIS #177000,R0 ; set bits 9-15
BR Save

o13bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0 ; 8 bits
BIS #160000,R0 ; set bits 13-15
SUB #512.,R0
BR Save

oOther: ROLB R3
BCS 1
MOV Offset,R0 ; reuse offset
BR Match
1: MOVB (R1)+,R0
SWAB R0
CLRB R0
BISB (R1)+,R0
BR Save

Nibble: COM R4
BNE 1
MOV R5,R0
BR 2
1: MOVB (R1)+,R5 ; read 2 nibbles
MOV R5,R0
ASR R0
ASR R0
ASR R0
ASR R0
2: BIC #177760,R0 ; leave 4 low bits
RET

Extend: MOV R0,-(SP) ; save original value
CALL Nibble ; get nibble in R0
CMP R0,#15.
BNE Ext2
CLR R0
BISB (R1)+,R0
CMP R0,(PC)+
Limit: .WORD 239.
BNE Ext1
MOVB (R1)+,R0 ; read low byte
SWAB R0
CLRB R0
BISB (R1)+,R0 ; read high byte
SWAB R0
TST (SP)+ ; skip saved R0
RET
Ext1: ADD #15.,R0
Ext2: ADD (SP)+,R0 ; add original value
Exit: RET

.ENDПопробую ещё с отрицательными оффсетами поколдовать - вдруг получится чуть оптимизировать.

MM
07.08.2021, 01:04
Пожалуйста, посоветуйте по упаковке 4-битного звука ( речевое сообщение о разряде батарейки ) с семплрейтом 8 Кгц - это будет эффективнее хотя бы на 50% по сравнению с обычным хранением в формате .WAV ?
Какая скорость декомпрессии отрезка 3.5 Кбайт ( размер выходного файла ) на БК11М-4 мгц ?

grf
07.08.2021, 04:50
Тем, что по данной вами ссылке нету упаковщиков под pdp-11, только распаковщики. А самому писать лень. Ибо не приспичило.
Не, может, где-то когда-то кто-то давал ссылки на упаковщики zx0..2, lzsa2, написанные для pdp-11, но это как-то мимо меня прошло.

LZ сделал Женя Пашигоров, но он был заточен на сжатие кучи файлов в один архив:
http://zx-pk.ru/images/ext/2016/04/08/01/lzb.png

Блин, вот что значит склероз )) Сначала я вспомнил, что Женя написал LZ и мы его активно использовали для сжатия каталогов/дисков. Потом я сжал им картинку TITR1.PIC и получил 15к (восьмеричных). Подумал, что можно поискать исходники LZ и сделать распаковщик для встраивания в программы. А потом оказалось, что Женя сделал этот распаковщик сто лет назад и мы с ним уже применяли его в Color Lines:

75937
75938

Все было под руками :)

Manwe
07.08.2021, 07:43
Пожалуйста, посоветуйте по упаковке 4-битного звука ( речевое сообщение о разряде батарейки ) с семплрейтом 8 Кгц - это будет эффективнее хотя бы на 50% по сравнению с обычным хранением в формате .WAV ?
Какая скорость декомпрессии отрезка 3.5 Кбайт ( размер выходного файла ) на БК11М-4 мгц ?Я писал алгоритм 4-битного ADPCM, скорость приемлемая. Кажется, там использовались таблицы для распаковки. С ходу не вспомню, надо искать алгоритм. Поищу попозже.

ivagor
07.08.2021, 09:01
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.

Manwe
07.08.2021, 09:28
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.Думаю, это возможно, если сконвертировать входной поток. Ниблы, отвечающие за смещения, нужно инвертировать. Парам байтов с 16-битным смещением нужно изменить знак и поменять порядок этих байтов. Думаю, это сократит размер распаковщика байт на 10 и ускорит на пару процентов. Пока что у меня размер 254 байта (перемещаемый вариант). Ещё можно поменять местами MMM и LL в токене, это даст сокращение распаковщика на 1 инструкцию и ускорение.

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

jerri
07.08.2021, 10:16
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.

а насколько реально запустить упаковщик на БК?

grf, хочет именно это.

ivagor
07.08.2021, 11:06
Manwe, мне очень не хотелось, но один раз все же потестировал - из 5 файлов: 3 распаковывает нормально, 2 вылетают. Не могу рекомендовать собственный подход к тестированию, длинные файлы я взял с вектора и проверяю в конфиге ДВК, лучше найти что-нибудь УКНЦшное или Неоновское и там проверять. А я торжественно обещаю больше не тестировать до достижения озвученных ранее параметров, мне еще приходится вручную править под используемый ассемблер.


grf, хочет именно это
В этом я, к сожалению, помочь не могу.

Manwe
07.08.2021, 11:15
Пожалуйста, посоветуйте по упаковке 4-битного звукаПосмотрел свои исходники, у меня такой изврат: два сэмпла хранятся по одним и тем же адресам - один сэмпл в младших 4-х битах каждого байта, другой сэмпл в старших 4-х битах этого же байта. Использовалось для микширования многоканального звука. Немного иная задача.
Чистый ADPCM сделать не сложно, напишу на досуге. Там главное выровнять по времени выдачу данных в Covox, чтобы через одинаковые промежутки времени шло. какие-то пустые команды придётся вставлять, замерять такты.

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


длинные файлы я взял с вектораМожно ссылку?

ivagor
07.08.2021, 12:05
Один из двух "проблемных" файлов вот (http://www.sensi.org/scalar/ware/393/), второй не нашел выложенным в таком виде, который у меня, надеюсь одного хватит.

Manwe
07.08.2021, 13:27
Один из двух "проблемных" файлов вот (http://www.sensi.org/scalar/ware/393/), второй не нашел выложенным в таком виде, который у меня, надеюсь одного хватит.chipdale.rom? Его надо скачать и упаковать lzsa2?

ivagor
07.08.2021, 14:06
chipdale.rom? Его надо скачать и упаковать lzsa2?
Да, только я не помню, какой версией сжимал. Сейчас уже есть 1.3.7, а там была или 1.3.5 или 1.3.6. На всякий случай размер сжатого файла 7965 байт, md5=2f8f9105e2bca7710256195fdb347fb4

reddie
07.08.2021, 14:35
один сэмпл в младших 4-х битах каждого байта, другой сэмпл в старших 4-х битах этого же байта
Таким же образом хранили оцифровки для AY на Спектруме))
Можно извратиться еще больще, оставив два бита и приделав интерполяцию. Хоть линейную, хоть навроде кривых Безье.

grf
07.08.2021, 15:00
а насколько реально запустить упаковщик на БК?

grf, хочет именно это.

Я уже нашел и упаковщик и распаковщик LZ, написанные именно для БК еще в 1995 году.

jerri
07.08.2021, 19:12
Я уже нашел и упаковщик и распаковщик LZ, написанные именно для БК еще в 1995 году.

в оригинале игра лезет на 2 диска. 140+140к
у тебя больше?

grf
08.08.2021, 03:45
в оригинале игра лезет на 2 диска. 140+140к
у тебя больше?

Больше, примерно 289к. Одна только музыка в виде упакованного psg занимает 32к.

Manwe
08.08.2021, 12:37
Да, только я не помню, какой версией сжимал. Сейчас уже есть 1.3.7, а там была или 1.3.5 или 1.3.6. На всякий случай размер сжатого файла 7965 байт, md5=2f8f9105e2bca7710256195fdb347fb4Разбира юсь с chipdale.rom, почти получилось :) Визуально распакованные файлы совпадают, но у меня получается на 6 байт больше оригинала, ищу проблему.
Опять же, в документации туманно написано:
233: a second and third byte follow, forming a little-endian 16-bit value. The final encoded match length is that 16-bit value.
Казалось бы, финальный результат. Но выше было написано the encoded match length is the actual match length offset by the minimum, which is 2 bytes. For instance, an actual match length of 5 bytes to be copied, is encoded as 3.
Непонятно, то 16-битное final всё-таки финальное, или ещё надо добавить 2? Потому что в других случаях "финальным" называлось значение после добавления 2: and then the minmatch of 2 is added, to compose the final match length.
Автор документации, конечно, не слишком следит за терминологией.

ivagor
08.08.2021, 13:37
Непонятно, то 16-битное final всё-таки финальное, или ещё надо добавить 2?
То 16 битное финальное, в других случаях добавляется 2.

Manwe
08.08.2021, 13:53
То 16 битное финальное, в других случаях добавляется 2.Архитектурный косяк, конечно. Из-за этого приходится заводить отдельный признак для 16-битных значений и делать лишнюю проверку. Итого, две лишние инструкции.
В общем, поборол я chipdale.rom, распаковщик работает корректно. Размер 254 байта (244 байт для неперемещаемого варианта). И чуть быстрей исполняется (на 6% быстрей твоего оригинального).
Оптимизация привела к тому, что появляется один артефакт: рандомный байт в памяти после распакованного файла. Это мешает, если данные выводятся сразу на экран. В таком случае после распаковки надо очищать содержимое байта, на который указывает R2. Чуть сложней случай - распаковка впритык к границе ПЗУ - тогда лишний байт попытается записать себя в ПЗУ и произойдёт прерывание (впрочем, означающее конец распаковки).


; LZSA2 PDP-11 decompressor by Manwe/SandS
; Thanks to Ivan Gorodetsky
; Usage:
; MOV #src_adr,R1
; MOV #dst_adr,R2
; CALL Unpack


Unpack: MOV PC,Table+2 ; correct table address
ADD #XYZ-Unpack-2,Table+2
CLR R4 ; no nibbles sign
Token: MOVB (R1)+,R3 ; read token

Liter: MOV R3,R0
ASR R0
ASR R0
ASR R0
BIC #177774,R0 ; get 2 bits
BEQ Decode
CMP R0,#3 ; literals length
BNE Copy
MOVB #239.,(R2) ; set limit
CALL Extend
Copy: MOVB (R1)+,(R2)+ ; literals length in R0
SOB R0,Copy

Decode: MOV R3,-(SP)
COM R3 ; invert for faster detect
ROLB R3 ; get 2 bits
ROL R0
ROLB R3
ROL R0
Table: MOVB XYZ(R0),R0
ADD R0,PC ; run subroutine
Save: MOV R0,(PC)+ ; save offset for future
Offset: .WORD 0

Match: MOV (SP)+,R0
BIC #177770,R0 ; get 3 bits
CMP R0,#7
BNE Clone
MOVB #233.,(R2) ; set limit
CALL Extend
BCS Clone+4 ; skip minimal match length
Clone: ADD #2,R0 ; match length
TSTB R0
BEQ Exit

MOV R2,R3
ADD Offset,R3
1: MOVB (R3)+,(R2)+
SOB R0,1
BR Token


XYZ: .BYTE oOther-Save, o13bit-Save, o9bit-Save, o5bit-Save

o5bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
BIS #177740,R0 ; set bits 5-15
BR Save

o9bit: ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0
BIS #177000,R0 ; set bits 9-15
BR Save

o13bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0 ; 8 bits
BIS #160000,R0 ; set bits 13-15
SUB #512.,R0
BR Save

oOther: ROLB R3
BCS 1
MOV Offset,R0 ; reuse offset
BR Match
1: MOVB (R1)+,R0
SWAB R0
CLRB R0
BISB (R1)+,R0
BR Save

Nibble: COM R4
BNE 1
MOV R5,R0
BR 2
1: MOVB (R1)+,R5 ; read 2 nibbles
MOV R5,R0
ASR R0
ASR R0
ASR R0
ASR R0
2: BIC #177760,R0 ; leave 4 low bits
RET

Extend: MOV R0,-(SP) ; save original value
CALL Nibble ; get nibble in R0
CMP R0,#15.
BNE Ext2
CLR R0
BISB (R1)+,R0
CMPB R0,(R2) ; compare with limit
BNE Ext1
; unnecessary for short files
MOVB (R1)+,R0 ; read low byte
SWAB R0
CLRB R0
BISB (R1)+,R0 ; read high byte
SWAB R0
TST (SP)+ ; skip saved R0
SEC ; set sign of 16 bit vslue
RET
Ext1: ADD #15.,R0
Ext2: ADD (SP)+,R0 ; add original value
Exit: RET

.END

Если интересно как я проверяю скорость: пишу такой код, он замеряет сколько тиков таймера распаковывается файл и выводит 10-чное число на экран (средствами MKDOS, в других операционных системах не выведет). Чем меньше число, тем быстрей исполнение. Один тик таймера равен 128-и тактам процессора.

TimerCommand = 177712 ; timer port address
TimerCounter = 177710
TimerInitial = 177706
DecOut = 120060 ; MKDOS subroutine

MOV #1,@#TimerInitial
MOV #1,@#TimerCommand ; stop and init timer
MOV #TimerCounter,R4
MTPS #340 ; disable all interruptions
MOV #32,@#TimerCommand ; start timer
1: TST (R4) ; wait till it's really started
BNE 1

MOV #File,R1
MOV #40000,R2
CALL Unpack

MOV @#TimerCounter,R0 ; get timer value
NEG R0
MTPS #0 ; enable all interruptions
CALL DecOut

HALT

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


Да, только я не помню, какой версией сжимал. Сейчас уже есть 1.3.7, а там была или 1.3.5 или 1.3.6. На всякий случай размер сжатого файла 7965 байт7963 байт выдаёт последняя версия упаковщика

ivagor
08.08.2021, 14:28
Архитектурный косяк, конечно. Из-за этого приходится заводить отдельный признак для 16-битных значений и делать лишнюю проверку. Итого, две лишние инструкции.
Для 8-биток, на которые ориентирован lzsa, это (отдельное 16 битное значение) удачное решение, которое экономит одну или две команды.

Размер 254 байта (244 байт для неперемещаемого варианта). И чуть быстрей исполняется (на 6% быстрей твоего оригинального).
У меня последний вариант на 8% быстрее, но 264 байта.

Manwe
08.08.2021, 15:13
Для 8-биток, на которые ориентирован lzsa, это (отдельное 16 битное значение) удачное решение, которое экономит одну или две команды.если бы это 16-битное значение было уменьшено на 2, то ещё 2 команды сэкономилось бы

ivagor
08.08.2021, 17:06
Вот так неожиданно выявляются различающиеся требования к упаковщику/распаковщику для 8/16 бит, ну или по крайней мере для pdp11. Про это я не думал, больше на виду лежит другой ресурс для ускорения распаковки на pdp11 - использование где можно 16 битных пересылок. Если это включить явно в компрессор, то на степени сжатия это скажется отрицательно, но это именно опция для быстрой распаковки, там где скорость важнее.

Manwe
08.08.2021, 17:57
Вот так неожиданно выявляются различающиеся требования к упаковщику/распаковщику для 8/16 бит, ну или по крайней мере для pdp11. Про это я не думал, больше на виду лежит другой ресурс для ускорения распаковки на pdp11 - использование где можно 16 битных пересылок. Если это включить явно в компрессор, то на степени сжатия это скажется отрицательно, но это именно опция для быстрой распаковки, там где скорость важнее.Да, согласен. Но и так простой перестановкой битов и байтов можно подготовить файл к более быстрой распаковке на PDP-11.

Вот, кстати, очередная оптимизация: 242 байта, на 6.6% быстрей оригинала.

; LZSA2 PDP-11 decompressor by Manwe/SandS
; Thanks to Ivan Gorodetsky
; Usage:
; MOV #src_adr,R1
; MOV #dst_adr,R2
; CALL Unpack


Unpack: CLR R4 ; no nibbles sign
Token: MOVB (R1)+,R3 ; read token

Liter: MOV R3,R0
ASR R0
ASR R0
ASR R0
BIC #177774,R0 ; get 2 bits
BEQ Decode
CMP R0,#3 ; literals length
BNE Copy
MOVB #239.,(R2) ; set limit
CALL Extend
Copy: MOVB (R1)+,(R2)+ ; literals length in R0
SOB R0,Copy

Decode: MOV R3,-(SP)
COM R3 ; invert for faster detect
ROLB R3 ; get 2 bits
ROL R0
ROLB R3
ROL R0
ASL R0
ADD R0,PC ; run subroutine
BR oOther
BR o13bit
BR o9bit
o5bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
BIS #177740,R0 ; set bits 5-15
Save: MOV R0,(PC)+ ; save offset for future
Offset: .WORD 0

Match: MOV (SP)+,R0
BIC #177770,R0 ; get 3 bits
CMP R0,#7
BNE Clone
MOVB #233.,(R2) ; set limit
CALL Extend
BCS Clone+4 ; skip minimal match length
Clone: ADD #2,R0 ; match length
TSTB R0
BEQ Exit

MOV R2,R3
ADD Offset,R3
1: MOVB (R3)+,(R2)+
SOB R0,1
BR Token


o9bit: ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0
BIS #177000,R0 ; set bits 9-15
BR Save

o13bit: CALL Nibble ; get nibble in R0
ROLB R3
ROL R0
SWAB R0
BISB (R1)+,R0 ; 8 bits
BIS #160000,R0 ; set bits 13-15
SUB #512.,R0
BR Save

oOther: ROLB R3
BCS 1
MOV Offset,R0 ; reuse offset
BR Match
1: MOVB (R1)+,R0
SWAB R0
CLRB R0
BISB (R1)+,R0
BR Save

Nibble: COM R4
BNE 1
MOV R5,R0
BR 2
1: MOVB (R1)+,R5 ; read 2 nibbles
MOV R5,R0
ASR R0
ASR R0
ASR R0
ASR R0
2: BIC #177760,R0 ; leave 4 low bits
RET

Extend: MOV R0,-(SP) ; save original value
CALL Nibble ; get nibble in R0
CMP R0,#15.
BNE Ext2
CLR R0
BISB (R1)+,R0
CMPB R0,(R2) ; compare with limit
BNE Ext1
; unnecessary for short files
MOVB (R1)+,R0 ; read low byte
SWAB R0
CLRB R0
BISB (R1)+,R0 ; read high byte
SWAB R0
TST (SP)+ ; skip saved R0
SEC ; set sign of 16 bit vslue
RET
Ext1: ADD #15.,R0
Ext2: ADD (SP)+,R0 ; add original value
Exit: RET

.END

Manwe
11.08.2021, 18:53
Пришлось модифицировать упаковщик LZSA2, чтобы формат лучше подходил для PDP-11.
Итого, распаковщик занимает 200 байт (на 27% меньше оригинала). Быстрей на 18% (в 1.22 раз).
ivagor, как это в сравнении с zx0 и zx1?

ivagor
11.08.2021, 19:10
Если принять твой последний распаковщик за точку отсчета, то zx0 (102 байта) медленнее на 16%, zx1 (144 байта) медленнее на 7%. Это уже встраивает lzsa2 в линейку как для z80 и 8080: lzsa1-lzsa2-zx1-zx0. Чем левее, тем быстрее; чем правее, тем лучше сжатие. Но все же 7% при распаковке файлов для 0010 сравнительно сложно заметить, а вот степень сжатия и размер распаковщика на стороне zx1. Тут в каждом конкретном случае надо смотреть, что важнее.

Manwe
11.08.2021, 20:18
а вот степень сжатия и размер распаковщика на стороне zx1. Тут в каждом конкретном случае надо смотреть, что важнее.А можешь дать ссылку на zx1 для PDP-11? Прогоню своим тестом

ivagor
11.08.2021, 21:03
Ссылка (https://github.com/ivagorRetrocomp) сразу на все распаковщики для pdp11, но придется сделать еще несколько кликов.

ivagor
12.08.2021, 06:11
zx1 (144 байта)
Поправка - zx1 (126 байт). 144 байта это все вместе, с заданием "откуда", "куда", вызовом подпрограммы и стопом, а в githubовском варианте правильная цифра.

Manwe
12.08.2021, 13:31
Спасибо, сравнил zx0 и zx1 с нашим адаптированным lzsa2 на 16-килобайтном файле. Итог:

zx0 медленней в 1.38 раз
размер zx0 меньше в 1.08 раз

zx1 медленней в 1.21 раз
размер zx1 меньше в 1.03 раз

Ссылка на нашу адаптацию lzsa2 (быстрый распаковщик размером 198 байт): github (https://github.com/imachug/lzsa3)

ivagor
12.08.2021, 14:11
zx0 медленней в 1.38 раз

zx1 медленней в 1.21 раз
Это на реале? И можно файлик для сравнения, я проверял в emu, интересно, сколько там покажет.

Manwe
12.08.2021, 18:02
Это на реале? И можно файлик для сравнения, я проверял в emu, интересно, сколько там покажет.Файлик для проверки и заодно программа замера скорости: https://github.com/imachug/lzsa3/tree/master/samples

На реальном железе пока не проверял, но результаты должны быть очень близкими.

ivagor
12.08.2021, 18:20
Обновил zxы (https://github.com/ivagorRetrocomp/DeZX) для pdp11. Немного сократил (zx1 на 16 байт, zx0 и zx2 на 4 байта) и ускорил (zx1 на 5-6%, zx0/2 поменьше).

ivagor
13.08.2021, 17:02
Ускорил zx1 (https://github.com/ivagorRetrocomp/DeZX/tree/main/ZX1/PDP11) еще на 3% и сократил на 2 байта. Последний вариант zx1 на 9% медленнее lzsa3 при распаковке facet.raw, что сравнительно неплохо с учетом размера распаковщика и степени сжатия.
Еще ускорил zx2 (https://github.com/ivagorRetrocomp/DeZX/tree/main/ZX2/PDP11) на 3-5%.

Manwe
14.08.2021, 08:18
Еще ускорил zx2 (https://github.com/ivagorRetrocomp/DeZX/tree/main/ZX2/PDP11) на 3-5%.Круто. А за версию Shrinkler для PDP-11 что не берёшься?

ivagor
14.08.2021, 09:10
А за версию Shrinkler для PDP-11 что не берёшься?
Для ВМ2 и ВМ1Г скорее всего можно сделать почти приличный (применимый на практике) распаковщик shrinklerа, но это сравнительно сложно и надо много мотивации, пока не накопил.

Manwe
15.08.2021, 08:21
Для ВМ2 и ВМ1Г скорее всего можно сделать почти приличный (применимый на практике) распаковщик shrinklerа, но это сравнительно сложно и надо много мотивации, пока не накопил.а есть внятное описание этого формата?

ivagor
15.08.2021, 09:07
Есть исходники, а текстового описания я не находил.

ivagor
04.10.2021, 17:01
Сократил на 2 байта и чуть-чуть ускорил распаковщик zx0 (https://github.com/ivagorRetrocomp/DeZX/tree/main/ZX0/PDP11). Это распаковщик для "классического" формата, не для второй версии. У меня не получилось выигрыша от перехода ко второй версии ни для 8080 ни для pdp11. К счастью степень сжатия одинаковая и вторая версия упаковщика может сжимать в "классический" формат.

BlaireCas
07.11.2021, 12:52
Ссылка на нашу адаптацию lzsa2 (быстрый распаковщик размером 198 байт): github
Грац за готовый код и утилиту под винду. Заюзал для УКНЦ. Работоспособно и шустренько так.
Единственно кажется для УКНЦ вот эта команда может быть из разряда "не все йогурты одинаково полезны":

BISB (R1)+,R0 ; read low byte
TST (SP)+ ; skip saved R0
RET
Дело в том что на УКНЦ чтение из некоторых ячеек памяти вызывает какие-то действия (например при чтении @#177024 загрузятся некими значениями ячейки памяти @#177020, @#177022). Разумеется случай нереально маловероятный, но "а вдруг".
На БК наверное таких ужасов нету и там все окей.

UPD: туплю-же. это ведь стек и он туда не залезет, просто привычка такая не юзать сокращения вида tst (Rn)+ или cmp (Rn)+,(Rn)+

lexarr
22.04.2022, 15:21
Исходник распаковщика, использующего алгоритм NRV2d из библиотеки UCL. Для других платформ такой уже делали давно (это кстати основной способ упаковки для утилиты UPX).
Распаковка одна из самых быстрых, но по степени сжатия уступает остальным, в целом - неплохо.



; Алгоритм распаковки NRV2d (UCL) для БК / PDP
; Вход:
; R0 - адрес сжатых данных;
; R1 - адрес распаковки.

N2DUNPK:
MOV #-1, R4
XOR R2, R2
BR DCL

NXDC: MOVB (R0)+, (R1)+
DCL: CALL RB
BCS NXDC

MOV #1, R3
OFN: ADD R3, R3
CALL RB
ADC R3
CALL RB
BCS OFE
DEC R3
ADD R3, R3
CALL RB
ADC R3
BR OFN

RB: ADD R2, R2
BEQ RBZ
RET
RBZ: MOVB (R0)+, R2
SWAB R2
BIC #177, R2
BIS #200, R2
ADD R2, R2
RET

OFE: SUB #3, R3
BCC OF2

MOV R4, R3
XOR R5, R5
CALL RB
ADC R5
BR OF3

OF2: SWAB R3
MOVB (R0)+, R5
BIC #177400, R5
BIS R5, R3
COM R3
BEQ BRK
XOR R5, R5
SEC
ROR R3
ADC R5
MOV R3, R4

OF3: ADD R5, R5
CALL RB
ADC R5
BNE LF1

INC R5
NXLF: ADD R5, R5
CALL RB
ADC R5
CALL RB
BCC NXLF
ADD #2, R5

LF1: CMP R3, #175400
ADC R5
INC R5

ADD R1, R3
NXMV: MOVB (R3)+, (R1)+
SOB R5, NXMV
BR DCL

BRK: RET


Для упаковки используется приложенная утилита `n2dpack`. Отличие от оригинального алгоритма - переделанный финальный маркер (с длинного на короткий).

Пример использования: 77229.

ivagor
22.04.2022, 17:06
Еще один распаковщик - это хорошо, но сейчас он представляет скорее исторический интерес, современные намного лучше. Если взять например zx1 (https://github.com/einar-saukas/ZX1), то он сжимает сильнее. А распаковщик (https://github.com/ivagorRetrocomp/DeZX/blob/main/ZX1/PDP11/dzx1.asm) 108 байт против 160 и почти в два раза быстрее.