z80unlze.asm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. ; Decompression routine for LZEXE-compressed streams, v1.1p1
  2. ;
  3. ; Copyright © 2020 Pedro Gimeno Fortea
  4. ;
  5. ; This is a decompressor for LZEXE-compressed streams. Copying, distribution
  6. ; and modification of this package or parts of it are permitted, under two
  7. ; conditions: that any copyright notices and this notice are preserved, and
  8. ; that any modified version is clearly marked as such. This package is offered
  9. ; as-is, without any warranty express or implied.
  10. ;
  11. ; Input: HL=source, DE=destination
  12. ; Output: HL=last source address read+1 ( = initial source address + length of compressed stream)
  13. ; : DE=last dest address written+1 ( = initial destination address + length of decompressed stream)
  14. ; Clobbers: AF, AF', BC
  15. ; Changes:
  16. ; 1.1p1 137/ 92 bytes 11-06-2020 : Moved getbit_routine to bottom, some optimizations by uniabis.
  17. ; 1.1 156/112 bytes 10-06-2020 : Very tiny optimization; also optimizing for size saves 10 more bytes
  18. ; 1.0 157/122 bytes 09-06-2020 : Original version
  19. ; Set OPTIMIZE to either SPEED or SIZE.
  20. ; Optimizing for speed makes the getbit code be inlined, at the cost of
  21. ; decompressor memory (137 bytes as of this writing).
  22. ; Optimizing for size ( 92 bytes as of this writing) makes the code a bit
  23. ; slower due to the calls to getbit and the relative jumps.
  24. SIZE equ 0
  25. SPEED equ 1
  26. ; Change this to select what to optimize for
  27. IF !defined OPTIMIZE
  28. OPTIMIZE equ SPEED
  29. ENDIF
  30. getbit_code macro
  31. ; Get the next bit from the bitstream into the carry flag
  32. local gotbit
  33. srl b
  34. rr c
  35. ex af,af'
  36. dec a
  37. IF OPTIMIZE=SPEED
  38. jp nz,gotbit
  39. ELSE
  40. jr nz,gotbit
  41. initbits:
  42. ENDIF
  43. ld c,(hl)
  44. inc hl
  45. ld b,(hl)
  46. inc hl
  47. ld a,16
  48. gotbit:
  49. ex af,af'
  50. endm
  51. unlze proc
  52. IF OPTIMIZE=SPEED
  53. ; Optimize for speed
  54. getbit macro
  55. getbit_code
  56. endm
  57. j macro x
  58. jp x
  59. endm
  60. jc macro x,y
  61. jp x,y
  62. endm
  63. ELSE
  64. ; Optimize for size
  65. local getbit_routine
  66. getbit macro
  67. call getbit_routine
  68. endm
  69. j macro x
  70. jr x
  71. endm
  72. jc macro x,y
  73. jr x,y
  74. endm
  75. ENDIF
  76. local one_literal
  77. local mainloop
  78. local not_literal
  79. local copy_match
  80. local long_match
  81. local got_length
  82. local clean_up_and_loop
  83. local clean_up_and_ret
  84. local initbits
  85. IF OPTIMIZE=SPEED
  86. ld c,(hl)
  87. inc hl
  88. ld b,(hl)
  89. inc hl
  90. ld a,16
  91. ex af,af'
  92. ELSE
  93. call initbits
  94. ENDIF
  95. jr mainloop
  96. ; 1 = copy next byte verbatim
  97. one_literal: inc bc
  98. ldi
  99. ; Bitstream codes:
  100. ; 1 = copy next byte verbatim
  101. ; 00cc = next 2 bits are count reduced by 2,
  102. ; i.e. cc=00 represents 2 and cc=11 represents 5;
  103. ; the next byte is the offset in two's complement
  104. ; 01 = get little endian word from byte stream
  105. ; where the low byte is the lower 8 bits of the
  106. ; offset, and the high byte is encoded as follows:
  107. ; oooooxxx
  108. ; where ooooo are bits 8-12 of the offset
  109. ; and xxx is either length - 2 if nonzero,
  110. ; or 0 to read the next byte as an extended length
  111. ; or code. If that next code is 0, it means end of
  112. ; the stream. If that code is 1, it should be ignored
  113. ; (it's used for avoiding going off a segment in x86,
  114. ; so it can handle files > 64K). If that code is 2 or
  115. ; more, the actual length is the code + 1.
  116. mainloop: getbit
  117. jc c,one_literal
  118. not_literal: getbit
  119. jc c,long_match
  120. ; Short match
  121. xor a
  122. getbit
  123. rla
  124. getbit
  125. rla
  126. push bc
  127. push hl
  128. ld l,(hl) ; Offset in two's complement (always negative)
  129. ld h,-1
  130. ; Length-2 in A
  131. ; Offset in HL
  132. copy_match: add hl,de ; HL = DE + offset (offset is always negative)
  133. inc a
  134. ld c,a
  135. ld b,0
  136. ldir
  137. ldi
  138. pop hl
  139. clean_up_and_loop:
  140. inc hl
  141. pop bc
  142. j mainloop
  143. clean_up_and_ret:
  144. inc hl
  145. pop bc
  146. ret
  147. long_match: push bc
  148. ld c,(hl)
  149. inc hl
  150. ld a,(hl)
  151. ld b,a
  152. ; Carry is assumed to be set here! (saves 1 cycle)
  153. rr b
  154. sra b
  155. sra b
  156. and 7
  157. jc nz,got_length
  158. inc hl
  159. or (hl)
  160. ; Check special codes
  161. jr z,clean_up_and_ret ; less than 1, must be 0, exit
  162. dec a
  163. jr z,clean_up_and_loop ; equal to 1, ignore
  164. ; Actual lenght is A + 1, but we add 2 when falling through
  165. ; so we compensate here:
  166. ; Fall through
  167. got_length: ; Offset in BC
  168. push hl
  169. ld l,c
  170. ld h,b
  171. j copy_match
  172. IF OPTIMIZE=SPEED
  173. ELSE
  174. getbit_routine: getbit_code
  175. ret
  176. ENDIF
  177. endp