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