unpack.asm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. ;-----------------------------------------------------------------------
  2. ;INTRODUCTION:
  3. ;
  4. ; This is a 100% assembly version of the ttunpack routine, which is
  5. ; based on code by Pasi 'Albert' Ojala, albert@cs.tut.fi, then
  6. ; reduced by Thomas Nussbaumer to fit his needs. For a full details
  7. ; on the algorithm see:
  8. ;
  9. ; http://www.cs.tut.fi/~albert/Dev/pucrunch/index.html
  10. ;
  11. ; Version: 2.33 Super Small, Improper Return Value
  12. ; Requires even alignment
  13. ; Register Parameters, a0 -> dest, a3 -> source
  14. ; Removed optional delta_lz code
  15. ; Fixed a bug in header error checks
  16. ;
  17. ;THE LICENSE:
  18. ;
  19. ; Copyright (C) 2004-2005 Samuel Stearley
  20. ;
  21. ; wxWindows Library Licence, Version 3.1
  22. ; ======================================
  23. ;
  24. ; Copyright (C) 1998-2005 Julian Smart, Robert Roebling et al
  25. ;
  26. ; Everyone is permitted to copy and distribute verbatim copies
  27. ; of this licence document, but changing it is not allowed.
  28. ;
  29. ; WXWINDOWS LIBRARY LICENCE
  30. ; TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  31. ;
  32. ; This library is free software; you can redistribute it and/or modify it
  33. ; under the terms of the GNU Library General Public Licence as published by
  34. ; the Free Software Foundation; either version 2 of the Licence, or (at
  35. ; your option) any later version.
  36. ;
  37. ; This library is distributed in the hope that it will be useful, but
  38. ; WITHOUT ANY WARRANTY; without even the implied warranty of
  39. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
  40. ; General Public Licence for more details.
  41. ;
  42. ; You should have received a copy of the GNU Library General Public Licence
  43. ; along with this software, usually in a file named COPYING.LIB. If not,
  44. ; write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  45. ; Boston, MA 02111-1307 USA.
  46. ;
  47. ; EXCEPTION NOTICE
  48. ;
  49. ; 1. As a special exception, the copyright holders of this library give
  50. ; permission for additional uses of the text contained in this release of
  51. ; the library as licenced under the wxWindows Library Licence, applying
  52. ; either version 3.1 of the Licence, or (at your option) any later version of
  53. ; the Licence as published by the copyright holders of version
  54. ; 3.1 of the Licence document.
  55. ;
  56. ; 2. The exception is that you may use, copy, link, modify and distribute
  57. ; under your own terms, binary object code versions of works based
  58. ; on the Library.
  59. ;
  60. ; 3. If you copy code from files distributed under the terms of the GNU
  61. ; General Public Licence or the GNU Library General Public Licence into a
  62. ; copy of this library, as this licence permits, the exception does not
  63. ; apply to the code that you add in this way. To avoid misleading anyone as
  64. ; to the status of such modified files, you must delete this exception
  65. ; notice from such code and/or adjust the licensing conditions notice
  66. ; accordingly.
  67. ;
  68. ; 4. If you write modifications of your own for this library, it is your
  69. ; choice whether to permit this exception to apply to your modifications.
  70. ; If you do not wish that, you must delete the exception notice from such
  71. ; code and/or adjust the licensing conditions notice accordingly.
  72. ;
  73. ;
  74. ;NOTES:
  75. ;
  76. ;1) There were several other names associated with this, but not
  77. ; anymore ;)
  78. ;
  79. ;
  80. ;2) The code was written with wordpad. It might look better if
  81. ; opened with that program.
  82. ;
  83. ;
  84. ;3) A version of this is included as a hex array for use with programs
  85. ; written with tigcc. OR you can use this file directly with a
  86. ; tigcc project: add it to the project and remove the ';' from
  87. ; before the 'CALL_DIRECTLY' below. Be sure to have the latest
  88. ; version of tigcc when doing this.
  89. ;----------------------------------------------------------------------
  90. ;CALL_DIRECTLY ;if this label is defined then this code can be used
  91. ; directly as part of a tigcc project.
  92. ifd CALL_DIRECTLY
  93. public ttunpack_decompress
  94. endc
  95. ifnd CALL_DIRECTLY
  96. include "os.h"
  97. xdef _ti89
  98. xdef _nostub
  99. endc
  100. ;------------------------------------------------------------------
  101. ;The data structure defines and error return values
  102. ;------------------------------------------------------------------
  103. osize_lo equ 0 ;original size lowbyte
  104. osize_hi equ 1 ;original size highbyte
  105. magic1 equ 2 ;must be equal to UNPACK_MAGIC1
  106. magic2 equ 3 ;must be equal to UNPACK_MAGIC2
  107. csize_lo equ 4 ;compressed size lowbyte
  108. csize_hi equ 5 ;compressed size lowbyte
  109. esc1 equ 6 ;escape >> (8-escBits)
  110. notused3 equ 7 ;
  111. notused4 equ 8 ;
  112. esc2 equ 9 ;escBits
  113. gamma1 equ 10 ;maxGamma + 1
  114. gamma2 equ 11 ;(1<<maxGamma)
  115. extralz equ 12 ;extraLZPosBits
  116. notused1 equ 13 ;
  117. notused2 equ 14 ;
  118. rleentries equ 15 ;rleUsed
  119. HEADER_SIZE equ 16
  120. __MAGIC_CHAR1 equ $54
  121. __MAGIC_CHAR2 equ $50
  122. __ERRPCK_OKAY equ 0
  123. __ERRPCK_NOESCFOUND equ 8 ;248
  124. __ERRPCK_ESCBITS equ 7 ;249
  125. __ERRPCK_MAXGAMMA equ 6 ;250
  126. __ERRPCK_EXTRALZP equ 5 ;251
  127. __ERRPCK_NOMAGIC equ 4 ;252
  128. __ERRPCK_OUTBUFOVERRUN equ 3 ;253
  129. __ERRPCK_LZPOSUNDERRUN equ 2 ;254
  130. ;-----------------------------------------------------------------------
  131. ;Notes on register useage, might be good Idea to print this.
  132. ;
  133. ; a0 => Input: The destination buffer
  134. ; a1 => Points to the next byte of the compressed data.
  135. ; udated when d7 overflows.
  136. ; a2 => NOT USED
  137. ; a3 => Input: The source data
  138. ; Used during error checking, will point to extralz bits
  139. ; Used to access 'bytecodevec' table
  140. ; a4 => NOT USED
  141. ; a5 => NOT USED
  142. ; a6 => NOT USED
  143. ;
  144. ; d0 => Trashing, output of __GetBits and __GetValue
  145. ; d1 => Trashing, input to __GetBits
  146. ; d2 => Trashing by __GetValue
  147. ; d3 => Trashing but only by the main routine, not the subroutines
  148. ; d4 => # of escape bits
  149. ; d5 => Start escape
  150. ; d6 => Current byte of data.
  151. ; d7 => Which bit we are at in the compressed data.
  152. ;
  153. ;-----------------------------------------------------------------------
  154. ttunpack_decompress:
  155. ifnd CALL_DIRECTLY
  156. dc.b "UNPACK_0"
  157. endc
  158. movem.l d3-d7/a2-a6,-(a7)
  159. ; move.l 4+10*4(a7),a3
  160. ; move.l 8+10*4(a7),a0
  161. ;--------------------------------------------------------
  162. ; startesc = cth->esc1; //d5
  163. ; bytecodevec = &src[15]; //a3
  164. ; __imask__ = 0x80; //d7
  165. ;
  166. ;These are initialized here to insure that certain
  167. ;branches can use the short form.
  168. ;--------------------------------------------------------
  169. move.b esc1(a3),d5 ;'StartEsc'
  170. moveq #-128,d7 ;which bit i am at.
  171. ;-------------------------------------------------------------------------------------------------
  172. ; if (cth->magic1 != __MAGIC_CHAR1 || cth->magic2 != __MAGIC_CHAR2) return __ERRPCK_NOMAGIC;
  173. ; if (cth->gamma1 != 8 || cth->gamma2 != 128) return __ERRPCK_MAXGAMMA;
  174. ; if ((escbits = cth->esc2) > 8) return __ERRPCK_ESCBITS;
  175. ; if ((extralzposbits = cth->extralz) > 4) return __ERRPCK_EXTRALZP;
  176. ;-------------------------------------------------------------------------------------------------
  177. moveq #8,d0 ;code for error is non-zero
  178. addq.l #2,a3
  179. cmp.w #__MAGIC_CHAR1*256+__MAGIC_CHAR2,(a3)+
  180. bne.s __ReturnError
  181. addq.l #5,a3 ;point to esc2
  182. move.b (a3)+,d4 ;get esc2 and point to gamma1
  183. cmp.b d0,d4
  184. bhi.s __ReturnError
  185. cmp.w #8*256+128,(a3)+ ;gamma1 = 8 and gamma2 = 128?
  186. bne.s __ReturnError
  187. ;--------------------------------------------------------
  188. ; __ibuffer__ = src + sizeof(__PACKHEADER) + cth->rleentries; //a1
  189. ;--------------------------------------------------------
  190. add.b 3(a3),d0 ;upper bytes of d0.l = 0, add (not load) in case a3 points to a zero
  191. lea 4-8(a3,d0.l),a1 ; because d0 is the error code must not be zero.
  192. cmp.b #5,(a3)
  193. bcs.s __DecompressLoop ;jump into the loop if 4..0
  194. ;---------------------------------------------------------
  195. ;And when all is done branch here
  196. ; If success d0 will be zero
  197. ;---------------------------------------------------------
  198. __ReturnError:
  199. __WeAreDone:
  200. movem.l (a7)+,d3-d7/a2-a6
  201. rts
  202. ;-----------------------------------------------------------------
  203. ; newesc = __GetBits(escbits);
  204. ; *outbuffer++ = (startesc<<escbits8) | __GetBits(escbits8);
  205. ; startesc = newesc;
  206. ; continue;
  207. ;-----------------------------------------------------------------
  208. __NextBitIsClear_EscapeFromEscape:
  209. bsr.s __GetBits_D4Input ;d0 is 'newesc'
  210. exg d0,d5 ;'startesc' = 'newesc'; and d0 = OLD_startesc
  211. ;---------------------------------------------------------
  212. ; *outbuffer++ = (sel<<escbits8) | __GetBits(escbits8);
  213. ; continue;
  214. ;---------------------------------------------------------
  215. __SelIsNOTStartEscape:
  216. moveq #8,d1
  217. sub.b d4,d1 ;'escbits8'
  218. bsr.s __GetBits_D0_IS_Loaded_For_Shifting
  219. move.b d0,(a0)+
  220. ;---------------------------------------------------------
  221. ;The while(1) loop, just a label ;)
  222. ;---------------------------------------------------------
  223. __DecompressLoop:
  224. ;---------------------------------------------------------
  225. ; sel = (escbits) ? __GetBits(escbits) : startesc;
  226. ; if (sel == startesc) {
  227. ;---------------------------------------------------------
  228. bsr.s __GetBits_D4Input ;get the bits, input is in d4
  229. cmp.b d5,d0 ;did __getBits return 'startesc' into 'sel'?
  230. bne.s __SelIsNOTStartEscape
  231. ;---------------------------------------------------------
  232. ;The following code is entered if sel = start escape
  233. ;but it does not actually use the sel variable
  234. ;
  235. ; lzlen = __GetValue();
  236. ; if (lzlen != 1) {
  237. ;---------------------------------------------------------
  238. __SelIsStartEscape:
  239. bsr.s __GetValue ;get a value for 'lzlen', d1 will be negative from above __GetBits
  240. ; as a side effect d1 will be negative
  241. move.w d0,d3 ;save 'lzlen'
  242. subq.w #1,d0 ;does 'lzlen' == 1 ?
  243. beq.s __RleDecoding ;this destination requires d0 = 0
  244. ;---------------------------------------------------------
  245. ;Zip decoding
  246. ;
  247. ; lzposhi = __GetValue() - 1;
  248. ; if (lzposhi == 254) {
  249. ;---------------------------------------------------------
  250. bsr.s __GetValue ;if it equals 254, then lzlen must be > 3 because
  251. addq.b #1,d0 ; there is no other possiblity because Delta decompression
  252. beq.s __WeAreDone ; is not being used. It the branch is not taken it
  253. ; drops through to the __LzPosHi_IsNot254
  254. ; This __GetValue relies on d1 = negative from above __GetValue
  255. ;----------------------------------------------------------------------------------------
  256. ; if (extralzposbits) lzposhi = (lzposhi<<extralzposbits) | __GetBits(extralzposbits);
  257. ; lzposlo = __Get8Bit() ^ 0xff;
  258. ; lzpos = COMBINE_LOWHIGH(lzposlo,lzposhi);
  259. ;
  260. ; d0= lzPosHi, d3.w = lzlen, d2.l =lzpos
  261. ;----------------------------------------------------------------------------------------
  262. __LzPosHi_IsNot254:
  263. subq.b #2,d0 ;undo the addq.b #1 and do the subtract that wasn't done
  264. move.b (a3),d1 ;get 'extralzposbits'
  265. bsr.s __GetBits_D0_IS_Loaded_For_Shifting
  266. __NextBitClear_DoZipAfterAll: ;to jump here be sure that d0.l = 0
  267. moveq #7,d1
  268. bsr.s __GetBits_D0_IS_Loaded_For_Shifting_D1_is_not_Variable
  269. ;-----------------------------------------------------------------------------------
  270. ; for (i=0; i<=lzlen; i++) {
  271. ; *outbuffer = *(outbuffer - lzpos - 1); //no 'add' variable
  272. ; outbuffer++;
  273. ; }
  274. ;
  275. ; d0.l must be lzpos
  276. ; d3.w must be lzlen
  277. ;------------------------------------------------------------------------------------
  278. not.b d0
  279. neg.l d0
  280. __WriteDataLoop:
  281. move.b -1(a0,d0.l),(a0)+ ;18 cycles
  282. __UseZipCopyLoop: ;entrance for the rle code
  283. dbra d3,__WriteDataLoop
  284. bra.s __DecompressLoop ;continue
  285. ;-------------------------------------------------------------
  286. ; __GetValue returns an 8 bit value in d0.l It can be used
  287. ; as an:
  288. ; unsigned character
  289. ; unsigned short
  290. ; unsigned long
  291. ;
  292. ; __GetBits takes as its input d1.b, returns a value in d0.w
  293. ; There is a limit on it being 16 bit output. With the
  294. ; upper bits being 0 so it can be used as an:
  295. ; unsigned character, if 8 bits or less are requested.
  296. ; unsigned short
  297. ; unsigned long
  298. ;
  299. ; __GetBits has two other entrances, that assume a value in d0
  300. ; is ready to be shifted up as bits are shifted in. This is
  301. ; limited to 16 bit values, with no guarantee about the upper
  302. ; bits.
  303. ;
  304. ; '__GetBits_D0_IS_Loaded_For_Shifting_D1_is_not_Variable' is
  305. ; used when there is no possiblity that the input is 0. For
  306. ; example: __getBits(3)
  307. ;
  308. ;--------------------------------------------------------------
  309. __GetBits_D4Input:
  310. move.b d4,d1
  311. __GetBits:
  312. moveq #0,d0
  313. bra.s __IntoLoop
  314. __GetBits_D0_IS_Loaded_For_Shifting_D1_is_not_Variable:
  315. __inl_loop0:
  316. __CheckBitProceed: ;to call this like the old 'CheckBitProceed' make sure d1 = negative
  317. rol.b #1,d7
  318. bcc.s __NotInNext
  319. move.b (a1)+,d6
  320. __NotInNext:
  321. add.b d6,d6
  322. addx.w d0,d0
  323. __GetBits_D0_IS_Loaded_For_Shifting:
  324. __IntoLoop:
  325. subq.b #1,d1 ;must be byte valued, if d1.b = negative then drop through
  326. bpl.s __inl_loop0
  327. move d0,ccr ;put the last bit into the carry flag.
  328. rts
  329. __GetValue:
  330. moveq #6,d2
  331. __inl_loop1:
  332. bsr.s __CheckBitProceed
  333. dbcc d2,__inl_loop1
  334. moveq #6,d1
  335. sub.w d2,d1
  336. moveq #1,d0
  337. bra.s __GetBits_D0_IS_Loaded_For_Shifting
  338. ;---------------------------------------------------------
  339. ;RLE decoding
  340. ;---------------------------------------------------------
  341. __RleDecoding: ;important! at this point d0=0 and d1 = -1
  342. bsr.s __CheckBitProceed ;will modify d0 if the bit is set
  343. bcc.s __NextBitClear_DoZipAfterAll ;if it branches d0 is still 0, the destination requires this!
  344. bsr.s __CheckBitProceed
  345. bcc.s __NextBitIsClear_EscapeFromEscape
  346. ;-----------------------------------------------------------------
  347. ; rlelen = __GetValue();
  348. ; if (rlelen >= 128) {
  349. ; rlelen = ((rlelen-128)<<1) | __GetBits(1);
  350. ; rlelen |= (((__GetValue())-1)<<8);
  351. ; }
  352. ;------------------------------------------------------------------
  353. __NextBitIsSet_RunLengthEncoding:
  354. bsr.s __GetValue ;get 'rlelen' into d0, limited to 8 bit values. d1 = is still negative!
  355. ; it gets the value and d1 is negative again
  356. move.b d0,d3 ;copy it and check sign bit to see if >= 128
  357. bpl.s __LessThan128
  358. bsr.s __CheckBitProceed ;__getBits(1), important d1 is negative
  359. move.w d0,-(a7)
  360. bsr.s __GetValue ;relies on d1 being negative ! Satisfied by above __GetValue
  361. subq.b #1,d0
  362. move.b d0,(a7) ;overwrites the high bit that is should be cleared by
  363. move.w (a7)+,d3 ; by the rlelen-128
  364. ;-------------------------------------------------------------------
  365. ;Need the byte to copy
  366. ;
  367. ; bytecode = __GetValue();
  368. ; if (bytecode < 32) byte = bytecodevec[bytecode];
  369. ; else byte = ((bytecode-32)<<3) | __GetBits(3);
  370. ;-------------------------------------------------------------------
  371. __LessThan128:
  372. bsr.s __GetValue ;get 'bytecode'
  373. subq.b #2,d2 ;d2= (6- # of bits retireved) jump if 5 ,6, or 7
  374. bmi.s __GreaterThanOrEqual32 ; bits retrieved means that it is >= 32
  375. move.b 3(a3,d0.w),d0 ;byte = bytecodevec[bytecode];
  376. bra.s __RleCopy
  377. __GreaterThanOrEqual32:
  378. moveq #2,d1
  379. bsr.s __GetBits_D0_IS_Loaded_For_Shifting_D1_is_not_Variable
  380. ;--------------------------------------------------------
  381. ; for (i=0; i<=rlelen; i++) *outbuffer++ = byte;
  382. ; continue; // continue the main loop ...
  383. ;
  384. ;Rle loop expects
  385. ; d0 = byte
  386. ; d3 = number of em to copy, no need to subtract 1 for
  387. ; dbra
  388. ;--------------------------------------------------------
  389. __RleCopy:
  390. move.b d0,(a0)+
  391. moveq #0,d0
  392. bra.s __UseZipCopyLoop
  393. ifnd CALL_DIRECTLY
  394. dc.b "UNPACK_1"
  395. endc