1 /*
2  * @file    ice68_pack.c
3  * @brief   Ice Packer 2.35 (native version)
4  * @author  http://sourceforge.net/users/benjihan
5  *
6  * Copyright (c) 1998-2015 Benjamin Gerard
7  *
8  * This  program is  free  software: you  can  redistribute it  and/or
9  * modify  it under the  terms of  the GNU  General Public  License as
10  * published by the Free Software  Foundation, either version 3 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
15  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
16  * General Public License for more details.
17  *
18  * You should have  received a copy of the  GNU General Public License
19  * along with this program.
20  * If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #ifndef PACKAGE_NAME
28 # define PACKAGE_NAME "unice68"
29 #endif
30 #ifndef PACKAGE_VERSION
31 # define PACKAGE_VERSION __DATE__
32 #endif
33 #ifndef PACKAGE_VERNUM
34 # define PACKAGE_VERNUM 0
35 #endif
36 
37 #include "unice68.h"
38 
39 #ifdef HAVE_STDINT_H
40 # include <stdint.h>
41 #endif
42 #ifdef HAVE_ASSERT_H
43 # include <assert.h>
44 #endif
45 
46 typedef uint8_t * areg_t;
47 typedef     int   dreg_t;
48 
49 typedef struct {
50   areg_t a0,a1,a2,a3,a4,a5,a6,ax;
51   dreg_t d0,d1,d2,d3,d4,d5,d6,d7;
52   areg_t srcbuf,srcend,dstbuf,dstend;
53   int srclen, dstlen, dstmax;
54   int error, optimize, maxlength, maxgleich, maxoffset;
55 } all_regs_t;
56 
57 #define ICE_MAGIC 0x49636521 /* 'Ice!' */
58 
59 #define EQ(A,B) ((A) == (B))
60 #define NE(A,B) ((A) != (B))
61 
62 #define GE(A,B) ((A) <= (B))
63 #define LE(A,B) ((A) >= (B))
64 #define HI(A,B) ((A) <  (B))
65 #define LS(A,B) ((A) >= (B))
66 #define GT(A,B) ((A) <  (B))
67 #define LT(A,B) ((A) >  (B))
68 
69 #define B_CC(CC, LABEL) if (CC) {goto LABEL;} else
70 #define DB_CC(CC, REG, LABEL) if (!(CC) && --REG >= 0) {goto LABEL;} else
71 #define DBF(REG,LABEL) DB_CC(0, REG, LABEL)
72 #define DBF_COUNT(REG) ( ( (REG) & 0xFFFF ) + 1 )
73 
74 #define BRA(LABEL) goto LABEL
75 #define BEQ(A, B, LABEL) B_CC( EQ(A,B), LABEL )
76 #define BNE(A, B, LABEL) B_CC( NE(A,B), LABEL )
77 #define BHI(A, B, LABEL) B_CC( HI(A,B), LABEL )
78 #define BGE(A, B, LABEL) B_CC( GE(A,B), LABEL )
79 #define BGT(A, B, LABEL) B_CC( GT(A,B), LABEL )
80 #define BLS(A, B, LABEL) B_CC( LS(A,B), LABEL )
81 #define BLE(A, B, LABEL) B_CC( LE(A,B), LABEL )
82 #define BLT(A, B, LABEL) B_CC( LT(A,B), LABEL )
83 
84 #define DBGE(A,B,REG,LABEL) DB_CC( GE(A,B), REG, LABEL )
85 
86 
87 static void longword_store(all_regs_t *R);
88 static void put_bits(all_regs_t * R);
89 static void make_stringlength(all_regs_t * R);
90 static void make_normal_bytes(all_regs_t * R);
91 
92 /* Store d7.l
93  */
longword_store(all_regs_t * R)94 static void longword_store(all_regs_t *R)
95 {
96   *R->a1++ = R->d7 >> 24;
97   *R->a1++ = R->d7 >> 16;
98   *R->a1++ = R->d7 >>  8;
99   *R->a1++ = R->d7;
100 }
101 
102 /* Store bit field
103  *
104  * d1[d4+1] bit field
105  * d7:      bit acu
106  * d6:      free bit in d7 minus 1
107  */
put_bits(all_regs_t * R)108 static void put_bits(all_regs_t *R)
109 {
110   assert(R->d7 >= 0 && R->d7 < 0x100);
111   assert(R->d4 >= 0 && R->d4 < 32);
112 
113   do {
114     R->d7 |= (R->d1 & 1) << 8;
115     R->d1 >>= 1;
116     R->d7 >>= 1;
117     if (--R->d6 < 0) {
118       *R->a1++ = R->d7;
119       R->d7 = 0;
120       R->d6 = 7;
121     }
122   } while (--R->d4 >= 0);
123 }
124 
125 
make_offset_2(all_regs_t * R)126 static void make_offset_2(all_regs_t * R)
127 {
128   /* move.w     d0,d1 */
129   R->d1 = R->d0;
130   /* cmpi.w     #$3f,d1 */
131   /* ble.s      offs_3f */
132   BLE ( 0x3f, R->d1, offs_3f );
133   /* subi.w     #$40,d1 */
134   R->d1 -= 0x40;
135   /* moveq      #9,d4 */
136   R->d4 = 9;
137   /* bset       d4,d1 */
138   R->d1 |= 1 << R->d4;
139   /* bra        put_bits */
140   goto put;
141 offs_3f:
142   /* moveq      #6,d4 */
143   R->d4 = 6;
144 put:
145   /* bra.s      put_bits */
146   put_bits(R);
147 }
148 
make_offset_mehr(all_regs_t * R)149 static void make_offset_mehr(all_regs_t * R)
150 {
151   static const int16_t table3[6] = {
152     0x0000,0x0020,0x0120,
153     0x0606,0x0908,0x0C0D
154   };
155   /* moveq        #2,d3 */
156   R->d3 = 2;
157 look_on:
158   /* add.w   d3,d3 */
159   /* move.w  0(a3,d3.w),d4 */
160   /* lsr.w   #1,d3 */
161   R->d4 = table3[R->d3];
162 
163   /* cmp.w   d4,d0 */
164   /* dbge    d3,look_on */
165   DBGE ( R->d4, R->d0, R->d3, look_on );
166   /* sub.w   d4,d0 */
167   R->d0 -= R->d4;
168 
169   /* add.w   d3,d3 */
170   /* move.w  6(a3,d3.w),d3 */
171   /* move.w  d3,d4 */
172   R->d4 = R->d3 = table3[3+R->d3];
173   /* lsr.w   #8,d3 */
174   R->d3 >>= 8;
175   /* moveq   #-1,d1 */
176   /* lsl.w   d3,d1 */
177   /* or.w    d0,d1 */
178   R->d1 = (-1 << R->d3) | R->d0;
179   /* andi.w  #$f,d4 */
180   R->d4 &= 0xf;
181   /* bra     put_bits */
182   put_bits(R);
183 }
184 
make_stringlength(all_regs_t * R)185 static void make_stringlength(all_regs_t *R)
186 {
187   static const int ta[5] = { 0x2, 0x3, 0x4, 0x6, 0xa };
188   static const int tb[5] = { 0x1, 0x1, 0x2, 0x3, 0xa };
189   int i, d4, d0;
190 
191   assert(R->maxlength >= 2);
192   for (i=4, d0 = R->maxlength;
193        d0 < (d4 = ta[i]);
194        --i);
195   d0 -= d4;
196   assert ( i >= 0 );
197   assert ( i <  5 );
198   d4 = tb[i];
199   R->d1 = (-1 << d4) | d0;
200   R->d4 = d4 + i - 1;
201   put_bits(R);
202 }
203 
ice_crunch(all_regs_t * R)204 static int ice_crunch(all_regs_t *R)
205 {
206   R->a0 = R->srcbuf;
207   R->d0 = R->srclen;
208 
209 mainloop:
210 
211 /***********************************************************************
212  * 1. Sequence of identical bytes are looking for pay
213  */
214 
215   /* lea        $409(a0),a4 */
216   R->a4 = R->a0 + 0x409;            /* a4 = End of the search range */
217   /* cmpa.l     src_ende,a4 */
218   /* ble.s      gleich_ok */
219   BLE ( R->srcend, R->a4, gleich_ok);
220   /* movea.l    src_ende,a4 */
221   R->a4 = R->srcend;
222 
223 gleich_ok:
224 /* a0 : search start
225  * a3 : search current
226  * a4 : search end
227  */
228 
229   /* move.l     a0,a3 */
230   R->a3 = R->a0;              /* a3 = Beginning of the search range */
231   /* move.b     (a3)+,d0 */
232   R->d0 = *R->a3++;                     /* current byte */
233 
234   /* while ( R->d0 == *R->a3++ && R->a3 < R->a4) */
235   /*   ; */
236 
237 gleich_compare:
238   /* cmp.b      (a3)+,d0 */
239   /* bne.s      gleich_ende */
240   BNE( *R->a3++, R->d0, gleich_ende );
241   /* cmpa.l     a4,a3 */
242   /* blt.s      gleich_compare */
243   BLT ( R->a4, R->a3, gleich_compare );
244 gleich_ende:
245 
246   /* move.l     a3,d1 */
247   /* sub.l      a0,d1 */
248   /* subq.l     #2,d1 */
249   /* move.l     d1,maxgleich */
250   R->maxgleich = R->d1 = R->a3 - R->a0 - 2;
251 
252   /* cmp.l      #$409,d1 */
253   /* beq        gleich_ablegen */
254   BEQ (0x409, R->d1, gleich_ablegen);
255 
256 
257 /*************************************************************
258  * 2. Search string with the greatest possible length and a small offset
259  */
260 
261   /* move.l     a0,a3 */
262   /* adda.l     optimize(pc),a3 */
263   R->a3 = R->a0 + R->optimize;
264   /* cmpa.l     src_ende,a3 */
265   /* ble.s      offset_ende */
266   BLE ( R->srcend, R->a3, offset_ende );
267   /* movea.l    src_ende,a3 */
268   R->a3 = R->srcend;
269 
270 offset_ende:
271   /* if (R->a3 > R->srcend) */
272   /*   R->a3 = R->srcend; */
273 
274   /* moveq      #1,d4 */
275   R->d4 = 1;
276   /* lea        2(a0),a4 */
277   R->a4 = R->a0 + 2;
278 
279 weiter_mit_string:
280   /* move.b     (a0),d0 */
281   R->d0 = *R->a0;
282   /* move.b     1(a0),d1 */
283   R->d1 = R->a0[1];
284 
285 search_string:
286   /* cmp.b      (a4)+,d0 */
287   /* beq.s      ein_byte_stimmt */
288   BEQ ( *R->a4++, R->d0, ein_byte_stimmt );
289 
290 no_string:
291   /* cmpa.l     a4,a3 */
292   /* bgt.s      search_string */
293   BGT ( R->a4, R->a3, search_string );
294   /* bra.s      string_suche_fertig */
295   BRA(string_suche_fertig);
296 
297 ein_byte_stimmt:
298   /* cmp.b      (a4),d1 */
299   /* bne.s      no_string */
300   BNE ( *R->a4, R->d1, no_string );
301 
302 /* string_start_found: */
303   /* move.l     a4,a6 */
304   /* subq.w     #1,a6 */
305   R->a6 = R->a4 - 1;
306   /* move.l     a6,d0 */
307   R->ax = R->a6;
308   /* movea.l    a0,a5 */
309   R->a5 = R->a0;
310 
311 string_compare:
312   /* cmpm.b     (a5)+,(a6)+ */
313   /* bne.s      string_zu_ende */
314   BNE ( *R->a5++, *R->a6++, string_zu_ende);
315   /* cmp.l      d0,a5 */
316   /* bhi.s      string_zu_ende */
317   BHI( R->ax, R->a5, string_zu_ende );
318   /* cmpa.l     a6,a3 */
319   /* bgt.s      string_compare */
320   BGT ( R->a6, R->a3, string_compare );
321 
322 string_zu_ende:
323   /* move.l     a5,d1 */
324   /* sub.l      a0,d1 */
325   /* subq.l     #1,d1 */
326   R->d1 = R->a5 - R->a0 - 1;
327 
328   /* move.l     a6,d2 */
329   /* sub.l      a5,d2 */
330   /* sub.l      d1,d2 */
331   /* addq.l     #1,d2 */
332   R->d2 = R->a6 - R->a5 - R->d1 + 1;
333 
334   /* move.l     #$409,d0 */
335   R->d0 = 0x409;                        /* max string length */
336 
337   /* cmp.l      d0,d4 */
338   /* beq.s      string_suche_fertig */
339   BEQ ( R->d0, R->d4, string_suche_fertig );
340 
341   /* cmp.l      d0,d1 */
342   /* bls.s      not_too_large */
343   BLS ( R->d0, R->d1, not_too_large );
344 
345   /* sub.l      d0,d1 */
346   R->d1 -= R->d0;
347   /* add.l      d1,d2 */
348   R->d2 += R->d1;
349 
350   /* move.l     d0,d1 */
351   R->d1  = R->d0;
352 not_too_large:
353 
354   /* cmp.l      d1,d4 */
355   /* bge.s      string_lohnt_nicht */
356   BGE( R->d1, R->d4, string_lohnt_nicht );
357   /* cmp.w      #2,d1 */
358   /* bls.s      shortstring */
359   BLS ( 2, R->d1, shortstring );
360   /* cmp.w      #$111f,d2 */
361   /* bhi.s      string_lohnt_nicht */
362   BHI ( 0x111f, R->d2, string_lohnt_nicht );
363 
364 shortstring:
365   /* move.l     d1,d4 */
366   /* move.w     d1,maxlength */
367   /* move.w     d2,maxoffset */
368   R->maxlength = R->d4 = R->d1;
369   R->maxoffset = R->d2;
370 
371 string_lohnt_nicht:
372   /* cmpa.l     a4,a3 */
373   /* bgt        weiter_mit_string */
374   BGT ( R->a4, R->a3, weiter_mit_string );
375 
376 string_suche_fertig:
377   /* move.l     maxgleich,d0 */
378   R->d0 = R->maxgleich;
379   /* cmp.w      #1,d0 */
380   /* ble.s      nogleich */
381   BLE ( 1, R->d0, nogleich );
382   /* cmp.l      d4,d0 */
383   /* bge.s      gleich_ablegen */
384   BGE( R->d4, R->d0, gleich_ablegen );
385 
386 nogleich:
387 
388   /* move.w     maxoffset(pc),d0 */
389   R->d0 = R->maxoffset;
390   /* move.w     d4,d1 */
391   R->d1 = R->d4;
392   /* cmpi.w     #1,d1 */
393   /* beq.s      ein_byte_ablegen */
394   BEQ ( 1, R->d1, ein_byte_ablegen );
395   /* cmpi.w     #2,d1 */
396   /* beq.s      zwei_byte_ablegen */
397   BEQ ( 2, R->d1, zwei_byte_ablegen );
398   /* bra.s      mehr_bytes_ablegen */
399   BRA(mehr_bytes_ablegen);
400 
401 /* ====================================================================== */
402 
403 ein_byte_ablegen:
404   /* move.b     (a0)+,(a1)+ */
405 
406   /* fprintf(stdout,"%04x %02x (%s:%d) / ein_byte_ablegen\n", */
407   /*         R->a1 - R->dstbuf, */
408   /*         *R->a0, */
409   /*         __FUNCTION__, __LINE__); */
410   *R->a1++ = *R->a0++;
411   /* addq.l     #1,d5 */
412   R->d5++;
413   /* bra.s      kein_byte_ablegen */
414   BRA ( kein_byte_ablegen );
415 
416 gleich_ablegen:
417   /* move.l     maxgleich,d1 */
418   R->d1 = R->maxgleich;
419   /* move.w     d1,maxlength */
420   R->maxlength = R->d1;
421   /* moveq      #0,d0 */
422   R->d0 = 0;
423   /* subq.l     #2,d1 */
424   /* bne.s      mehr_bytes_ablegen */
425   if ( (R->d1 -= 2) != 0 )
426     goto mehr_bytes_ablegen;
427 
428 zwei_byte_ablegen:
429   /* cmpi.w     #$23f,d0 */
430   /* bhi.s      ein_byte_ablegen */
431   BHI( 0x23f, R->d0, ein_byte_ablegen );
432   /* bsr        make_normal_bytes */
433   make_normal_bytes(R);
434   /* cmpi.w     #$23f,d0 */
435   /* bhi        ein_byte_ablegen */
436   BHI( 0x23f, R->d0, ein_byte_ablegen );
437   /* bsr        make_offset_2 */
438   make_offset_2(R);
439   /* bra.s      drop_length */
440   BRA(drop_length);
441 
442 mehr_bytes_ablegen:
443   /* bsr        make_normal_bytes */
444   make_normal_bytes(R);
445   /* bsr        make_offset_mehr */
446   make_offset_mehr(R);
447 
448 drop_length:
449   /* bsr        make_stringlength */
450   make_stringlength(R);
451   /* moveq      #0,d5 */
452   R->d5 = 0;
453   /* move.w     maxlength(pc),d0 */
454   R->d0 = R->maxlength;
455   /* add.w      d0,a0 */
456   R->a0 += R->d0;
457 
458 kein_byte_ablegen:
459   /* move.l     src_ende,d0 */
460   /* sub.l      a0,d0 */
461   /* subq.l     #3,d0 */
462   /* bpl        mainloop */
463   if ( ( R->d0 = R->srcend - R->a0 - 3 ) >= 0 )
464     goto mainloop;
465 
466 still_packing:
467   /* cmp.l      src_ende,a0 */
468   /* bge.s      all_packed */
469   BGE ( R->srcend, R->a0, all_packed );
470   /* move.b     (a0)+,(a1)+ */
471   /* fprintf(stdout,"%04x %02x (%s:%d) / still_packing\n", */
472   /*         R->a1 - R->dstbuf, */
473   /*         *R->a0, */
474   /*         __FUNCTION__ , __LINE__); */
475   *R->a1++ = *R->a0++;
476   /* addq.l     #1,d5 */
477   R->d5++;
478   /* bra.s      still_packing */
479   BRA(still_packing);
480 
481 all_packed:
482   /* bsr        make_normal_bytes */
483   make_normal_bytes(R);
484   /* bset       d6,d7 */
485   /* move.b     d7,(a1)+ */
486 
487   /* fprintf(stdout,"%04x %02x (%s:%d) /all_packed\n", */
488   /*         R->a1 - R->dstbuf, */
489   /*         R->d7 | (1 << R->d6), */
490   /*         __FUNCTION__ , __LINE__); */
491   *R->a1++ = R->d7 |= (1 << R->d6);
492   /* sub.l   packed_data(pc),a1 */
493   /* move.l  a1,d0 */
494   /* move.l  d0,d7 */
495   R->d7 = R->d0 = R->a1 - R->dstbuf;
496   /* move.l  packed_data,a1 */
497   /* addq.l  #4,a1 */
498   /* bsr     longword_store */
499   R->a1 = R->dstbuf + 4;
500   longword_store(R);
501   /* rts */
502   return R->d0;
503 }
504 
make_normal_bytes(all_regs_t * R)505 static void make_normal_bytes(all_regs_t * R)
506 {
507   static const int t1a[7] = { 0, 1, 2, 5, 8, 15, 270 };
508 
509   static const int tib[7][2] = {
510     { 0x01,0x01 }, { 0x01, 0x02 }, { 0x02, 0x04 }, { 0x02, 0x06 },
511     { 0x03,0x09 }, { 0x08, 0x11 }, { 0x0f, 0x20 }
512   };
513 
514   /* cmp.l      #$810d,d5 */
515   /* bls.s      noerror */
516   BLS ( 0x810d, R->d5, noerror );
517 
518   /* move.w     #-1,error */
519   /* move.l     a0,src_ende */
520   R->error = -1;
521   R->srcend = R->a0;
522 noerror:
523 
524   /* lea.l      table1(pc),a3 */
525   /* moveq      #6,d3 */
526   R->d3 = 6;
527 kleiner:
528   /* move.w     -(a3),d4 */
529 
530   assert (R->d3 >= 0);
531   assert (R->d3 <  7);
532   R->d4 = t1a[R->d3];
533   /* cmp.w      d4,d5 */
534   /* dbge       d3,kleiner */
535   DBGE ( R->d4, R->d5, R->d3, kleiner );
536   /* sub.w      d4,d5 */
537   R->d5 -= R->d4;
538 
539   assert (R->d3 >= 0);
540   assert (R->d3 <  7);
541 
542   R->d2 = tib[R->d3][0];
543   /* moveq      #-1,d1 */
544   /* lsl.l      d2,d1 */
545   /* or.w       d5,d1 */
546   R->d1 = (-1 << R->d2) | R->d5;
547   /* moveq      #0,d5 */
548   R->d5 = 0;
549   /* move.b     (a3)+,d4 */
550   /* ext.w      d4 */
551   /* subq.w     #1,d4 */
552   R->d4 = tib[R->d3][1] - 1;
553   /* bra        put_bits */
554   put_bits(R);
555 }
556 
unice68_packer(void * dst,int dstsz,const void * src,int srcsz)557 int unice68_packer(void * dst, int dstsz, const void * src, int srcsz)
558 {
559   all_regs_t allregs, *R = &allregs;
560 
561 
562   /***********************************************************************
563    * Save parameters
564    */
565   R->srcbuf = (areg_t) src;
566   R->srcend = R->srcbuf + srcsz;
567   R->srclen = srcsz;
568   R->dstbuf = (areg_t) dst;
569   R->dstend = R->dstbuf + dstsz;
570   R->dstlen = 0;
571   R->dstmax = dstsz;
572 
573   R->a0 = R->srcbuf;
574   R->d0 = R->srclen;
575   R->a1 = R->dstbuf;
576 
577   R->a2 = R->a3 = R->a4 = R->a5 = R->a6 = 0;
578 
579   R->error     = 0;
580   R->optimize  = 0x1580;
581   R->maxlength = 0;
582   R->maxgleich = 0;
583   R->maxoffset = 0;
584 
585   /***********************************************************************
586    * Store header
587    */
588 
589   /* move.l  #'Ice!',d7 */
590   /* bsr     longword_store */
591   /* addq.l  #4,a1 */
592   /* move.l  filesize(pc),d7 */
593   /* bsr     longword_store */
594 
595   R->d7 = ICE_MAGIC;               /* Store magic id 'Ice!'         */
596   longword_store(R);
597   R->a1 += 4;                      /* Leave space for packed length */
598   R->d7 = R->srclen;               /* Store unpacked length         */
599   longword_store(R);
600 
601   /* moveq   #0,d5 */
602   /* moveq   #0,d7 */
603   /* moveq   #0,d4 */
604   /* moveq   #0,d1 */
605   R->d1 = R->d2 = R->d3 = R->d4 = R->d5 = R->d7 = 0;
606   /* moveq   #7,d6 */
607   R->d6 = 7;
608   /* bsr     put_bits */
609 
610   /* Store one bit for picture flag */
611   put_bits(R);
612 
613 
614   /* Main loop */
615   ice_crunch(R);
616 
617   if (R->error)
618     R->d0 = -1;
619 
620   return R->d0;
621 }
622