/* * SPDX-FileCopyrightText: Copyright 2020, 2022 Arm Limited and/or its affiliates * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "mlw_common.h" #include "mlw_decode.h" #define CHECKED_MALLOC(var, size) { if ( !(var = malloc(size)) ) break; } /////////////////////////////// Read from bitstream typedef struct bitbuf { uint8_t *buf; int buf_size; // in bytes int pos; // bit pos of next bit int log_symbols; } bitbuf_t; // size in byte static void bitbuf_init( bitbuf_t *bb, uint8_t *buf, int size, int log_symbols) { bb->buf = buf; bb->pos = 0; bb->buf_size = size; bb->log_symbols = log_symbols; } static int bitbuf_getbit( bitbuf_t *bb) { int byte_pos = bb->pos>>3; int bit_pos = bb->pos&7; if ( byte_pos < 0 || byte_pos >= bb->buf_size ) { printf("bitbuf_getbit: underrun, bit_pos %3d byte_pos %3d buf_size %3d\n", bit_pos, byte_pos, bb->buf_size); exit(1); } int bit = bb->buf[ byte_pos ] & (1<pos++; return bit; } static int bitbuf_get( bitbuf_t *bb, const char *name, int len) { int i, data=0, save_pos=bb->pos; if (len>0) { for(i=0; ilog_symbols) printf("bitbuf: pos %3d %7s len %d data %x\n", save_pos, name, len, data); } return data; } // Decode the given weight stream // inbuf compressed bitstream // inbuf_size size of compressed bitstream in bytes // outbuf uncompressed 9bit signed weights, buffer malloced // verbose if non-zero, printf log // Return value is the number of uncompressed weights int mlw_decode( uint8_t *inbuf, int inbuf_size, int16_t **outbuf, int verbose) { int nvalues; int w_grc_div; int w_grc_trunc; int w_uncompressed; int z_grc_div, z_prev_grc_div=0; int new_palette; int palsize=0, palbits=0; int direct_offset=0; int16_t palette[512]; int first=1; int use_zero_run, i, j; int outbuf_size=0; int nchunks=0; *outbuf=0; bitbuf_t bitbuf_s, *bb=&bitbuf_s; bitbuf_init( bb, inbuf, inbuf_size, (verbose&2)?1:0 ); int *w_value = NULL; int *z_value = NULL; // Loop over all slices do { // Decode slice header z_grc_div = bitbuf_get( bb, "ZDIV", 3 ); while(z_grc_div==ZDIV_EOS) { // TODO: change to ZDIV_PAD // End of stream // Byte align bitbuf_get( bb, "BYTEALIGN", (8-(bb->pos&7))&7 ); first=1; if ( (bb->pos/8) == inbuf_size) { // Quit if we actually reached end of input stream break; } z_grc_div = bitbuf_get( bb, "ZDIV", 3 ); } if ( (bb->pos/8) == inbuf_size) { break; // reached end of input stream } assert(z_grc_div<4 || z_grc_div==ZDIV_DISABLE); use_zero_run = z_grc_div!=ZDIV_DISABLE; // alternating grc nvalues = bitbuf_get( bb, "SLICELEN", 15 )+1; w_grc_div = bitbuf_get( bb, "WDIV", 3 ); w_grc_trunc = bitbuf_get( bb, "WTRUNC", 1 ); new_palette = bitbuf_get( bb, "NEWPAL", 1 ); if (first) { // the first slice must have a palette/direct mode setup assert(new_palette); first=0; } if (!new_palette) { // At the moment it is not supported to change between alternating // and non-alternating without redefining the palette (this is because // the zero is not included in the palette in case of alternating) int prev_use_zero_run = z_prev_grc_div!=ZDIV_DISABLE; (void)(prev_use_zero_run); assert( use_zero_run == prev_use_zero_run); } z_prev_grc_div = z_grc_div; if (new_palette) { direct_offset = bitbuf_get( bb, "DIROFS", 5 ); palsize = bitbuf_get( bb, "PALSIZE", 5 ); if (palsize>0) palsize++; palbits = bitbuf_get( bb, "PALBITS", 3 )+2; for(i=0; i0) { // Uncompressed bits is given by palette size. uncompressed_bits=0; while( (1<=0 && use_zero_run && z_pos5 ? 8 : 12; for(i=0; i>1; } cnt += code; if (code<2 || w_grc_trunc) { w_q[w_nsymbols++] = cnt; cnt=0; } } w_carry = cnt; w_pos += w_nsymbols; } if (w_prev_enable) { for(i=0; i>1; (*outbuf)[k++] = sign ? -mag : mag; if (use_zero_run) { for(j=0; j