Просмотр полной версии : Упаковщики
Какие есть упаковщики графики и кода для БК, кроме KOMP2?
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.
Спасибо, попробую найти и заюзать)
Какие есть упаковщики графики и кода для БК, кроме KOMP2?Советую LZSA (https://github.com/ivagorRetrocomp/DeLZSA/tree/main/PDP11)
Советую LZSA (https://github.com/ivagorRetrocomp/DeLZSA/tree/main/PDP11)
Спасибо! Но это только распаковщик. Упаковывать предполагается на PC?
Спасибо! Но это только распаковщик. Упаковывать предполагается на PC?
а в чем проблема - это же удобно.
могу предложить еще вот такой упаковщик. zx0 (https://github.com/einar-saukas/ZX0)
распаковщик есть и под PDP11
распаковщик правда под z80
но переписать как мне кажется трудностей не составит
Интересующимся могу предложить глянуть Спектрумовские жамкалки скринов и данных, работали неплохо.
Для данных вообще была прога, создающая sfx-архивы - Hrust. Упаковщик картинок, по памяти - ASC Screen Crasher.
В свое время Писишники переделывали Hrust/Dehrust для распаковки интрух, настолько мало он весил =)
распаковщик есть и под PDP11
75927
Исходники распаковщиков LZSA1, LZSA2, ZX0, ZX1 для БК0010
BKPACK дал хорошие результаты, буду юзать его )
BKPACK дал хорошие результаты, буду юзать его )
насколько хорошо жмет?
https://introspec.retroscene.org/compression/pareto_20210128.png
лучше чем Shrinker?
Файлы заставок, которые мне нужно сжать, жмет в среднем в два раза:
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
Все числа восьмеричные. Причем это он делает исполняемый файл с встроенным распаковщиком, который надо из них будет выдрать и использовать только в одном экземпляре.
Файлы заставок, которые мне нужно сжать
а можно сюда их выложить? поковыряюсь на досуге с переделкой спектрумовского.
Для сравнения результатов, чтоб было понятней, кто как жмет.
а можно сюда их выложить? поковыряюсь на досуге с переделкой спектрумовского.
Для сравнения результатов, чтоб было понятней, кто как жмет.
https://cloud.mail.ru/public/5NuJ/UDEP6T154
ZX0
TITR1.PIC - 3890dec байт=7462oct байта
TITR2.PIC - 3784dec байт=7310oct байт
+распаковщик 102dec=146oct байт
в PONG Charged (https://r-games.net/bk001x/games/48297-pong-charged.html) я использовал LZSA2 и очень доволен
LZSA2
Если распаковщик мой, то вариант для pdp11 был совсем неудачный, даже не стал его выкладывать на github. Но и при наличии более эффективного распаковщика актуальность lzsa2 после появления zx0/1 сильно уменьшилась. lzsa1 - быстрый; zx0 - сильно сжимает; zx2 - компактный распаковщик; zx1 - степень сжатия немного уступает zx1, зато скорость почти как у lzsa2, а в варианте для pdp11 даже быстрее, что правда больше говорит о недоработанности того распаковщика lzsa2.
zx1 - степень сжатия немного уступает zx1Вот этого я не понял :)
zx0 я попробовал, но он не сильней чем lzsa2 сжал.
в PONG Charged (https://r-games.net/bk001x/games/48297-pong-charged.html) я использовал LZSA2 и очень доволен
Мне вполне хватит BKPACK, тем более он полностью БКшный - и упаковщик и распаковщик :)
Вот этого я не понял
Пардон, "zx1 - степень сжатия немного уступает zx0".
zx0 я попробовал, но он не сильней чем lzsa2 сжал.
Для редких отдельных файлов это возможно (кстати, пока не находил примеров таких файлов, можно куда-нибудь выложить тот самый?), но в среднем по больнице он заметно опережает.
Bkpack. Я только им и пользовался. Единственный из упаковщиков такого типа который мне нравился.
Распаковщик BKPACK существует в версии, которая пригодна к многократной распаковке архива и не портит сама себя?
Если распаковщик мой, то вариант для pdp11 был совсем неудачный, даже не стал его выкладывать на github.Не подскажешь как в LZSA2 это устроено? Read a nibble... then read a byte. После чтения токена (байта) нужно прочитать ниббл (4 бита), а потом байт. Получается, этот байт сдвинут на 4 бита? То есть расположение данных в памяти выглядит так (побитно, где | означает границы байтов в памяти)?
| tokenmmm | niblbyte | byte.... |
^^^^ ^^^^
Распаковщик BKPACK существует в версии, которая пригодна к многократной распаковке архива и не портит сама себя?
Насколько я помню, он вообще ничего в себе не изменяет, поэтому можно хранить в памяти кучу данных и распаковывать им по мере надобности. Благо алгоритм неожиданно удачный. Он близок по степени сжатия к ZIP/DEFLATE, и при этом вообще не использует побитовой упаковки!
близок по степени сжатия к ZIP/DEFLATE
Спорное утверждение, например TITR1.PIC и TITR2.PIC zip/deflate сжал в полтора раза лучше, чем bkpack.
как в LZSA2 это устроено
Про формат lzsa2 я вряд ли напишу лучше автора, но если ограничиться нибблами, то можно сказать, что есть как бы параллельный поток нибблов (это как поток битов во многих других упаковщиках), перемежающийся с потоком байтов. Если нужен ниббл, то мы проверяем текущее состояние "буфера нибблов", и
1. если там пусто, читаем следующий байт, берем оттуда один ниббл, а второй - в буфер нибблов.
2. если там не пусто, берем ниббл и помечаем, что "буффер нибблов" пуст.
Про формат lzsa2 я вряд ли напишу лучше автора, но если ограничиться нибблами, то можно сказать, что есть как бы параллельный поток нибблов (это как поток битов во многих других упаковщиках), перемежающийся с потоком байтов. Если нужен ниббл, то мы проверяем текущее состояние "буфера нибблов", и
1. если там пусто, читаем следующий байт, берем оттуда один ниббл, а второй - в буфер нибблов.
2. если там не пусто, берем ниббл и помечаем, что "буффер нибблов" пуст.То есть нибблы всегда хранятся парами, чтобы занимать ровно байт?
P.S. мне кажется, обсуждение распаковки - НЕ оффтопик в теме про упаковку, так что можно не прятать обсуждение в спойлер.
То есть нибблы всегда хранятся парами, чтобы занимать ровно байт?
да
Насколько я помню, он вообще ничего в себе не изменяет, поэтому можно хранить в памяти кучу данных и распаковывать им по мере надобности. Благо алгоритм неожиданно удачный. Он близок по степени сжатия к ZIP/DEFLATE, и при этом вообще не использует побитовой упаковки!
Распаковщик изначально выглядит так:
75933
Он пересылает часть кода в назначенную рабочую область, потом делает JMP на начало этого кода, и первым делом затирает свое начало, пересылая туда 572 байта из конца архива:
75934
Таким образом, повторный запуск уже не имеет смысла, потому что там нет изначального кода.
Таким образом, повторный запуск уже не имеет смысла, потому что там нет изначального кода.
можно было бы использовать 1 распаковщик на все файлы.
Но нет так нет.
Распаковщик изначально выглядит так:
Таким образом, повторный запуск уже не имеет смысла, потому что там нет изначального кода.
Но сам же себя он не ломает? Что мешает эту пересылку отрезать? Она нужна только для того, чтобы можно было запускать программу со стандартного адреса 1000, и одновременно там в начале был бы распаковщик. если этого требования нет, то и так фокусничать не надо.
Но сам же себя он не ломает? Что мешает эту пересылку отрезать? Она нужна только для того, чтобы можно было запускать программу со стандартного адреса 1000, и одновременно там в начале был бы распаковщик. если этого требования нет, то и так фокусничать не надо.
Он ломает себя не тем, что пересылает куда-то кусок своего кода, а тем, что пересылает кусок данных из конца архива в свое начало уже после этого. И архив начинает распаковывать уже после этого. Понятно, что его можно переделать. Но это необратимое таскание своих кусков совсем не вяжется с "он вообще ничего в себе не изменяет". Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.
Он ломает себя не тем, что пересылает куда-то кусок своего кода, а тем, что пересылает кусок данных из конца архива в свое начало уже после этого. И архив начинает распаковывать уже после этого. Понятно, что его можно переделать. Но это необратимое таскание своих кусков совсем не вяжется с "он вообще ничего в себе не изменяет". Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.
Вопрос понятен. У нас, похоже, несколько разное понимание вопросов изменения. Пусть будет так. Так вот, версию распаковщика без этих манипуляций я совершенно точно видел в работе. И упаковать можно было в непрерывный поток, а не так вот с перекидкой.
Попробую вспомнить.
Но сам же себя он не ломает? Что мешает эту пересылку отрезать?
Алгоритм мешает. Он возвращает в начало, взамен модуля автораспаковщика, тот участок упакованных данных, которые должны там находится.
Чтобы всё это исправить, надо по сути написать новую версию упаковщика.
Потому я и спросил, нет ли версии, изначально просто распаковывающей архив в нужный адрес без выкрутасов.
Нет. Основное назначение бкпака - сжатие исполняемых файлов, т.е. файл загрузился, распаковался в памяти и запустился.
Если нужно многократное использование сжатых массивов, то в случае бкпака делали так - копировали сжатый массив в нужное место, и запускали автораспаковщик. Там у него был режим "сжатие данных", когда после распаковки делался не запуск, а просто возврат из п/п RTS PC.
Ну и существенный минус - нужна область для таблиц распаковки.
Для данных, особенно, если массив надо распаковать куда-то в определённое место, на БК использовали самарский Crunch/Decrunch.
Или, как тут советуют, использовать ZXn/DZXn, правда сперва придётся написать нужный упаковщик конкретно для БК.
использовать ZXn/DZXn, правда сперва придётся написать нужный упаковщик конкретно для БК.
Чем не устраивает имеющиеся (https://github.com/ivagorRetrocomp/DeZX)? Проверял их в том числе в эмуляторе БК, работали. Или какие-то проблемы на реале?
даСпасибо! А можешь объяснить что такое "match"? Просто документация автора рассчитана на тех, кто знаком с другими его алгоритмами - описаны только особенности lzsa2, а базовые понятия не описаны.
Про биты LL (literals length) я понял: сколько байт из входного потока копировать в выходной поток. Но не понял как при этом используется XYZ (offset). И что делать когда literals length = 0 - пропускать этот токен или разбирать биты MMM?
Про биты MMM (match length) вообще не врубился: что если задано значение и LL, и MMM? Выполнять и то, и другое? Если да, то в каком порядке? Чем match length отличается от literals length и что делать если match length = 0?
Возможно несколько запутывает то, что автору пришлось объединить в "токене", с которого начинается каждый отдельный фрагмент все сразу - и информацию о литералах и о ссылках, все чтобы избежать дробления служебной информации на более мелкие небайтовые куски.
LL отдельно, сколько литералов скопировать, там может быть и 0.
XYZ и MMM отдельно, соответственно смещение и длина ссылки в уже раскодированном блоке, чтобы взять оттуда фрагмент и скопировать его в текущую позицию. Конечно по 3 бита мало на все случаи жизни, поэтому он там расписал, когда и как берутся дополнительные байты для длинных совпадений и дальних ссылок.
LL отдельно, сколько литералов скопировать, там может быть и 0.А что если LL=1 и MMM=1? Сначала копируем один байт из входного потока, а потом применяем оффсет (1+2)?
XYZ и MMM отдельно, соответственно смещение и длина ссылки в уже раскодированном блоке, чтобы взять оттуда фрагмент и скопировать его в текущую позицию.Спасибо. По названию "match" я догадывался, но в описании прямо об этом не сказано. Мне кажется немного странным, что нужно устанавливать старшие биты в 1, а потом прибавлять оффсет. Было бы логично биты не трогать и отнимать оффсет. Может быть так и сделаю. Тогда, вроде, надо предварительно увеличить оффсет на 1 (преобразование отрицательных чисел в положительные).
А что если LL=1 и MMM=1? Сначала копируем один байт из входного потока, а потом применяем оффсет (1+2)?
Да, ну и смещение из XYZ (и при необходимости из следующих байт) надо взять.
Мне кажется немного странным, что нужно устанавливать старшие биты в 1, а потом прибавлять оффсет. Было бы логично биты не трогать и отнимать оффсет.
Для pdp11 это без разницы, а вот для z80 и особенно 8080 это очень важная оптимизация. У z80 команда 16 битного вычитания длиннее и медленнее 16 битного сложения, а у 8080 нет команды 16 битного вычитания. Раньше я даже кое-какие упаковщики переделывал на эту тему.
У z80 команда 16 битного вычитания длиннее и медленнее 16 битного сложения, а у 8080 нет команды 16 битного вычитания.Было у меня такое подозрение.
Для pdp11 это без разницыВ данном случае можно было бы в распаковщике сэкономить несколько инструкций, если бы оффсеты во входном потоке хранились положительные. А это плюс к быстродействию.
Чем не устраивает имеющиеся?
Тем, что по данной вами ссылке нету упаковщиков под pdp-11, только распаковщики. А самому писать лень. Ибо не приспичило.
Не, может, где-то когда-то кто-то давал ссылки на упаковщики zx0..2, lzsa2, написанные для pdp-11, но это как-то мимо меня прошло.
нету упаковщиков
Ошибся. Для lzsa2 еще можно представить упаковщик для pdp-11, а вот для zxов нет, соответствующие упаковщики были бы или невыносимо медленны или уступали бы имеющимся для ПК. Все же фишка оптимальных упаковщиков в том, что они опираются на мощь современных компьютеров.
Тем, что по данной вами ссылке нету упаковщиков под pdp-11, только распаковщики. А самому писать лень. Ибо не приспичило.
Не, может, где-то когда-то кто-то давал ссылки на упаковщики zx0..2, lzsa2, написанные для pdp-11, но это как-то мимо меня прошло.
Ну они изначально существуют только под ПЦ
вот исходники (https://github.com/einar-saukas/ZX0/tree/main/src) - можно в С собрать.
есть С под БК?
Хм, похоже, при распаковке LZSA2 нужно сперва обрабатывать LL, а только потом всё остальное (в документации об этом, конечно, не сказано). Странно и неудобно, ведь MMM и XYZ по краям байта, проще и короче с них начать. Неоптимальный формат, однако.
нужно сперва обрабатывать LL, а только потом всё остальное
Не скажу про все случаи, но например в начале распаковки это потенциально экономит токен, скопировали затравочный фрагмент и потом еще можем сослаться в него ссылкой, и все в одном токене.
Неоптимальный формат
"LZSA is a collection of byte-aligned compression formats that are specifically engineered for very fast decompression on 8-bit systems.", на pdp11 они не замахивались.
"LZSA is a collection of byte-aligned compression formats that are specifically engineered for very fast decompression on 8-bit systems.", на pdp11 они не замахивались.На 8-битках тоже оптимальней доставать LL с краю байта, а не из середины.
В токене три компонента и не получится все расположить с краю. Насколько я понимаю, они набрали статистику на типичных файлах, какие токены встречаются чаще и оптимизировали разбор наиболее частых. Автор бывал на форуме или можно написать ему напрямую, если что.
- - - Добавлено - - -
Вспомнил пример exomizera, когда автор выбрал формат битового потока удобный для 6502, не очень удобный для z80 и совсем неудобный для 8080. В том случае я даже не стал пересобирать упаковщик, а сделал отдельный постобработчик, который переставлял биты. Но я конечно был не один такой умный и вскоре автор добавил опцию для изменения формата битового потока в упаковщик. Аналогично можно поступить и с lzsa, или изменить упаковщик или сделать отдельную утилиту для постобработки сжатых файлов, которая будет переставлять биты в токене или где угодно и как угодно.
Аналогично можно поступить и с 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Попробую ещё с отрицательными оффсетами поколдовать - вдруг получится чуть оптимизировать.
Пожалуйста, посоветуйте по упаковке 4-битного звука ( речевое сообщение о разряде батарейки ) с семплрейтом 8 Кгц - это будет эффективнее хотя бы на 50% по сравнению с обычным хранением в формате .WAV ?
Какая скорость декомпрессии отрезка 3.5 Кбайт ( размер выходного файла ) на БК11М-4 мгц ?
Тем, что по данной вами ссылке нету упаковщиков под 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
Все было под руками :)
Пожалуйста, посоветуйте по упаковке 4-битного звука ( речевое сообщение о разряде батарейки ) с семплрейтом 8 Кгц - это будет эффективнее хотя бы на 50% по сравнению с обычным хранением в формате .WAV ?
Какая скорость декомпрессии отрезка 3.5 Кбайт ( размер выходного файла ) на БК11М-4 мгц ?Я писал алгоритм 4-битного ADPCM, скорость приемлемая. Кажется, там использовались таблицы для распаковки. С ходу не вспомню, надо искать алгоритм. Поищу попозже.
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.Думаю, это возможно, если сконвертировать входной поток. Ниблы, отвечающие за смещения, нужно инвертировать. Парам байтов с 16-битным смещением нужно изменить знак и поменять порядок этих байтов. Думаю, это сократит размер распаковщика байт на 10 и ускорит на пару процентов. Пока что у меня размер 254 байта (перемещаемый вариант). Ещё можно поменять местами MMM и LL в токене, это даст сокращение распаковщика на 1 инструкцию и ускорение.
Потестируй, пожалуйста, мой распаковщик. Мне пока не удалось создать упакованные файлы, в которых используется длинное смещение. Кстати, блок обработки длинных смещений можно вообще выпилить в ряде случаев (написать утилиту, анализирующую архив - если длинных смещений не найдено, она предложит использовать укороченную версию распаковщика).
Manwe, попробовал сам реализовать имевшуюся заготовку по lzsa2, сократил на 6 байт (до 264) и ускорил примерно на 8%. Не так уж плохо, если бы не было zx1. Да, удалось немного обойти его по скорости, но zx1 сжимает лучше и распаковщик 144 байта против 264. Готов поучаствовать в тестировании, если получится сократить распаковщик lzsa2 до 144 байт при хотя бы символическом опережении zx1 по скорости или пусть распаковщик останется большим, но тогда надо обогнать хотя бы процентов на 10.
а насколько реально запустить упаковщик на БК?
grf, хочет именно это.
Manwe, мне очень не хотелось, но один раз все же потестировал - из 5 файлов: 3 распаковывает нормально, 2 вылетают. Не могу рекомендовать собственный подход к тестированию, длинные файлы я взял с вектора и проверяю в конфиге ДВК, лучше найти что-нибудь УКНЦшное или Неоновское и там проверять. А я торжественно обещаю больше не тестировать до достижения озвученных ранее параметров, мне еще приходится вручную править под используемый ассемблер.
grf, хочет именно это
В этом я, к сожалению, помочь не могу.
Пожалуйста, посоветуйте по упаковке 4-битного звукаПосмотрел свои исходники, у меня такой изврат: два сэмпла хранятся по одним и тем же адресам - один сэмпл в младших 4-х битах каждого байта, другой сэмпл в старших 4-х битах этого же байта. Использовалось для микширования многоканального звука. Немного иная задача.
Чистый ADPCM сделать не сложно, напишу на досуге. Там главное выровнять по времени выдачу данных в Covox, чтобы через одинаковые промежутки времени шло. какие-то пустые команды придётся вставлять, замерять такты.
- - - Добавлено - - -
длинные файлы я взял с вектораМожно ссылку?
Один из двух "проблемных" файлов вот (http://www.sensi.org/scalar/ware/393/), второй не нашел выложенным в таком виде, который у меня, надеюсь одного хватит.
Один из двух "проблемных" файлов вот (http://www.sensi.org/scalar/ware/393/), второй не нашел выложенным в таком виде, который у меня, надеюсь одного хватит.chipdale.rom? Его надо скачать и упаковать lzsa2?
chipdale.rom? Его надо скачать и упаковать lzsa2?
Да, только я не помню, какой версией сжимал. Сейчас уже есть 1.3.7, а там была или 1.3.5 или 1.3.6. На всякий случай размер сжатого файла 7965 байт, md5=2f8f9105e2bca7710256195fdb347fb4
один сэмпл в младших 4-х битах каждого байта, другой сэмпл в старших 4-х битах этого же байта
Таким же образом хранили оцифровки для AY на Спектруме))
Можно извратиться еще больще, оставив два бита и приделав интерполяцию. Хоть линейную, хоть навроде кривых Безье.
а насколько реально запустить упаковщик на БК?
grf, хочет именно это.
Я уже нашел и упаковщик и распаковщик LZ, написанные именно для БК еще в 1995 году.
Я уже нашел и упаковщик и распаковщик LZ, написанные именно для БК еще в 1995 году.
в оригинале игра лезет на 2 диска. 140+140к
у тебя больше?
в оригинале игра лезет на 2 диска. 140+140к
у тебя больше?
Больше, примерно 289к. Одна только музыка в виде упакованного psg занимает 32к.
Да, только я не помню, какой версией сжимал. Сейчас уже есть 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.
Автор документации, конечно, не слишком следит за терминологией.
Непонятно, то 16-битное final всё-таки финальное, или ещё надо добавить 2?
То 16 битное финальное, в других случаях добавляется 2.
То 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 байт выдаёт последняя версия упаковщика
Архитектурный косяк, конечно. Из-за этого приходится заводить отдельный признак для 16-битных значений и делать лишнюю проверку. Итого, две лишние инструкции.
Для 8-биток, на которые ориентирован lzsa, это (отдельное 16 битное значение) удачное решение, которое экономит одну или две команды.
Размер 254 байта (244 байт для неперемещаемого варианта). И чуть быстрей исполняется (на 6% быстрей твоего оригинального).
У меня последний вариант на 8% быстрее, но 264 байта.
Для 8-биток, на которые ориентирован lzsa, это (отдельное 16 битное значение) удачное решение, которое экономит одну или две команды.если бы это 16-битное значение было уменьшено на 2, то ещё 2 команды сэкономилось бы
Вот так неожиданно выявляются различающиеся требования к упаковщику/распаковщику для 8/16 бит, ну или по крайней мере для pdp11. Про это я не думал, больше на виду лежит другой ресурс для ускорения распаковки на pdp11 - использование где можно 16 битных пересылок. Если это включить явно в компрессор, то на степени сжатия это скажется отрицательно, но это именно опция для быстрой распаковки, там где скорость важнее.
Вот так неожиданно выявляются различающиеся требования к упаковщику/распаковщику для 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
Пришлось модифицировать упаковщик LZSA2, чтобы формат лучше подходил для PDP-11.
Итого, распаковщик занимает 200 байт (на 27% меньше оригинала). Быстрей на 18% (в 1.22 раз).
ivagor, как это в сравнении с zx0 и zx1?
Если принять твой последний распаковщик за точку отсчета, то zx0 (102 байта) медленнее на 16%, zx1 (144 байта) медленнее на 7%. Это уже встраивает lzsa2 в линейку как для z80 и 8080: lzsa1-lzsa2-zx1-zx0. Чем левее, тем быстрее; чем правее, тем лучше сжатие. Но все же 7% при распаковке файлов для 0010 сравнительно сложно заметить, а вот степень сжатия и размер распаковщика на стороне zx1. Тут в каждом конкретном случае надо смотреть, что важнее.
а вот степень сжатия и размер распаковщика на стороне zx1. Тут в каждом конкретном случае надо смотреть, что важнее.А можешь дать ссылку на zx1 для PDP-11? Прогоню своим тестом
Ссылка (https://github.com/ivagorRetrocomp) сразу на все распаковщики для pdp11, но придется сделать еще несколько кликов.
zx1 (144 байта)
Поправка - zx1 (126 байт). 144 байта это все вместе, с заданием "откуда", "куда", вызовом подпрограммы и стопом, а в githubовском варианте правильная цифра.
Спасибо, сравнил zx0 и zx1 с нашим адаптированным lzsa2 на 16-килобайтном файле. Итог:
zx0 медленней в 1.38 раз
размер zx0 меньше в 1.08 раз
zx1 медленней в 1.21 раз
размер zx1 меньше в 1.03 раз
Ссылка на нашу адаптацию lzsa2 (быстрый распаковщик размером 198 байт): github (https://github.com/imachug/lzsa3)
zx0 медленней в 1.38 раз
zx1 медленней в 1.21 раз
Это на реале? И можно файлик для сравнения, я проверял в emu, интересно, сколько там покажет.
Это на реале? И можно файлик для сравнения, я проверял в emu, интересно, сколько там покажет.Файлик для проверки и заодно программа замера скорости: https://github.com/imachug/lzsa3/tree/master/samples
На реальном железе пока не проверял, но результаты должны быть очень близкими.
Обновил zxы (https://github.com/ivagorRetrocomp/DeZX) для pdp11. Немного сократил (zx1 на 16 байт, zx0 и zx2 на 4 байта) и ускорил (zx1 на 5-6%, zx0/2 поменьше).
Ускорил 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%.
Еще ускорил zx2 (https://github.com/ivagorRetrocomp/DeZX/tree/main/ZX2/PDP11) на 3-5%.Круто. А за версию Shrinkler для PDP-11 что не берёшься?
А за версию Shrinkler для PDP-11 что не берёшься?
Для ВМ2 и ВМ1Г скорее всего можно сделать почти приличный (применимый на практике) распаковщик shrinklerа, но это сравнительно сложно и надо много мотивации, пока не накопил.
Для ВМ2 и ВМ1Г скорее всего можно сделать почти приличный (применимый на практике) распаковщик shrinklerа, но это сравнительно сложно и надо много мотивации, пока не накопил.а есть внятное описание этого формата?
Есть исходники, а текстового описания я не находил.
Сократил на 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)+
Исходник распаковщика, использующего алгоритм 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.
Еще один распаковщик - это хорошо, но сейчас он представляет скорее исторический интерес, современные намного лучше. Если взять например zx1 (https://github.com/einar-saukas/ZX1), то он сжимает сильнее. А распаковщик (https://github.com/ivagorRetrocomp/DeZX/blob/main/ZX1/PDP11/dzx1.asm) 108 байт против 160 и почти в два раза быстрее.
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot