summaryrefslogtreecommitdiff
path: root/cesar/mac/pbproc/src/sacki_dec.c
blob: f67124bcb5dba500d0f90e8de698ed2e087a102d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* Cesar project {{{
 *
 * Copyright (C) 2007 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    sacki_dec.c
 * \brief   SACKI decompression.
 * \ingroup mac_pbproc
 */
#include "common/std.h"

#include "inc/sacki_dec.h"

#include "hal/arch/arch.h"

#include "pbproc_sacki_dec_tables.h"

#ifdef PBPROC_SACKI_DEC_DEBUG
# undef PBPROC_SACKI_DEC_DEBUG
void
pbproc_sacki_dec_debug (uint eat, uint prod, uint nok0, uint nok1, uint nok2);
# define PBPROC_SACKI_DEC_DEBUG(eat, prod, nok0, nok1, nok2) \
    pbproc_sacki_dec_debug ((eat), (prod), (nok0), (nok1), (nok2))
#else
# define PBPROC_SACKI_DEC_DEBUG(eat, prod, nok0, nok1, nok2)
#endif

uint ARCH_ILRAM
pbproc_sacki_dec_process (u32 si[3], uint sil, uint pbl,
                          void *user, pbproc_sacki_dec_nok_cb_t nok_cb)
{
    uint pbs;
    u32 si0, si1, si2;
    /* Load cache. */
    si0 = si[0];
    si1 = si[1];
    si2 = si[2];
    /* Fast decompression. */
    pbs = 0;
    while (sil >= 8)
    {
        /* Lookup. */
        uint eat = sack_dec_fast[si0 & 0xff].eat;
        uint prod = sack_dec_fast[si0 & 0xff].prod;
        if (prod > pbl)
            break;
        uint nok0 = sack_dec_fast[si0 & 0xff].nok0;
        uint nok1 = sack_dec_fast[si0 & 0xff].nok1;
        uint nok2 = sack_dec_fast[si0 & 0xff].nok2;
        PBPROC_SACKI_DEC_DEBUG (eat, prod, nok0, nok1, nok2);
        /* Call callback. */
        if (nok0 != SACK_DEC_FAST_NOK_UNDEF)
        {
            nok_cb (user, pbs + nok0, 1);
            if (nok1 != SACK_DEC_FAST_NOK_UNDEF)
            {
                nok_cb (user, pbs + nok1, 1);
                if (nok2 != SACK_DEC_FAST_NOK_UNDEF)
                {
                    nok_cb (user, pbs + nok2, 1);
                }
            }
        }
        /* Advance. */
        si0 = si1 << (32 - eat) | si0 >> eat;
        si1 = si2 << (32 - eat) | si1 >> eat;
        si2 = si2 >> eat;
        sil -= eat;
        pbs += prod;
        pbl -= prod;
    }
    /* Slow decompression. */
    while (pbl)
    {
        /* Lookup. */
        uint eat = sack_dec_slow[si0 & 0x3f].eat;
        if (eat > sil)
            break;
        uint prod = sack_dec_slow[si0 & 0x3f].prod;
        uint nok0 = sack_dec_slow[si0 & 0x3f].nok0;
        uint nok1 = sack_dec_slow[si0 & 0x3f].nok1;
        PBPROC_SACKI_DEC_DEBUG (eat, prod, nok0, nok1, 7);
        prod = MIN (prod, pbl);
        /* Call callback. */
        if (nok0 != SACK_DEC_SLOW_NOK_UNDEF && nok0 < pbl)
        {
            nok_cb (user, pbs + nok0, 1);
            if (nok1 != SACK_DEC_SLOW_NOK_UNDEF && nok1 < pbl)
            {
                nok_cb (user, pbs + nok1, 1);
            }
        }
        /* Advance. */
        si0 = si1 << (32 - eat) | si0 >> eat;
        si1 = si2 << (32 - eat) | si1 >> eat;
        si2 = si2 >> eat;
        sil -= eat;
        pbs += prod;
        pbl -= prod;
    }
    /* Extra PB. */
    if (pbl)
        nok_cb (user, pbs, pbl);
    /* Store cache. */
    si[0] = si0;
    si[1] = si1;
    si[2] = si2;
    return sil;
}