/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file mac/pbproc/src/sacki_enc.c * \brief SACKI compression. * \ingroup mac_pbproc */ #include "common/std.h" #include "inc/sacki_enc.h" #include "pbproc_sacki_enc_tables.h" #ifdef PBPROC_SACKI_ENC_DEBUG # undef PBPROC_SACKI_ENC_DEBUG void pbproc_sacki_enc_debug (u32 code, uint codel, uint eat); # define PBPROC_SACKI_ENC_DEBUG(code, codel, eat) \ pbproc_sacki_enc_debug ((code), (codel), (eat)) #else # define PBPROC_SACKI_ENC_DEBUG(code, codel, eat) #endif static const struct sack_enc_finish_t * const sack_enc_f[] = { sack_enc_f1, sack_enc_f2, sack_enc_f3, }; void pbproc_sacki_enc_init (pbproc_sacki_enc_t *ctx, uint sil) { ctx->si[0] = 0; ctx->si[1] = 0; ctx->si[2] = 0; ctx->sis = 0; ctx->sil = sil; ctx->bmps = 0; } void pbproc_sacki_enc_process (pbproc_sacki_enc_t *ctx, const volatile u32 *bmp, uint bmpl, bool final) { u32 bmp0, bmp1; /* Extended bmp cache. */ uint bmp01l; /* Number of bits remaining in {bmp1, bmp0}. */ uint bmps; /* Start offset in bmp. */ u32 si0; /* SACKI write cache. */ uint sisw; /* SACKI start offset in words. */ uint sisb; /* SACKI start offset in bits. */ uint sil; /* SACKI bits left. */ /* Load bmp cache. */ bmps = ctx->bmps; bmp += bmps / 32; bmpl -= bmps; bmp01l = MIN (bmpl, 32 - bmps % 32); bmpl -= bmp01l; bmp0 = *bmp++; bmp0 >>= bmps % 32; bmp1 = 0; /* Load si cache. */ sisw = ctx->sis / 32; sisb = ctx->sis % 32; si0 = ctx->si[sisw]; sil = ctx->sil; /* Fast compression. */ while (1) { /* Load words? */ if (bmp01l < 8 && bmpl) { bmp1 = *bmp++; bmp0 |= bmp1 << bmp01l; bmp1 = bmp01l == 0 ? 0 : bmp1 >> (32 - bmp01l); if (bmpl >= 32) { bmp01l += 32; bmpl -= 32; } else { bmp01l += bmpl; bmpl = 0; } } /* Can continue? */ if (bmp01l < 8 || sil == 0) break; /* Look up table. */ u32 code = sack_enc_8[bmp0 & 0xff].code; uint codel = sack_enc_8[bmp0 & 0xff].codel; uint bmp_eat = sack_enc_8[bmp0 & 0xff].eat; PBPROC_SACKI_ENC_DEBUG (code, codel, bmp_eat); /* Output bits. */ codel = MIN (codel, sil); si0 |= code << sisb; if (sisb + codel >= 32) { /* si0 overflow, store it. */ ctx->si[sisw] = si0; si0 = code >> (32 - sisb); sisw++; sisb = sisb + codel - 32; } else { sisb += codel; } sil -= codel; /* Consume input. */ dbg_assert (bmp_eat <= bmp01l); bmp0 >>= bmp_eat; bmp0 |= bmp1 << (32 - bmp_eat); bmp1 >>= bmp_eat; bmp01l -= bmp_eat; bmps += bmp_eat; } dbg_assert ((bmp01l < 8 && bmpl == 0) || sil == 0); if (final) { while (bmp01l >= 4 && sil) { u32 code = sack_enc_4[bmp0 & 0xf].code; uint codel = sack_enc_4[bmp0 & 0xf].codel; uint bmp_eat = sack_enc_4[bmp0 & 0xf].eat_m1 + 1; PBPROC_SACKI_ENC_DEBUG (code, codel, bmp_eat); /* Output bits. */ codel = MIN (codel, sil); si0 |= code << sisb; if (sisb + codel >= 32) { /* si0 overflow, store it. */ ctx->si[sisw] = si0; si0 = code >> (32 - sisb); sisw++; sisb = sisb + codel - 32; } else { sisb += codel; } sil -= codel; /* Consume input. */ dbg_assert (bmp_eat <= bmp01l); bmp0 >>= bmp_eat; bmp01l -= bmp_eat; bmps += bmp_eat; } if (bmp01l && sil) { const struct sack_enc_finish_t *t = sack_enc_f[bmp01l - 1]; u32 bmp0m = bmp0 & ((1 << bmp01l) - 1); u32 code = t[bmp0m].code; u32 codel = t[bmp0m].codel; PBPROC_SACKI_ENC_DEBUG (code, codel, bmp01l); /* Output bits. */ codel = MIN (codel, sil); si0 |= code << sisb; if (sisb + codel >= 32) { /* si0 overflow, store it. */ ctx->si[sisw] = si0; si0 = code >> (32 - sisb); sisw++; sisb = sisb + codel - 32; } else { sisb += codel; } sil -= codel; } bmps += bmp01l; bmp01l = 0; } dbg_assert (bmp01l <= 8 || sil == 0); ctx->bmps = bmps; ctx->sil = sil; ctx->sis = sisw * 32 + sisb; if (sisb) { si0 &= (1u << sisb) - 1; ctx->si[sisw] = si0; } }