/* 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 "hal/arch/arch.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 ARCH_DLRAM_DATA sack_enc_f[] = { sack_enc_f1, sack_enc_f2, sack_enc_f3, }; void ARCH_ILRAM pbproc_sacki_enc_init (pbproc_sacki_enc_t *ctx, uint sil, bool reset) { dbg_claim (ctx); if (reset) { ctx->si[0] = 0; ctx->si[1] = 0; ctx->si[2] = 0; ctx->sis = 0; ctx->sil = sil; } ctx->sis_save = ctx->sis; ctx->bmps = 0; } void ARCH_ILRAM 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_claim (bmp_eat <= bmp01l); bmp0 >>= bmp_eat; bmp0 |= bmp1 << (32 - bmp_eat); bmp1 >>= bmp_eat; bmp01l -= bmp_eat; bmps += bmp_eat; } dbg_claim ((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_claim (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_claim (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; } } void pbproc_sacki_enc_rewind (pbproc_sacki_enc_t *ctx) { uint sissw, sissb; dbg_claim (ctx); sissw = ctx->sis_save / 32; sissb = ctx->sis_save % 32; /* Clear upper bits if not at a word frontier. */ if (sissb) { ctx->si[sissw] = ctx->si[sissw] & ((1u << sissb) - 1); sissw++; /* This word is handled. */ } /* Clear remaining words. */ while (sissw < (ctx->sis + 31) / 32) ctx->si[sissw++] = 0; /* Update counters. */ ctx->sil += ctx->sis - ctx->sis_save; ctx->sis = ctx->sis_save; } void pbproc_sacki_enc_copy (pbproc_sacki_enc_t *ctx, const volatile u32 *bmp, uint bmpl) { u32 bmp0; /* bmp cache. */ uint bmp0l; /* Number of bits remaining in bmp0. */ u32 si0; /* SACKI write cache. */ uint sisw; /* SACKI start offset in words. */ uint sisb; /* SACKI start offset in bits. */ uint sil; /* SACKI bits left. */ dbg_claim (ctx); /* Load si cache. */ sisw = ctx->sis / 32; sisb = ctx->sis % 32; si0 = ctx->si[sisw]; sil = ctx->sil; /* Copy until finished or no room left. */ while (sil && bmpl) { /* Load bmp cache. */ bmp0 = *bmp++; if (bmpl >= 32) { bmp0l = 32; bmpl -= 32; } else { bmp0l = bmpl; bmpl = 0; } /* Truncate. */ if (bmp0l > sil) bmp0l = sil; /* Copy to si. */ si0 |= bmp0 << sisb; if (sisb + bmp0l >= 32) { /* si0 overflow, store it. */ ctx->si[sisw] = si0; if (sisb == 0) si0 = 0; else si0 = bmp0 >> (32 - sisb); sisw++; sisb = sisb + bmp0l - 32; } else { sisb += bmp0l; } sil -= bmp0l; } /* Flush si cache. */ ctx->sil = sil; ctx->sis = sisw * 32 + sisb; if (sisb) { si0 &= (1u << sisb) - 1; ctx->si[sisw] = si0; } } bool pbproc_sacki_enc_better (pbproc_sacki_enc_t *ctx, uint bmpl) { dbg_claim (ctx); /* Could not fit more bit than there is room. */ bmpl = MIN (bmpl, ctx->sil + ctx->sis - ctx->sis_save); /* Better if: * - encoded more bits, * - encoded as much bits, but used less bits. */ return ctx->bmps > bmpl || (ctx->bmps == bmpl && ctx->sis - ctx->sis_save <= bmpl); }