
Сообщение от
ivagor
То 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
- - - Добавлено - - -

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