Full Code of ultraembedded/core_jpeg for AI

main bb03cce45d0b cached
33 files
275.5 KB
85.9k tokens
13 symbols
1 requests
Download .txt
Showing preview only (288K chars total). Download the full file or copy to clipboard to get everything.
Repository: ultraembedded/core_jpeg
Branch: main
Commit: bb03cce45d0b
Files: 33
Total size: 275.5 KB

Directory structure:
gitextract_xejh9o8w/

├── LICENSE
├── README.md
├── c_model/
│   ├── README.md
│   ├── jpeg_bit_buffer.h
│   ├── jpeg_dht.h
│   ├── jpeg_dqt.h
│   ├── jpeg_idct.h
│   ├── jpeg_mcu_block.h
│   ├── main.cpp
│   └── makefile
└── src_v/
    ├── jpeg_bitbuffer.v
    ├── jpeg_core.v
    ├── jpeg_dht.v
    ├── jpeg_dht_std_cx_ac.v
    ├── jpeg_dht_std_cx_dc.v
    ├── jpeg_dht_std_y_ac.v
    ├── jpeg_dht_std_y_dc.v
    ├── jpeg_dqt.v
    ├── jpeg_idct.v
    ├── jpeg_idct_fifo.v
    ├── jpeg_idct_ram.v
    ├── jpeg_idct_ram_dp.v
    ├── jpeg_idct_transpose.v
    ├── jpeg_idct_transpose_ram.v
    ├── jpeg_idct_x.v
    ├── jpeg_idct_y.v
    ├── jpeg_input.v
    ├── jpeg_mcu_id.v
    ├── jpeg_mcu_proc.v
    ├── jpeg_output.v
    ├── jpeg_output_cx_ram.v
    ├── jpeg_output_fifo.v
    └── jpeg_output_y_ram.v

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   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

       http://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.


================================================
FILE: README.md
================================================
# High throughput JPEG decoder

Github: [https://github.com/ultraembedded/core_jpeg](https://github.com/ultraembedded/core_jpeg)

This project is a JPEG decoder core for FPGA written in Verilog.

![JPEG Core](docs/block_diagram.png)

## Features
* Baseline JPEG Decoder IP (sequential encoded images).
* 32-bit AXI Stream input.
* Input format: JPEG (JPEG File Interchange Format)
* Output format: 24-bit RGB output in 8x8 blocks (row-major ordering).
* Support for Monochrome, 4:4:4, 4:2:0 chroma subsampling support.
* Support for fixed standard Huffman tables (reduced logic usage, fast).
* Support for dynamic Huffman tables (from JPEG input stream -> slower decode, more logic).
* Dynamic DQT tables from JPEG input stream.
* Synthesizable Verilog 2001, Verilator and FPGA friendly.
* Multipliers and tables / FIFO's map efficiently to FPGA resources (DSP48, blockRAM, etc).
* Verified using co-simulation against a C-model and tested on FPGA with thousands of images.

## Design Aims
1. Fast decode performance suitable for video playback
2. Support a minimal JPEG baseline feature set.
3. Be well tested (with verification against a reference C-model).
4. Map to FPGA resources such as BlockRAM, DSP macros wherever possible.

## FPGA Mapping
The current version of the JPEG decoder uses the following resources on a Xilinx 7 series FPGA (post-implementation);  
![Resource Usage](docs/resources.png)

The design is also able to meet timing >= 75MHz.

## Performance
Peak JPEG decode performance is as follows;
* Monochrome  = 66 cycles per 8x8 pixels  (1.0 cycles per pixel)
* YCbCr 4:2:0 = 137 cycles per 8x8 pixels (2.1 cycles per pixel)
* YCbCr 4:4:4 = 198 cycles per 8x8 pixels (3.1 cycles per pixel)

## Use Case
The purpose of this design was to replace a 3rd party JPEG decoder core used in my [Motion JPEG](https://en.wikipedia.org/wiki/Motion_JPEG) based [FPGA video player](https://github.com/ultraembedded/FPGAmp).  
Motion JPEG has worse compression performance than MPEG based video, but the complexity of the HW required is low enough that it can be used on low(-ish)-end FPGAs.

Video playback usually requires at least 25 frames per second, hence there is a budget of less than 40ms per JPEG frame.  
This fact drives the design choices taken for this implementation.

Clearly, the higher the resolution, the more pixels that must be produced from the JPEG decoder within that 40ms budget, so this core is designed to have high throughput in the output stages - with additional resources dedicated to the IDCT transform, and output re-ordering stages to facilitate this.

## Limitations
The current release does not support;
* Restart markers
* 4:2:2 H/V chroma subsampling (only 4:4:4 and 4:2:0 are supported).

Under the GNU Image Manipulation Program, the following 'X' options are **not** supported currently;
![Unsupported Opts](docs/supported_opts.png)

Note: Support for 'optimised' Huffman tables is possible when design parameter SUPPORT_WRITABLE_DHT=1.  
This functionality increases the core size substantially and reduces performance.

## Future Work / TODO
* Add support for the first layer of progressive JPEG images.
* Add option to reduce arithmetic precision to reduce design size.
* Add lightweight variant of the core with reduced performance (for smaller FPGAs).

================================================
FILE: c_model/README.md
================================================
## JPEG Decoder C Model

This a simple C model of a JPEG decoder that can decode baseline JPEG images.
The purpose of this is to provide a reference to test the digital HW design against.

It supports;
* YCbCr 4:4:4 (no chroma subsampling), 4:2:0 and monochrome images.
* Conversion to a bitmap file (PPM / P6 format).
* Optimised (Huffman tables) images.

It does not support (currently);
* Progressive
* YCbCr 4:2:2 chroma subsampling
* Restart markers
* App data, COM sections, will be ignored.


### Building / Usage
```
# Build
make

# Run
./jpeg my_image.jpg bitmap.ppm
```


================================================
FILE: c_model/jpeg_bit_buffer.h
================================================
#ifndef JPEG_BIT_BUFFER_H
#define JPEG_BIT_BUFFER_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#define dprintf

#ifndef TEST_HOOKS_BITBUFFER
#define TEST_HOOKS_BITBUFFER(x)
#endif

#ifndef TEST_HOOKS_BITBUFFER_DECL
#define TEST_HOOKS_BITBUFFER_DECL
#endif

//-----------------------------------------------------------------------------
// jpeg_bit_buffer:
//-----------------------------------------------------------------------------
class jpeg_bit_buffer
{
public:
    jpeg_bit_buffer() 
    {
        m_buffer = NULL;
        reset(-1);
    }

    void reset(int max_size = -1)
    {
        if (m_buffer)
        {
            delete [] m_buffer;
            m_buffer = NULL;
        }

        if (max_size <= 0)
            m_max_size = 1 << 20;
        else
            m_max_size = max_size;

        m_buffer = new uint8_t[m_max_size];
        memset(m_buffer, 0, m_max_size);
        m_wr_offset = 0;
        m_last      = 0;
        m_rd_offset = 0;
    }

    // Push byte into stream (return false if marker found)
    bool push(uint8_t b)
    {
        uint8_t last = m_last;

        // Skip padding
        if (last == 0xFF && b == 0x00)
            ;
        // Marker found
        else if (last == 0xFF && b != 0x00)
        {
            m_wr_offset--;
            return false;
        }
        // Push byte into buffer
        else
        {
            assert(m_wr_offset < m_max_size);
            m_buffer[m_wr_offset++] = b;
        }

        m_last = b;

        return true;
    }

    // Read upto 32-bit (aligned to MSB)
    uint32_t read_word(void)
    {
        if (eof())
            return 0;

        int byte   = m_rd_offset / 8;
        int bit    = m_rd_offset % 8; // 0 - 7
        uint64_t w = 0;
        for (int x=0;x<5;x++)
        {
            w |= m_buffer[byte+x];
            w <<= 8;
        }
        w <<= bit;
        return w >> 16;
    }

    void advance(int bits)
    {
        TEST_HOOKS_BITBUFFER(bits);
        m_rd_offset += bits;
    }

    bool eof(void)
    {
        return (((m_rd_offset+7) / 8) >= m_wr_offset);
    }

    TEST_HOOKS_BITBUFFER_DECL;

private:
    uint8_t *m_buffer;
    uint8_t  m_last;
    int      m_max_size;
    int      m_wr_offset;
    int      m_rd_offset; // in bits
};

#endif


================================================
FILE: c_model/jpeg_dht.h
================================================
#ifndef JPEG_DHT_H
#define JPEG_DHT_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#define DHT_TABLE_Y_DC      0x00
#define DHT_TABLE_Y_DC_IDX  0
#define DHT_TABLE_Y_AC      0x10
#define DHT_TABLE_Y_AC_IDX  1
#define DHT_TABLE_CX_DC     0x01
#define DHT_TABLE_CX_DC_IDX 2
#define DHT_TABLE_CX_AC     0x11
#define DHT_TABLE_CX_AC_IDX 3

#define dprintf

//-----------------------------------------------------------------------------
// jpeg_dqt:
//-----------------------------------------------------------------------------
class jpeg_dht
{
public:
    jpeg_dht() { reset(); }

    void reset(void)
    {
        for (int i=0;i<4;i++)
            memset(&m_dht_table[i], 0, sizeof(t_huffman_table));
    }

    int process(uint8_t *data, int len)
    {
        uint8_t *buf = data;
        int consumed = 0;

        // DHT tables can be combined into one section (it seems)
        while (consumed <= (len-17))
        {
            // Huffman table info, first four MSBs represent table type (0 for DC, 1 for AC), last four LSBs represent table #
            uint8_t  table_info  = *buf++;

            int table_idx = 0;
            switch (table_info)
            {
                case DHT_TABLE_Y_DC:
                    table_idx = DHT_TABLE_Y_DC_IDX;
                    break;
                case DHT_TABLE_Y_AC:
                    table_idx = DHT_TABLE_Y_AC_IDX;
                    break;
                case DHT_TABLE_CX_DC:
                    table_idx = DHT_TABLE_CX_DC_IDX;
                    break;
                case DHT_TABLE_CX_AC:
                    table_idx = DHT_TABLE_CX_AC_IDX;
                    break;
                default:
                    assert(!"ERROR: Bad JPEG");
                    break;
            }
            dprintf("DHT (Table idx %d)\n", table_idx);

            // Reset table
            memset(&m_dht_table[table_idx], 0, sizeof(m_dht_table[0]));

            // Extract symbol count
            uint8_t symb_count[16];
            for (int x=0;x<16;x++)
            {
                symb_count[x] = *buf++;
                dprintf(" bit length: %d, symbols: %d\n", x, symb_count[x]);
            }

            // Extract table values
            // Build the Huffman map of (length, code) -> value
            uint16_t code = 0;
            int entry = 0;
            for (int x=0;x<16;x++)
            {
                for (int j=0;j<symb_count[x];j++)
                {
                    uint8_t dht_val = *buf++;
                    m_dht_table[table_idx].code[entry]     = code;
                    m_dht_table[table_idx].code_len[entry] = x+1;
                    m_dht_table[table_idx].value[entry++]  = dht_val;
                    dprintf(" %d: %x -> %x\n", entry, code, dht_val);

                    code++;
                }
                code <<= 1;
            }
            m_dht_table[table_idx].entries = entry;

            consumed = buf - data;
        }

        return buf - data;
    }

    // lookup: Perform huffman lookup (starting from bit 15 of w)
    int lookup(int table_idx, uint16_t w, uint8_t &value)
    {
        for (int i=0;i<m_dht_table[table_idx].entries;i++)
        {
            int      width   = m_dht_table[table_idx].code_len[i];
            uint16_t bitmap  = m_dht_table[table_idx].code[i];
            
            
            uint16_t shift_val = w >> (16-width);
            //printf("- %d: check against %04x ", width, shift_val);
            //print_bin(shift_val, width);
            //printf(" == %04x -> %02x\n", bitmap, value);
            if (shift_val == bitmap)
            {
                value   = m_dht_table[table_idx].value[i];
                return width;
            }
        }
        return 0;
    }

private:
    typedef struct
    {
        // 16-bit (max) code
        uint16_t code[255];
        // Code length
        uint8_t  code_len[255];
        // Value to translate to
        uint8_t  value[255];
        int      entries;
    } t_huffman_table;

    t_huffman_table m_dht_table[4];
};

#endif


================================================
FILE: c_model/jpeg_dqt.h
================================================
#ifndef JPEG_DQT_H
#define JPEG_DQT_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

// Zigzag table
static const int m_zigzag_table[]=
{
     0, 1, 8, 16,9, 2, 3,10,
    17,24,32,25,18,11, 4, 5,
    12,19,26,33,40,48,41,34,
    27,20,13, 6, 7,14,21,28,
    35,42,49,56,57,50,43,36,
    29,22,15,23,30,37,44,51,
    58,59,52,45,38,31,39,46,
    53,60,61,54,47,55,62,63,
    0
};

#define dprintf

//-----------------------------------------------------------------------------
// jpeg_dqt:
//-----------------------------------------------------------------------------
class jpeg_dqt
{
public:
    jpeg_dqt() { reset(); }

    //-------------------------------------------------------------------------
    // reset: Reset DQT tables
    //-------------------------------------------------------------------------
    void reset(void)
    {
        memset(&m_table_dqt[0], 0, 64 * 4);
    }

    //-------------------------------------------------------------------------
    // process: Store DQT table from input stream
    //-------------------------------------------------------------------------
    int process(uint8_t *data, int len)
    {
        uint8_t *buf = data;

        // Table number
        uint8_t  table_num = (*buf++) & 0x3;
        dprintf(" DQT: Table %d\n", table_num);

        for (int x=0;x<64;x++)
        {
            // 8-bit
            uint8_t qv = *buf++;
            dprintf(" %d: %x\n", x, qv);
            m_table_dqt[table_num][x] = qv;
        }

        return buf - data;
    }

    //-------------------------------------------------------------------------
    // lookup: DQT table entry lookup
    //-------------------------------------------------------------------------
    uint8_t lookup(int table_num, int position)
    {
        return m_table_dqt[table_num][position];
    }

    //-------------------------------------------------------------------------
    // process_samples: Multiply out samples and de-zigzag ready for IDCT
    // samples: (idx, value)
    //-------------------------------------------------------------------------
    void process_samples(int quant_table, int *sample_in, int *block_out, int count)
    {
        // Apply quantisation and zigzag
        memset(block_out, 0, sizeof(block_out[0])*64);
        for (int i=0;i<count;i++)
        {
            int16_t smpl      = (int16_t)(sample_in[i] & 0xFFFF);
            int   block_idx   = (sample_in[i] >> 16);
            dprintf("DEQ: %d: %d * %d -> %d @ %d\n", block_idx, smpl, lookup(quant_table,block_idx), smpl * lookup(quant_table,block_idx), m_zigzag_table[block_idx]);
            block_out[m_zigzag_table[block_idx]] = smpl * lookup(quant_table,block_idx);
        }
    }

private:
    uint8_t  m_table_dqt[4][64];
};

#endif


================================================
FILE: c_model/jpeg_idct.h
================================================
#ifndef JPEG_IDCT_H
#define JPEG_IDCT_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

//-----------------------------------------------------------------------------
// jpeg_idct:
//-----------------------------------------------------------------------------
class jpeg_idct
{
public:
    jpeg_idct() { reset(); }
    void reset(void) { }

    //-----------------------------------------------------------------------------
    // process: Perform inverse DCT on already dequantized data.
    // [Not quite sure who to attribute this implementation to...]
    //-----------------------------------------------------------------------------
    void process(int *data_in, int *data_out)
    {
        int s0,s1,s2,s3,s4,s5,s6,s7;
        int t0,t1,t2,t3,t4,t5,t6,t7;

        int working_buf[64];
        int *temp_buf = working_buf;

        // X - Rows
        for(int i=0;i<8;i++)
        {
            s0 = (data_in[0] + data_in[4])       * C4;
            s1 = (data_in[0] - data_in[4])       * C4;
            s3 = (data_in[2] * C2) + (data_in[6] * C6);
            s2 = (data_in[2] * C6) - (data_in[6] * C2);
            s7 = (data_in[1] * C1) + (data_in[7] * C7);
            s4 = (data_in[1] * C7) - (data_in[7] * C1);
            s6 = (data_in[5] * C5) + (data_in[3] * C3);
            s5 = (data_in[5] * C3) - (data_in[3] * C5);

            // Next row
            data_in += 8;

            t0 = s0 + s3;
            t3 = s0 - s3;
            t1 = s1 + s2;
            t2 = s1 - s2;
            t4 = s4 + s5;
            t5 = s4 - s5;
            t7 = s7 + s6;
            t6 = s7 - s6;

            s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2)
            s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2)

            *temp_buf++ = (t0 + t7) >> 11;
            *temp_buf++ = (t1 + s6) >> 11;
            *temp_buf++ = (t2 + s5) >> 11;
            *temp_buf++ = (t3 + t4) >> 11;
            *temp_buf++ = (t3 - t4) >> 11;
            *temp_buf++ = (t2 - s5) >> 11;
            *temp_buf++ = (t1 - s6) >> 11;
            *temp_buf++ = (t0 - t7) >> 11;
        }

        // Y - Columns
        temp_buf = working_buf;
        for(int i=0;i<8;i++)
        {
            s0 = (temp_buf[0] + temp_buf[32])     * C4;
            s1 = (temp_buf[0] - temp_buf[32])     * C4;
            s3 = temp_buf[16] * C2 + temp_buf[48] * C6;
            s2 = temp_buf[16] * C6 - temp_buf[48] * C2;
            s7 = temp_buf[8]  * C1 + temp_buf[56] * C7;
            s4 = temp_buf[8]  * C7 - temp_buf[56] * C1;
            s6 = temp_buf[40] * C5 + temp_buf[24] * C3;
            s5 = temp_buf[40] * C3 - temp_buf[24] * C5;

            t0 = s0 + s3;
            t1 = s1 + s2;
            t2 = s1 - s2;
            t3 = s0 - s3;
            t4 = s4 + s5;
            t5 = s4 - s5;
            t6 = s7 - s6;
            t7 = s6 + s7;

            s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2)
            s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2)

            data_out[0]  = ((t0 + t7) >> 15);
            data_out[56] = ((t0 - t7) >> 15);
            data_out[8]  = ((t1 + s6) >> 15);
            data_out[48] = ((t1 - s6) >> 15);
            data_out[16] = ((t2 + s5) >> 15);
            data_out[40] = ((t2 - s5) >> 15);
            data_out[24] = ((t3 + t4) >> 15);
            data_out[32] = ((t3 - t4) >> 15);
            
            temp_buf++;
            data_out++;
        }
        data_out -= 8;
    }

    static const int C1 = 4017; // cos( pi/16) x4096
    static const int C2 = 3784; // cos(2pi/16) x4096
    static const int C3 = 3406; // cos(3pi/16) x4096
    static const int C4 = 2896; // cos(4pi/16) x4096
    static const int C5 = 2276; // cos(5pi/16) x4096
    static const int C6 = 1567; // cos(6pi/16) x4096
    static const int C7 = 799;  // cos(7pi/16) x4096
};

#endif


================================================
FILE: c_model/jpeg_mcu_block.h
================================================
#ifndef JPEG_MCU_BLOCK_H
#define JPEG_MCU_BLOCK_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#include "jpeg_bit_buffer.h"
#include "jpeg_dht.h"

#define dprintf

//-----------------------------------------------------------------------------
// jpeg_mcu_block:
//-----------------------------------------------------------------------------
class jpeg_mcu_block
{
public:
    jpeg_mcu_block(jpeg_bit_buffer *bit_buf, jpeg_dht *dht)
    {
        m_bit_buffer = bit_buf;
        m_dht        = dht;
        reset();
    }

    void reset(void) { }

    //-----------------------------------------------------------------------------
    // decode: Run huffman entropy decoder on input stream, expand to DC + upto 
    //         63 AC samples.
    //-----------------------------------------------------------------------------
    int decode(int table_idx, int16_t &olddccoeff, int32_t *block_out)
    {
        int samples = 0;

        for (int coeff=0;coeff<64;coeff++)
        {
            // Read 32-bit word
            uint32_t input_word = m_bit_buffer->read_word();

            // Start with upper 16-bits
            uint16_t input_data = input_word >> 16;

            // Perform huffman decode on input data (code=RLE,num_bits)
            uint8_t code   = 0;
            int code_width = m_dht->lookup(table_idx + (coeff != 0), input_data, code);
            int coef_bits  = code & 0xF;

            // Move input point past decoded data
            if (coeff == 0)
                m_bit_buffer->advance(code_width + coef_bits);
            // End of block or ZRL (no coefficient)
            else if (code == 0 || code == 0xF0)
                m_bit_buffer->advance(code_width);
            else
                m_bit_buffer->advance(code_width + coef_bits);

            // Use remaining data for actual coeffecient
            input_data = input_word >> (16 - code_width);

            // DC
            if (coeff == 0)
            {
                input_data >>= (16 - code);

                int16_t dcoeff = decode_number(input_data, coef_bits) + olddccoeff;
                olddccoeff = dcoeff;
                block_out[samples++] = (0 << 16) | (dcoeff & 0xFFFF);
            }
            // AC
            else
            {
                // End of block
                if (code == 0)
                {
                    dprintf("SMPL: EOB\n");
                    coeff = 64;
                    break;
                }

                // The first part of the AC key_len is the number of leading zeros
                if (code == 0xF0)
                {
                    // When the ZRL code comes, it is regarded as 15 zero data
                    dprintf("SMPL: ZRL\n");
                    coeff += 15; // +1 in the loop
                    continue;
                }
                else if (code > 15)
                    coeff   += code >> 4;

                input_data >>= (16 - coef_bits);

                if (coeff < 64)
                {
                    int16_t acoeff = decode_number(input_data, coef_bits);
                    block_out[samples++] = (coeff << 16) | (acoeff & 0xFFFF);
                }
            }
        }

        return samples;
    }


private:
    //-----------------------------------------------------------------------------
    // decode_number: Extract number from code / width
    //-----------------------------------------------------------------------------
    int16_t decode_number(uint16_t code, int bits)
    {   
        if (!(code & (1<<(bits-1))) && bits != 0)
        {
            code |= (~0) << bits;
            code += 1;
        }
        return code;
    }

private:
    jpeg_bit_buffer *m_bit_buffer;
    jpeg_dht *m_dht;

};

#endif


================================================
FILE: c_model/main.cpp
================================================
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include "jpeg_dqt.h"
#include "jpeg_dht.h"
#include "jpeg_idct.h"
#include "jpeg_bit_buffer.h"
#include "jpeg_mcu_block.h"

static jpeg_dqt        m_dqt;
static jpeg_dht        m_dht;
static jpeg_idct       m_idct;
static jpeg_bit_buffer m_bit_buffer;
static jpeg_mcu_block  m_mcu_dec(&m_bit_buffer, &m_dht);

static uint16_t m_width;
static uint16_t m_height;

typedef enum eJpgMode
{
    JPEG_MONOCHROME,
    JPEG_YCBCR_444,
    JPEG_YCBCR_420,
    JPEG_UNSUPPORTED
} t_jpeg_mode;

static t_jpeg_mode m_mode;

static uint8_t m_dqt_table[3];

#define get_byte(_buf, _idx)  _buf[_idx++]
#define get_word(_buf, _idx)  ((_buf[_idx++] << 8) | (_buf[_idx++]))

static uint8_t *m_output_r;
static uint8_t *m_output_g;
static uint8_t *m_output_b;

#define dprintf
#define dprintf_blk(_name, _arr, _max) for (int __i=0;__i<_max;__i++) { dprintf("%s: %d -> %d\n", _name, __i, _arr[__i]); }

//-----------------------------------------------------------------------------
// ConvertYUV2RGB: Convert from YUV to RGB
//-----------------------------------------------------------------------------
static void ConvertYUV2RGB(int block_num, int *y, int *cb, int *cr)
{
    int x_blocks = (m_width / 8);

    // If width is not a multiple of 8, round up
    if (m_width % 8)
        x_blocks++;

    int x_start = (block_num % x_blocks) * 8;
    int y_start = (block_num / x_blocks) * 8;

    if (m_mode == JPEG_MONOCHROME)
    {
        for (int i=0;i<64;i++)
        {
            int r = 128 + y[i];
            int g = 128 + y[i];
            int b = 128 + y[i];

            // Avoid overflows
            r = (r & 0xffffff00) ? (r >> 24) ^ 0xff : r;
            g = (g & 0xffffff00) ? (g >> 24) ^ 0xff : g;
            b = (b & 0xffffff00) ? (b >> 24) ^ 0xff : b;

            int _x = x_start + (i % 8);
            int _y = y_start + (i / 8);
            int offset = (_y * m_width) + _x;

            dprintf("RGB: r=%d g=%d b=%d -> %d\n", r, g, b, offset);
            m_output_r[offset] = r;
            m_output_g[offset] = g;
            m_output_b[offset] = b;
        }
    }
    else
    {
        for (int i=0;i<64;i++)
        {
            int r = 128 + y[i] + (cr[i] * 1.402);
            int g = 128 + y[i] - (cb[i] * 0.34414) - (cr[i] * 0.71414);
            int b = 128 + y[i] + (cb[i] * 1.772);

            // Avoid overflows
            r = (r & 0xffffff00) ? (r >> 24) ^ 0xff : r;
            g = (g & 0xffffff00) ? (g >> 24) ^ 0xff : g;
            b = (b & 0xffffff00) ? (b >> 24) ^ 0xff : b;

            int _x = x_start + (i % 8);
            int _y = y_start + (i / 8);
            int offset = (_y * m_width) + _x;

            if (_x < m_width && _y < m_height)
            {
                dprintf("RGB: r=%d g=%d b=%d -> %d [x=%d,y=%d]\n", r, g, b, offset, _x, _y);
                m_output_r[offset] = r;
                m_output_g[offset] = g;
                m_output_b[offset] = b;
            }
        }
    }
}
//-----------------------------------------------------------------------------
// DecodeImage: Decode image data section (supports 4:4:4, 4:2:0, monochrom)
//-----------------------------------------------------------------------------
static bool DecodeImage(void)
{
    int16_t dc_coeff_Y = 0;
    int16_t dc_coeff_Cb= 0;
    int16_t dc_coeff_Cr= 0;
    int32_t sample_out[64];
    int     block_out[64];
    int     y_dct_out[4*64];
    int     cb_dct_out[64];
    int     cr_dct_out[64];
    int     count = 0;
    int     loop = 0;

    int block_num = 0;
    while (!m_bit_buffer.eof())
    {
        // [Y0 Y1 Y2 Y3 Cb Cr] x N
        if (m_mode == JPEG_YCBCR_420)
        {
            // Y0
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[0]);

            // Y1
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[64]);

            // Y2
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[128]);

            // Y3
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[192]);

            // Cb
            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cb, sample_out);
            m_dqt.process_samples(m_dqt_table[1], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &cb_dct_out[0]);

            // Cr
            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cr, sample_out);
            m_dqt.process_samples(m_dqt_table[2], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &cr_dct_out[0]);

            // Expand Cb/Cr samples to match Y0-3
            int cb_dct_out_x2[256];
            int cr_dct_out_x2[256];

            for (int i=0;i<64;i++)
            {
                int x = i % 8;
                int y = i / 16;
                int sub_idx = (y * 8) + (x / 2);
                cb_dct_out_x2[i] = cb_dct_out[sub_idx];
                cr_dct_out_x2[i] = cr_dct_out[sub_idx];
            }

            for (int i=0;i<64;i++)
            {
                int x = i % 8;
                int y = i / 16;
                int sub_idx = (y * 8) + 4 + (x / 2);
                cb_dct_out_x2[64 + i] = cb_dct_out[sub_idx];
                cr_dct_out_x2[64 + i] = cr_dct_out[sub_idx];
            }

            for (int i=0;i<64;i++)
            {
                int x = i % 8;
                int y = i / 16;
                int sub_idx = 32 + (y * 8) + (x / 2);
                cb_dct_out_x2[128+i] = cb_dct_out[sub_idx];
                cr_dct_out_x2[128+i] = cr_dct_out[sub_idx];
            }

            for (int i=0;i<64;i++)
            {
                int x = i % 8;
                int y = i / 16;
                int sub_idx = 32 + (y * 8) + 4 + (x / 2);
                cb_dct_out_x2[192 + i] = cb_dct_out[sub_idx];
                cr_dct_out_x2[192 + i] = cr_dct_out[sub_idx];
            }

            int mcu_width = m_width / 8;
            if (m_width % 8)
                mcu_width++;

            // Output all 4 blocks of pixels
            ConvertYUV2RGB((block_num/2) + 0, &y_dct_out[0],  &cb_dct_out_x2[0], &cr_dct_out_x2[0]);
            ConvertYUV2RGB((block_num/2) + 1, &y_dct_out[64], &cb_dct_out_x2[64], &cr_dct_out_x2[64]);
            ConvertYUV2RGB((block_num/2) + mcu_width + 0, &y_dct_out[128], &cb_dct_out_x2[128], &cr_dct_out_x2[128]);
            ConvertYUV2RGB((block_num/2) + mcu_width + 1, &y_dct_out[192], &cb_dct_out_x2[192], &cr_dct_out_x2[192]);
            block_num += 4;

            if (++loop == (mcu_width / 2))
            {
                block_num += (mcu_width * 2);
                loop = 0;
            }
        }
        // [Y Cb Cr] x N
        else if (m_mode == JPEG_YCBCR_444)
        {
            // Y
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[0]);

            // Cb
            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cb, sample_out);
            m_dqt.process_samples(m_dqt_table[1], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &cb_dct_out[0]);

            // Cr
            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cr, sample_out);
            m_dqt.process_samples(m_dqt_table[2], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &cr_dct_out[0]);

            ConvertYUV2RGB(block_num++, y_dct_out, cb_dct_out, cr_dct_out);
        }
        // [Y] x N
        else if (m_mode == JPEG_MONOCHROME)
        {
            // Y
            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);
            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);
            dprintf_blk("DCT-IN", block_out, 64);
            m_idct.process(block_out, &y_dct_out[0]);

            ConvertYUV2RGB(block_num++, y_dct_out, cb_dct_out, cr_dct_out);
        }
    }

    return true;
}
//-----------------------------------------------------------------------------
// main:
//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    if (argc < 3)
    {
        printf("./jpeg src_image.jpg dst_image.ppm\n");
        return -1;
    }

    const char *src_image = argv[1];
    const char *dst_image = argv[2];

    // Load source file
    uint8_t *buf = NULL;
    int      len = 0;
    FILE *f = fopen(src_image, "rb");
    if (f)
    {
        long size;

        // Get size
        fseek(f, 0, SEEK_END);
        size = ftell(f);
        rewind(f);

        // Read file data in
        buf = (uint8_t*)malloc(size);
        assert(buf);
        len = fread(buf, 1, size, f);

        fclose(f);
    }
    else
    {
        printf("./jpeg src_image.jpg dst_image.ppm\n");
        return -1;
    }

    m_dqt.reset();
    m_dht.reset();
    m_idct.reset();
    m_mode = JPEG_UNSUPPORTED;
    m_output_r = NULL;
    m_output_g = NULL;
    m_output_b = NULL;

    uint8_t last_b = 0;
    bool decode_done = false;
    for (int i=0;i<len;)
    {
        uint8_t b = buf[i++];

        //-----------------------------------------------------------------------------
        // SOI: Start of image
        //-----------------------------------------------------------------------------
        if (last_b == 0xFF && b == 0xd8)
            printf("Section: SOI\n");
        //-----------------------------------------------------------------------------
        // SOF0: Indicates that this is a baseline DCT-based JPEG
        //-----------------------------------------------------------------------------
        else if (last_b == 0xFF && b == 0xc0)
        {
            printf("Section: SOF0\n");
            int seg_start = i;

            // Length of the segment
            uint16_t seg_len   = get_word(buf, i);

            // Precision of the frame data
            uint8_t  precision = get_byte(buf,i);

            // Image height in pixels
            m_height = get_word(buf, i);

            // Image width in pixels
            m_width = get_word(buf, i);

            // Allocate pixel buffer
            m_output_r = new uint8_t[m_height * m_width];
            m_output_g = new uint8_t[m_height * m_width];
            m_output_b = new uint8_t[m_height * m_width];
            memset(m_output_r, 0, m_height * m_width);
            memset(m_output_g, 0, m_height * m_width);
            memset(m_output_b, 0, m_height * m_width);

            // # of components (n) in frame, 1 for monochrom, 3 for colour images
            uint8_t num_comps = get_byte(buf,i);
            assert(num_comps <= 3);

            printf(" x=%d, y=%d, components=%d\n", m_width, m_height, num_comps);
            uint8_t comp_id[3];
            uint8_t comp_sample_factor[3];
            uint8_t horiz_factor[3];
            uint8_t vert_factor[3];

            for (int x=0;x<num_comps;x++)
            {
                // First byte identifies the component
                comp_id[x] = get_byte(buf,i);
                // id: 1 = Y, 2 = Cb, 3 = Cr

                // Second byte represents sampling factor (first four MSBs represent horizonal, last four LSBs represent vertical)
                comp_sample_factor[x] = get_byte(buf,i);
                horiz_factor[x]       = comp_sample_factor[x] >> 4;
                vert_factor[x]        = comp_sample_factor[x] & 0xF;

                // Third byte represents which quantization table to use for this component
                m_dqt_table[x]        = get_byte(buf,i);
                printf(" num: %d a: %02x b: %02x\n", comp_id[x], comp_sample_factor[x], m_dqt_table[x]);
                printf(" horiz_factor: %d, vert_factor: %d\n", horiz_factor[x], vert_factor[x]);
            }

            m_mode = JPEG_UNSUPPORTED;

            // Single component (Y)
            if (num_comps == 1)
            {
                printf(" Mode: Monochrome\n");
                m_mode = JPEG_MONOCHROME;
            }
            // Colour image (YCbCr)
            else if (num_comps == 3)
            {
                // YCbCr ordering expected
                if (comp_id[0] == 1 && comp_id[1] == 2 && comp_id[2] == 3)
                {
                    if (horiz_factor[0] == 1 && vert_factor[0] == 1 &&
                        horiz_factor[1] == 1 && vert_factor[1] == 1 &&
                        horiz_factor[2] == 1 && vert_factor[2] == 1)
                    {
                        m_mode = JPEG_YCBCR_444;
                        printf(" Mode: YCbCr 4:4:4\n");
                    }
                    else if (horiz_factor[0] == 2 && vert_factor[0] == 2 &&
                             horiz_factor[1] == 1 && vert_factor[1] == 1 &&
                             horiz_factor[2] == 1 && vert_factor[2] == 1)
                    {
                        m_mode = JPEG_YCBCR_420;
                        printf(" Mode: YCbCr 4:2:0\n");
                    }
                }
            }

            i = seg_start + seg_len;
        }
        //-----------------------------------------------------------------------------
        // DQT: Quantisation table
        //-----------------------------------------------------------------------------
        else if (last_b == 0xFF && b == 0xdb)
        {
            printf("Section: DQT Table\n");
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            m_dqt.process(&buf[i], seg_len);
            i = seg_start + seg_len;
        }
        //-----------------------------------------------------------------------------
        // DHT: Huffman table
        //-----------------------------------------------------------------------------
        else if (last_b == 0xFF && b == 0xc4)
        {
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            printf("Section: DHT Table\n");
            m_dht.process(&buf[i], seg_len);
            i = seg_start + seg_len;
        }
        //-----------------------------------------------------------------------------
        // EOI: End of image
        //-----------------------------------------------------------------------------
        else if (last_b == 0xFF && b == 0xd9)
        {
            printf("Section: EOI\n");
            break;
        }
        //-----------------------------------------------------------------------------
        // SOS: Start of Scan Segment (SOS)
        //-----------------------------------------------------------------------------
        else if (last_b == 0xFF && b == 0xda)
        {
            printf("Section: SOS\n");
            int seg_start = i;

            if (m_mode == JPEG_UNSUPPORTED)
            {
                printf("ERROR: Unsupported JPEG mode\n");
                break;
            }

            uint16_t seg_len   = get_word(buf, i);

            // Component count (n)
            uint8_t  comp_count = get_byte(buf,i);

            // Component data
            for (int x=0;x<comp_count;x++)
            {
                // First byte denotes component ID
                uint8_t comp_id = get_byte(buf,i);

                // Second byte denotes the Huffman table used (first four MSBs denote Huffman table for DC, and last four LSBs denote Huffman table for AC)
                uint8_t comp_table = get_byte(buf,i);

                printf(" %d: ID=%x Table=%x\n", x, comp_id, comp_table);
            }

            // Skip bytes
            get_byte(buf,i);
            get_byte(buf,i);
            get_byte(buf,i);

            i = seg_start + seg_len;

            //-----------------------------------------------------------------------
            // Process data segment
            //-----------------------------------------------------------------------
            m_bit_buffer.reset(len);
            while (i < len)
            {
                b = buf[i];
                if (m_bit_buffer.push(b))
                    i++;
                // Marker detected (reverse one byte)
                else
                {
                    i--;
                    break;
                }
            }

            decode_done = DecodeImage();
        }
        //-----------------------------------------------------------------------------
        // Unsupported / Skipped
        //-----------------------------------------------------------------------------        
        else if (last_b == 0xFF && b == 0xc2)
        {
            printf("Section: SOF2\n");
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            i = seg_start + seg_len;

            printf("ERROR: Progressive JPEG not supported\n");
            break; // ERROR: Not supported
        }
        else if (last_b == 0xFF && b == 0xdd)
        {
            printf("Section: DRI\n");
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            i = seg_start + seg_len;            
        }
        else if (last_b == 0xFF && b >= 0xd0 && b <= 0xd7)
        {
            printf("Section: RST%d\n", b - 0xd0);
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            i = seg_start + seg_len;
        }
        else if (last_b == 0xFF && b >= 0xe0 && b <= 0xef)
        {
            printf("Section: APP%d\n", b - 0xe0);
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            i = seg_start + seg_len;
        }
        else if (last_b == 0xFF && b == 0xfe)
        {
            printf("Section: COM\n");
            int seg_start = i;
            uint16_t seg_len   = get_word(buf, i);
            i = seg_start + seg_len;
        }

        last_b = b;
    }

    if (decode_done)
    {
        FILE *f = fopen(dst_image, "w");
        if (f)
        {
            fprintf(f, "P6\n");
            fprintf(f, "%d %d\n", m_width, m_height);
            fprintf(f, "255\n");
            for (int y=0;y<m_height;y++)
                for (int x=0;x<m_width;x++)
                {
                    putc(m_output_r[(y*m_width)+x], f);
                    putc(m_output_g[(y*m_width)+x], f);
                    putc(m_output_b[(y*m_width)+x], f);
                }
            fclose(f);
        }
        else
        {
            fprintf(stderr, "ERROR: Could not write file\n");
            decode_done = false;
        }
    }

    if (m_output_r) delete [] m_output_r;
    if (m_output_g) delete [] m_output_g;
    if (m_output_b) delete [] m_output_b;
    return decode_done ? 0 : -1;
}


================================================
FILE: c_model/makefile
================================================
###############################################################################
# Makefile
###############################################################################

# Target
TARGET	   ?= jpeg

# Source Files
SRC_DIR    = .

CFLAGS	    = -O2 -fPIC
CFLAGS     += -Wno-format

INCLUDE_PATH += $(SRC_DIR)
CFLAGS       += $(patsubst %,-I%,$(INCLUDE_PATH))

LDFLAGS     = 
LIBS        = 

###############################################################################
# Variables
###############################################################################
OBJ_DIR      ?= obj/

###############################################################################
# Variables: Lists of objects, source and deps
###############################################################################
# SRC / Object list
src2obj       = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1)))

SRC          ?= $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp))
OBJ          ?= $(foreach src,$(SRC),$(call src2obj,$(src)))

###############################################################################
# Rules: Compilation macro
###############################################################################
define template_cpp
$(call src2obj,$(1)): $(1) | $(OBJ_DIR)
	@echo "# Compiling $(notdir $(1))"
	@g++ $(CFLAGS) -c $$< -o $$@
endef

###############################################################################
# Rules
###############################################################################
all: $(TARGET) 
	
$(OBJ_DIR):
	@mkdir -p $@

$(foreach src,$(SRC),$(eval $(call template_cpp,$(src))))	

$(TARGET): $(OBJ) makefile
	@echo "# Linking $(notdir $@)"
	@g++ $(LDFLAGS) $(OBJ) $(LIBS) -o $@

clean:
	-rm -rf $(OBJ_DIR) $(TARGET)


================================================
FILE: src_v/jpeg_bitbuffer.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_bitbuffer
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input           inport_valid_i
    ,input  [  7:0]  inport_data_i
    ,input           inport_last_i
    ,input  [  5:0]  outport_pop_i

    // Outputs
    ,output          inport_accept_o
    ,output          outport_valid_o
    ,output [ 31:0]  outport_data_o
    ,output          outport_last_o
);



//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [7:0] ram_q[7:0];
reg [5:0] rd_ptr_q;
reg [5:0] wr_ptr_q;
reg [6:0] count_q;
reg       drain_q;

//-----------------------------------------------------------------
// Input side FIFO
//-----------------------------------------------------------------
reg [6:0] count_r; 
always @ *
begin
    count_r = count_q;

    // Count up
    if (inport_valid_i && inport_accept_o)
        count_r = count_r + 7'd8;

    // Count down
    if (outport_valid_o && (|outport_pop_i))
        count_r = count_r - outport_pop_i;
end

always @ (posedge clk_i )
if (rst_i)
begin
    count_q   <= 7'b0;
    rd_ptr_q  <= 6'b0;
    wr_ptr_q  <= 6'b0;
    drain_q   <= 1'b0;
end
else if (img_start_i)
begin
    count_q   <= 7'b0;
    rd_ptr_q  <= 6'b0;
    wr_ptr_q  <= 6'b0;
    drain_q   <= 1'b0;
end
else
begin
    // End of image
    if (inport_last_i)
        drain_q <= 1'b1;

    // Push
    if (inport_valid_i && inport_accept_o)
    begin
        ram_q[wr_ptr_q[5:3]] <= inport_data_i;
        wr_ptr_q             <= wr_ptr_q + 6'd8;
    end

    // Pop
    if (outport_valid_o && (|outport_pop_i))
        rd_ptr_q <= rd_ptr_q + outport_pop_i;

    count_q <= count_r;
end

assign inport_accept_o = (count_q <= 7'd56);

//-------------------------------------------------------------------
// Output side FIFO
//-------------------------------------------------------------------
reg [39:0] fifo_data_r;

always @ *
begin
    fifo_data_r = 40'b0;

    case (rd_ptr_q[5:3])
    3'd0: fifo_data_r = {ram_q[0], ram_q[1], ram_q[2], ram_q[3], ram_q[4]};
    3'd1: fifo_data_r = {ram_q[1], ram_q[2], ram_q[3], ram_q[4], ram_q[5]};
    3'd2: fifo_data_r = {ram_q[2], ram_q[3], ram_q[4], ram_q[5], ram_q[6]};
    3'd3: fifo_data_r = {ram_q[3], ram_q[4], ram_q[5], ram_q[6], ram_q[7]};
    3'd4: fifo_data_r = {ram_q[4], ram_q[5], ram_q[6], ram_q[7], ram_q[0]};
    3'd5: fifo_data_r = {ram_q[5], ram_q[6], ram_q[7], ram_q[0], ram_q[1]};
    3'd6: fifo_data_r = {ram_q[6], ram_q[7], ram_q[0], ram_q[1], ram_q[2]};
    3'd7: fifo_data_r = {ram_q[7], ram_q[0], ram_q[1], ram_q[2], ram_q[3]};
    endcase
end

wire [39:0] data_shifted_w = fifo_data_r << rd_ptr_q[2:0];

assign outport_valid_o  = (count_q >= 7'd32) || (drain_q && count_q != 7'd0);
assign outport_data_o   = data_shifted_w[39:8];
assign outport_last_o   = 1'b0;


`ifdef verilator
function get_valid; /*verilator public*/
begin
    get_valid = inport_valid_i && inport_accept_o;
end
endfunction
function [7:0] get_data; /*verilator public*/
begin
    get_data = inport_data_i;
end
endfunction
`endif




endmodule


================================================
FILE: src_v/jpeg_core.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_core
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
     parameter SUPPORT_WRITABLE_DHT = 0
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           inport_valid_i
    ,input  [ 31:0]  inport_data_i
    ,input  [  3:0]  inport_strb_i
    ,input           inport_last_i
    ,input           outport_accept_i

    // Outputs
    ,output          inport_accept_o
    ,output          outport_valid_o
    ,output [ 15:0]  outport_width_o
    ,output [ 15:0]  outport_height_o
    ,output [ 15:0]  outport_pixel_x_o
    ,output [ 15:0]  outport_pixel_y_o
    ,output [  7:0]  outport_pixel_r_o
    ,output [  7:0]  outport_pixel_g_o
    ,output [  7:0]  outport_pixel_b_o
    ,output          idle_o
);

wire  [ 15:0]  idct_outport_data_w;
wire           dqt_inport_valid_w;
wire  [ 31:0]  dqt_inport_id_w;
wire  [ 31:0]  output_outport_data_w;
wire  [  5:0]  idct_inport_idx_w;
wire           dqt_inport_eob_w;
wire           img_start_w;
wire  [ 15:0]  img_height_w;
wire           output_inport_accept_w;
wire  [ 15:0]  img_width_w;
wire           dht_cfg_valid_w;
wire           lookup_req_w;
wire           lookup_valid_w;
wire  [  1:0]  img_dqt_table_cb_w;
wire  [  7:0]  dht_cfg_data_w;
wire           img_end_w;
wire  [ 31:0]  idct_inport_id_w;
wire  [  4:0]  lookup_width_w;
wire           idct_inport_accept_w;
wire  [  5:0]  output_inport_idx_w;
wire  [ 15:0]  dqt_outport_data_w;
wire           dqt_inport_blk_space_w;
wire           idct_inport_valid_w;
wire  [  7:0]  dqt_cfg_data_w;
wire  [  1:0]  img_dqt_table_y_w;
wire           idct_inport_eob_w;
wire           dht_cfg_accept_w;
wire  [ 31:0]  output_inport_id_w;
wire           output_inport_valid_w;
wire  [ 15:0]  lookup_input_w;
wire           dqt_cfg_accept_w;
wire  [  7:0]  lookup_value_w;
wire  [  1:0]  lookup_table_w;
wire           dht_cfg_last_w;
wire  [  5:0]  dqt_inport_idx_w;
wire  [  1:0]  img_mode_w;
wire  [  1:0]  img_dqt_table_cr_w;
wire           bb_inport_valid_w;
wire           bb_outport_last_w;
wire           bb_inport_last_w;
wire  [  5:0]  bb_outport_pop_w;
wire  [  7:0]  bb_inport_data_w;
wire           dqt_cfg_valid_w;
wire           bb_outport_valid_w;
wire           bb_inport_accept_w;
wire  [ 31:0]  bb_outport_data_w;
wire           dqt_cfg_last_w;


jpeg_input
u_jpeg_input
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.inport_valid_i(inport_valid_i)
    ,.inport_data_i(inport_data_i)
    ,.inport_strb_i(inport_strb_i)
    ,.inport_last_i(inport_last_i)
    ,.dqt_cfg_accept_i(dqt_cfg_accept_w)
    ,.dht_cfg_accept_i(dht_cfg_accept_w)
    ,.data_accept_i(bb_inport_accept_w)

    // Outputs
    ,.inport_accept_o(inport_accept_o)
    ,.img_start_o(img_start_w)
    ,.img_end_o(img_end_w)
    ,.img_width_o(img_width_w)
    ,.img_height_o(img_height_w)
    ,.img_mode_o(img_mode_w)
    ,.img_dqt_table_y_o(img_dqt_table_y_w)
    ,.img_dqt_table_cb_o(img_dqt_table_cb_w)
    ,.img_dqt_table_cr_o(img_dqt_table_cr_w)
    ,.dqt_cfg_valid_o(dqt_cfg_valid_w)
    ,.dqt_cfg_data_o(dqt_cfg_data_w)
    ,.dqt_cfg_last_o(dqt_cfg_last_w)
    ,.dht_cfg_valid_o(dht_cfg_valid_w)
    ,.dht_cfg_data_o(dht_cfg_data_w)
    ,.dht_cfg_last_o(dht_cfg_last_w)
    ,.data_valid_o(bb_inport_valid_w)
    ,.data_data_o(bb_inport_data_w)
    ,.data_last_o(bb_inport_last_w)
);


jpeg_dht
#(
     .SUPPORT_WRITABLE_DHT(SUPPORT_WRITABLE_DHT)
)
u_jpeg_dht
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.cfg_valid_i(dht_cfg_valid_w)
    ,.cfg_data_i(dht_cfg_data_w)
    ,.cfg_last_i(dht_cfg_last_w)
    ,.lookup_req_i(lookup_req_w)
    ,.lookup_table_i(lookup_table_w)
    ,.lookup_input_i(lookup_input_w)

    // Outputs
    ,.cfg_accept_o(dht_cfg_accept_w)
    ,.lookup_valid_o(lookup_valid_w)
    ,.lookup_width_o(lookup_width_w)
    ,.lookup_value_o(lookup_value_w)
);


jpeg_idct
u_jpeg_idct
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.img_start_i(img_start_w)
    ,.img_end_i(img_end_w)
    ,.inport_valid_i(idct_inport_valid_w)
    ,.inport_data_i(idct_outport_data_w)
    ,.inport_idx_i(idct_inport_idx_w)
    ,.inport_eob_i(idct_inport_eob_w)
    ,.inport_id_i(idct_inport_id_w)
    ,.outport_accept_i(output_inport_accept_w)

    // Outputs
    ,.inport_accept_o(idct_inport_accept_w)
    ,.outport_valid_o(output_inport_valid_w)
    ,.outport_data_o(output_outport_data_w)
    ,.outport_idx_o(output_inport_idx_w)
    ,.outport_id_o(output_inport_id_w)
);


jpeg_dqt
u_jpeg_dqt
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.img_start_i(img_start_w)
    ,.img_end_i(img_end_w)
    ,.img_dqt_table_y_i(img_dqt_table_y_w)
    ,.img_dqt_table_cb_i(img_dqt_table_cb_w)
    ,.img_dqt_table_cr_i(img_dqt_table_cr_w)
    ,.cfg_valid_i(dqt_cfg_valid_w)
    ,.cfg_data_i(dqt_cfg_data_w)
    ,.cfg_last_i(dqt_cfg_last_w)
    ,.inport_valid_i(dqt_inport_valid_w)
    ,.inport_data_i(dqt_outport_data_w)
    ,.inport_idx_i(dqt_inport_idx_w)
    ,.inport_id_i(dqt_inport_id_w)
    ,.inport_eob_i(dqt_inport_eob_w)
    ,.outport_accept_i(idct_inport_accept_w)

    // Outputs
    ,.cfg_accept_o(dqt_cfg_accept_w)
    ,.inport_blk_space_o(dqt_inport_blk_space_w)
    ,.outport_valid_o(idct_inport_valid_w)
    ,.outport_data_o(idct_outport_data_w)
    ,.outport_idx_o(idct_inport_idx_w)
    ,.outport_id_o(idct_inport_id_w)
    ,.outport_eob_o(idct_inport_eob_w)
);


jpeg_output
u_jpeg_output
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.img_start_i(img_start_w)
    ,.img_end_i(img_end_w)
    ,.img_width_i(img_width_w)
    ,.img_height_i(img_height_w)
    ,.img_mode_i(img_mode_w)
    ,.inport_valid_i(output_inport_valid_w)
    ,.inport_data_i(output_outport_data_w)
    ,.inport_idx_i(output_inport_idx_w)
    ,.inport_id_i(output_inport_id_w)
    ,.outport_accept_i(outport_accept_i)

    // Outputs
    ,.inport_accept_o(output_inport_accept_w)
    ,.outport_valid_o(outport_valid_o)
    ,.outport_width_o(outport_width_o)
    ,.outport_height_o(outport_height_o)
    ,.outport_pixel_x_o(outport_pixel_x_o)
    ,.outport_pixel_y_o(outport_pixel_y_o)
    ,.outport_pixel_r_o(outport_pixel_r_o)
    ,.outport_pixel_g_o(outport_pixel_g_o)
    ,.outport_pixel_b_o(outport_pixel_b_o)
    ,.idle_o(idle_o)
);


jpeg_bitbuffer
u_jpeg_bitbuffer
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.img_start_i(img_start_w)
    ,.img_end_i(img_end_w)
    ,.inport_valid_i(bb_inport_valid_w)
    ,.inport_data_i(bb_inport_data_w)
    ,.inport_last_i(bb_inport_last_w)
    ,.outport_pop_i(bb_outport_pop_w)

    // Outputs
    ,.inport_accept_o(bb_inport_accept_w)
    ,.outport_valid_o(bb_outport_valid_w)
    ,.outport_data_o(bb_outport_data_w)
    ,.outport_last_o(bb_outport_last_w)
);


jpeg_mcu_proc
u_jpeg_mcu_proc
(
    // Inputs
     .clk_i(clk_i)
    ,.rst_i(rst_i)
    ,.img_start_i(img_start_w)
    ,.img_end_i(img_end_w)
    ,.img_width_i(img_width_w)
    ,.img_height_i(img_height_w)
    ,.img_mode_i(img_mode_w)
    ,.inport_valid_i(bb_outport_valid_w)
    ,.inport_data_i(bb_outport_data_w)
    ,.inport_last_i(bb_outport_last_w)
    ,.lookup_valid_i(lookup_valid_w)
    ,.lookup_width_i(lookup_width_w)
    ,.lookup_value_i(lookup_value_w)
    ,.outport_blk_space_i(dqt_inport_blk_space_w)

    // Outputs
    ,.inport_pop_o(bb_outport_pop_w)
    ,.lookup_req_o(lookup_req_w)
    ,.lookup_table_o(lookup_table_w)
    ,.lookup_input_o(lookup_input_w)
    ,.outport_valid_o(dqt_inport_valid_w)
    ,.outport_data_o(dqt_outport_data_w)
    ,.outport_idx_o(dqt_inport_idx_w)
    ,.outport_id_o(dqt_inport_id_w)
    ,.outport_eob_o(dqt_inport_eob_w)
);



endmodule


================================================
FILE: src_v/jpeg_dht.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_dht
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
     parameter SUPPORT_WRITABLE_DHT = 0
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           cfg_valid_i
    ,input  [  7:0]  cfg_data_i
    ,input           cfg_last_i
    ,input           lookup_req_i
    ,input  [  1:0]  lookup_table_i
    ,input  [ 15:0]  lookup_input_i

    // Outputs
    ,output          cfg_accept_o
    ,output          lookup_valid_o
    ,output [  4:0]  lookup_width_o
    ,output [  7:0]  lookup_value_o
);




localparam DHT_TABLE_Y_DC      = 8'h00;
localparam DHT_TABLE_Y_AC      = 8'h10;
localparam DHT_TABLE_CX_DC     = 8'h01;
localparam DHT_TABLE_CX_AC     = 8'h11;

//---------------------------------------------------------------------
// Support writable huffman tables (e.g. file contains optimised tables)
//---------------------------------------------------------------------
generate
if (SUPPORT_WRITABLE_DHT)
begin
    reg [15:0] y_dc_min_code_q[0:15];
    reg [15:0] y_dc_max_code_q[0:15];
    reg [9:0]  y_dc_ptr_q[0:15];
    reg [15:0] y_ac_min_code_q[0:15];
    reg [15:0] y_ac_max_code_q[0:15];
    reg [9:0]  y_ac_ptr_q[0:15];
    reg [15:0] cx_dc_min_code_q[0:15];
    reg [15:0] cx_dc_max_code_q[0:15];
    reg [9:0]  cx_dc_ptr_q[0:15];
    reg [15:0] cx_ac_min_code_q[0:15];
    reg [15:0] cx_ac_max_code_q[0:15];
    reg [9:0]  cx_ac_ptr_q[0:15];

    // DHT tables can be combined into one section...
    // Reset the table state machine at the end of each table
    wire cfg_last_w = cfg_last_i || (total_entries_q == idx_q && idx_q >= 12'd16);

    //-----------------------------------------------------------------
    // Capture Index
    //-----------------------------------------------------------------
    reg [11:0] idx_q;

    always @ (posedge clk_i )
    if (rst_i)
        idx_q <= 12'hFFF;
    else if (cfg_valid_i && cfg_last_w && cfg_accept_o)
        idx_q <= 12'hFFF;
    else if (cfg_valid_i && cfg_accept_o)
        idx_q <= idx_q + 12'd1;

    //-----------------------------------------------------------------
    // Table Index
    //-----------------------------------------------------------------
    reg [7:0] cfg_table_q;

    always @ (posedge clk_i )
    if (rst_i)
        cfg_table_q <= 8'b0;
    else if (cfg_valid_i && cfg_accept_o && idx_q == 12'hFFF)
        cfg_table_q <= cfg_data_i;

    //-----------------------------------------------------------------
    // Extract symbol count (temporary)
    //-----------------------------------------------------------------
    reg [7:0]  num_entries_q[0:15];
    reg [15:0] has_entries_q; // bitmap
    reg [11:0] total_entries_q;

    always @ (posedge clk_i )
    if (rst_i)
    begin
        num_entries_q[0] <= 8'b0;
        num_entries_q[1] <= 8'b0;
        num_entries_q[2] <= 8'b0;
        num_entries_q[3] <= 8'b0;
        num_entries_q[4] <= 8'b0;
        num_entries_q[5] <= 8'b0;
        num_entries_q[6] <= 8'b0;
        num_entries_q[7] <= 8'b0;
        num_entries_q[8] <= 8'b0;
        num_entries_q[9] <= 8'b0;
        num_entries_q[10] <= 8'b0;
        num_entries_q[11] <= 8'b0;
        num_entries_q[12] <= 8'b0;
        num_entries_q[13] <= 8'b0;
        num_entries_q[14] <= 8'b0;
        num_entries_q[15] <= 8'b0;
        has_entries_q   <= 16'b0;
        total_entries_q <= 12'd15;
    end
    else if (cfg_valid_i && cfg_accept_o && idx_q < 12'd16)
    begin
        num_entries_q[idx_q[3:0]] <= cfg_data_i;
        has_entries_q[idx_q[3:0]] <= (cfg_data_i != 8'b0);
        total_entries_q           <= total_entries_q + {4'b0, cfg_data_i};
    end
    // End of DHT table
    else if (cfg_valid_i && cfg_last_w && cfg_accept_o)
    begin
        num_entries_q[0] <= 8'b0;
        num_entries_q[1] <= 8'b0;
        num_entries_q[2] <= 8'b0;
        num_entries_q[3] <= 8'b0;
        num_entries_q[4] <= 8'b0;
        num_entries_q[5] <= 8'b0;
        num_entries_q[6] <= 8'b0;
        num_entries_q[7] <= 8'b0;
        num_entries_q[8] <= 8'b0;
        num_entries_q[9] <= 8'b0;
        num_entries_q[10] <= 8'b0;
        num_entries_q[11] <= 8'b0;
        num_entries_q[12] <= 8'b0;
        num_entries_q[13] <= 8'b0;
        num_entries_q[14] <= 8'b0;
        num_entries_q[15] <= 8'b0;
        has_entries_q   <= 16'b0;
        total_entries_q <= 12'd15;
    end

    //-----------------------------------------------------------------
    // Fill tables
    //-----------------------------------------------------------------
    reg [3:0]  i_q;
    reg [7:0]  j_q;
    reg [15:0] code_q;
    reg [9:0]  next_ptr_q;

    always @ (posedge clk_i )
    if (rst_i)
    begin
        y_dc_min_code_q[0] <= 16'b0;
        y_dc_max_code_q[0] <= 16'b0;
        y_dc_ptr_q[0]      <= 10'b0;
        y_dc_min_code_q[1] <= 16'b0;
        y_dc_max_code_q[1] <= 16'b0;
        y_dc_ptr_q[1]      <= 10'b0;
        y_dc_min_code_q[2] <= 16'b0;
        y_dc_max_code_q[2] <= 16'b0;
        y_dc_ptr_q[2]      <= 10'b0;
        y_dc_min_code_q[3] <= 16'b0;
        y_dc_max_code_q[3] <= 16'b0;
        y_dc_ptr_q[3]      <= 10'b0;
        y_dc_min_code_q[4] <= 16'b0;
        y_dc_max_code_q[4] <= 16'b0;
        y_dc_ptr_q[4]      <= 10'b0;
        y_dc_min_code_q[5] <= 16'b0;
        y_dc_max_code_q[5] <= 16'b0;
        y_dc_ptr_q[5]      <= 10'b0;
        y_dc_min_code_q[6] <= 16'b0;
        y_dc_max_code_q[6] <= 16'b0;
        y_dc_ptr_q[6]      <= 10'b0;
        y_dc_min_code_q[7] <= 16'b0;
        y_dc_max_code_q[7] <= 16'b0;
        y_dc_ptr_q[7]      <= 10'b0;
        y_dc_min_code_q[8] <= 16'b0;
        y_dc_max_code_q[8] <= 16'b0;
        y_dc_ptr_q[8]      <= 10'b0;
        y_dc_min_code_q[9] <= 16'b0;
        y_dc_max_code_q[9] <= 16'b0;
        y_dc_ptr_q[9]      <= 10'b0;
        y_dc_min_code_q[10] <= 16'b0;
        y_dc_max_code_q[10] <= 16'b0;
        y_dc_ptr_q[10]      <= 10'b0;
        y_dc_min_code_q[11] <= 16'b0;
        y_dc_max_code_q[11] <= 16'b0;
        y_dc_ptr_q[11]      <= 10'b0;
        y_dc_min_code_q[12] <= 16'b0;
        y_dc_max_code_q[12] <= 16'b0;
        y_dc_ptr_q[12]      <= 10'b0;
        y_dc_min_code_q[13] <= 16'b0;
        y_dc_max_code_q[13] <= 16'b0;
        y_dc_ptr_q[13]      <= 10'b0;
        y_dc_min_code_q[14] <= 16'b0;
        y_dc_max_code_q[14] <= 16'b0;
        y_dc_ptr_q[14]      <= 10'b0;
        y_dc_min_code_q[15] <= 16'b0;
        y_dc_max_code_q[15] <= 16'b0;
        y_dc_ptr_q[15]      <= 10'b0;
        y_ac_min_code_q[0] <= 16'b0;
        y_ac_max_code_q[0] <= 16'b0;
        y_ac_ptr_q[0]      <= 10'b0;
        y_ac_min_code_q[1] <= 16'b0;
        y_ac_max_code_q[1] <= 16'b0;
        y_ac_ptr_q[1]      <= 10'b0;
        y_ac_min_code_q[2] <= 16'b0;
        y_ac_max_code_q[2] <= 16'b0;
        y_ac_ptr_q[2]      <= 10'b0;
        y_ac_min_code_q[3] <= 16'b0;
        y_ac_max_code_q[3] <= 16'b0;
        y_ac_ptr_q[3]      <= 10'b0;
        y_ac_min_code_q[4] <= 16'b0;
        y_ac_max_code_q[4] <= 16'b0;
        y_ac_ptr_q[4]      <= 10'b0;
        y_ac_min_code_q[5] <= 16'b0;
        y_ac_max_code_q[5] <= 16'b0;
        y_ac_ptr_q[5]      <= 10'b0;
        y_ac_min_code_q[6] <= 16'b0;
        y_ac_max_code_q[6] <= 16'b0;
        y_ac_ptr_q[6]      <= 10'b0;
        y_ac_min_code_q[7] <= 16'b0;
        y_ac_max_code_q[7] <= 16'b0;
        y_ac_ptr_q[7]      <= 10'b0;
        y_ac_min_code_q[8] <= 16'b0;
        y_ac_max_code_q[8] <= 16'b0;
        y_ac_ptr_q[8]      <= 10'b0;
        y_ac_min_code_q[9] <= 16'b0;
        y_ac_max_code_q[9] <= 16'b0;
        y_ac_ptr_q[9]      <= 10'b0;
        y_ac_min_code_q[10] <= 16'b0;
        y_ac_max_code_q[10] <= 16'b0;
        y_ac_ptr_q[10]      <= 10'b0;
        y_ac_min_code_q[11] <= 16'b0;
        y_ac_max_code_q[11] <= 16'b0;
        y_ac_ptr_q[11]      <= 10'b0;
        y_ac_min_code_q[12] <= 16'b0;
        y_ac_max_code_q[12] <= 16'b0;
        y_ac_ptr_q[12]      <= 10'b0;
        y_ac_min_code_q[13] <= 16'b0;
        y_ac_max_code_q[13] <= 16'b0;
        y_ac_ptr_q[13]      <= 10'b0;
        y_ac_min_code_q[14] <= 16'b0;
        y_ac_max_code_q[14] <= 16'b0;
        y_ac_ptr_q[14]      <= 10'b0;
        y_ac_min_code_q[15] <= 16'b0;
        y_ac_max_code_q[15] <= 16'b0;
        y_ac_ptr_q[15]      <= 10'b0;
        cx_dc_min_code_q[0] <= 16'b0;
        cx_dc_max_code_q[0] <= 16'b0;
        cx_dc_ptr_q[0]      <= 10'b0;
        cx_dc_min_code_q[1] <= 16'b0;
        cx_dc_max_code_q[1] <= 16'b0;
        cx_dc_ptr_q[1]      <= 10'b0;
        cx_dc_min_code_q[2] <= 16'b0;
        cx_dc_max_code_q[2] <= 16'b0;
        cx_dc_ptr_q[2]      <= 10'b0;
        cx_dc_min_code_q[3] <= 16'b0;
        cx_dc_max_code_q[3] <= 16'b0;
        cx_dc_ptr_q[3]      <= 10'b0;
        cx_dc_min_code_q[4] <= 16'b0;
        cx_dc_max_code_q[4] <= 16'b0;
        cx_dc_ptr_q[4]      <= 10'b0;
        cx_dc_min_code_q[5] <= 16'b0;
        cx_dc_max_code_q[5] <= 16'b0;
        cx_dc_ptr_q[5]      <= 10'b0;
        cx_dc_min_code_q[6] <= 16'b0;
        cx_dc_max_code_q[6] <= 16'b0;
        cx_dc_ptr_q[6]      <= 10'b0;
        cx_dc_min_code_q[7] <= 16'b0;
        cx_dc_max_code_q[7] <= 16'b0;
        cx_dc_ptr_q[7]      <= 10'b0;
        cx_dc_min_code_q[8] <= 16'b0;
        cx_dc_max_code_q[8] <= 16'b0;
        cx_dc_ptr_q[8]      <= 10'b0;
        cx_dc_min_code_q[9] <= 16'b0;
        cx_dc_max_code_q[9] <= 16'b0;
        cx_dc_ptr_q[9]      <= 10'b0;
        cx_dc_min_code_q[10] <= 16'b0;
        cx_dc_max_code_q[10] <= 16'b0;
        cx_dc_ptr_q[10]      <= 10'b0;
        cx_dc_min_code_q[11] <= 16'b0;
        cx_dc_max_code_q[11] <= 16'b0;
        cx_dc_ptr_q[11]      <= 10'b0;
        cx_dc_min_code_q[12] <= 16'b0;
        cx_dc_max_code_q[12] <= 16'b0;
        cx_dc_ptr_q[12]      <= 10'b0;
        cx_dc_min_code_q[13] <= 16'b0;
        cx_dc_max_code_q[13] <= 16'b0;
        cx_dc_ptr_q[13]      <= 10'b0;
        cx_dc_min_code_q[14] <= 16'b0;
        cx_dc_max_code_q[14] <= 16'b0;
        cx_dc_ptr_q[14]      <= 10'b0;
        cx_dc_min_code_q[15] <= 16'b0;
        cx_dc_max_code_q[15] <= 16'b0;
        cx_dc_ptr_q[15]      <= 10'b0;
        cx_ac_min_code_q[0] <= 16'b0;
        cx_ac_max_code_q[0] <= 16'b0;
        cx_ac_ptr_q[0]      <= 10'b0;
        cx_ac_min_code_q[1] <= 16'b0;
        cx_ac_max_code_q[1] <= 16'b0;
        cx_ac_ptr_q[1]      <= 10'b0;
        cx_ac_min_code_q[2] <= 16'b0;
        cx_ac_max_code_q[2] <= 16'b0;
        cx_ac_ptr_q[2]      <= 10'b0;
        cx_ac_min_code_q[3] <= 16'b0;
        cx_ac_max_code_q[3] <= 16'b0;
        cx_ac_ptr_q[3]      <= 10'b0;
        cx_ac_min_code_q[4] <= 16'b0;
        cx_ac_max_code_q[4] <= 16'b0;
        cx_ac_ptr_q[4]      <= 10'b0;
        cx_ac_min_code_q[5] <= 16'b0;
        cx_ac_max_code_q[5] <= 16'b0;
        cx_ac_ptr_q[5]      <= 10'b0;
        cx_ac_min_code_q[6] <= 16'b0;
        cx_ac_max_code_q[6] <= 16'b0;
        cx_ac_ptr_q[6]      <= 10'b0;
        cx_ac_min_code_q[7] <= 16'b0;
        cx_ac_max_code_q[7] <= 16'b0;
        cx_ac_ptr_q[7]      <= 10'b0;
        cx_ac_min_code_q[8] <= 16'b0;
        cx_ac_max_code_q[8] <= 16'b0;
        cx_ac_ptr_q[8]      <= 10'b0;
        cx_ac_min_code_q[9] <= 16'b0;
        cx_ac_max_code_q[9] <= 16'b0;
        cx_ac_ptr_q[9]      <= 10'b0;
        cx_ac_min_code_q[10] <= 16'b0;
        cx_ac_max_code_q[10] <= 16'b0;
        cx_ac_ptr_q[10]      <= 10'b0;
        cx_ac_min_code_q[11] <= 16'b0;
        cx_ac_max_code_q[11] <= 16'b0;
        cx_ac_ptr_q[11]      <= 10'b0;
        cx_ac_min_code_q[12] <= 16'b0;
        cx_ac_max_code_q[12] <= 16'b0;
        cx_ac_ptr_q[12]      <= 10'b0;
        cx_ac_min_code_q[13] <= 16'b0;
        cx_ac_max_code_q[13] <= 16'b0;
        cx_ac_ptr_q[13]      <= 10'b0;
        cx_ac_min_code_q[14] <= 16'b0;
        cx_ac_max_code_q[14] <= 16'b0;
        cx_ac_ptr_q[14]      <= 10'b0;
        cx_ac_min_code_q[15] <= 16'b0;
        cx_ac_max_code_q[15] <= 16'b0;
        cx_ac_ptr_q[15]      <= 10'b0;
        j_q    <= 8'b0;
        i_q    <= 4'b0;
        code_q <= 16'b0;
    end
    else if (idx_q < 12'd16 || idx_q == 12'hFFF)
    begin
        j_q    <= 8'b0;
        i_q    <= 4'b0;
        code_q <= 16'b0;
    end
    else if (cfg_valid_i && cfg_accept_o)
    begin
        if (j_q == 8'b0)
        begin
            case (cfg_table_q)
            DHT_TABLE_Y_DC:
            begin
                y_dc_min_code_q[i_q] <= code_q;
                y_dc_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};
                y_dc_ptr_q[i_q]      <= next_ptr_q;
            end
            DHT_TABLE_Y_AC:
            begin
                y_ac_min_code_q[i_q] <= code_q;
                y_ac_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};
                y_ac_ptr_q[i_q]      <= next_ptr_q;
            end
            DHT_TABLE_CX_DC:
            begin
                cx_dc_min_code_q[i_q] <= code_q;
                cx_dc_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};
                cx_dc_ptr_q[i_q]      <= next_ptr_q;
            end
            default:
            begin
                cx_ac_min_code_q[i_q] <= code_q;
                cx_ac_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};
                cx_ac_ptr_q[i_q]      <= next_ptr_q;
            end
            endcase
        end

        if ((j_q + 8'd1) == num_entries_q[i_q])
        begin
            j_q <= 8'b0;
            i_q <= i_q + 4'd1;
            code_q <= (code_q + 16'd1) << 1;
        end
        else
        begin
            code_q <= code_q + 16'd1;
            j_q    <= j_q + 8'd1;
        end
    end
    // Increment through empty bit widths
    else if (cfg_valid_i && !cfg_accept_o)
    begin
        i_q    <= i_q + 4'd1;
        code_q <= code_q << 1;
    end

    assign cfg_accept_o = has_entries_q[i_q] || (idx_q < 12'd16) || (idx_q == 12'hFFF);

    //-----------------------------------------------------------------
    // Code table write pointer
    //-----------------------------------------------------------------
    wire alloc_entry_w = cfg_valid_i && cfg_accept_o && (idx_q >= 12'd16 && idx_q != 12'hFFF);    

    always @ (posedge clk_i )
    if (rst_i)
        next_ptr_q <= 10'b0;
    else if (alloc_entry_w)
        next_ptr_q <= next_ptr_q + 10'd1;

    //-----------------------------------------------------------------
    // Lookup: Match shortest bit sequence
    //-----------------------------------------------------------------

    reg [3:0] y_dc_width_r;
    always @ *
    begin
        y_dc_width_r = 4'b0;

        if ({15'b0, lookup_input_i[15]} < y_dc_max_code_q[0])
            y_dc_width_r = 4'd0;
        else if ({14'b0, lookup_input_i[15:14]} < y_dc_max_code_q[1])
            y_dc_width_r = 4'd1;
        else if ({13'b0, lookup_input_i[15:13]} < y_dc_max_code_q[2])
            y_dc_width_r = 4'd2;
        else if ({12'b0, lookup_input_i[15:12]} < y_dc_max_code_q[3])
            y_dc_width_r = 4'd3;
        else if ({11'b0, lookup_input_i[15:11]} < y_dc_max_code_q[4])
            y_dc_width_r = 4'd4;
        else if ({10'b0, lookup_input_i[15:10]} < y_dc_max_code_q[5])
            y_dc_width_r = 4'd5;
        else if ({9'b0, lookup_input_i[15:9]} < y_dc_max_code_q[6])
            y_dc_width_r = 4'd6;
        else if ({8'b0, lookup_input_i[15:8]} < y_dc_max_code_q[7])
            y_dc_width_r = 4'd7;
        else if ({7'b0, lookup_input_i[15:7]} < y_dc_max_code_q[8])
            y_dc_width_r = 4'd8;
        else if ({6'b0, lookup_input_i[15:6]} < y_dc_max_code_q[9])
            y_dc_width_r = 4'd9;
        else if ({5'b0, lookup_input_i[15:5]} < y_dc_max_code_q[10])
            y_dc_width_r = 4'd10;
        else if ({4'b0, lookup_input_i[15:4]} < y_dc_max_code_q[11])
            y_dc_width_r = 4'd11;
        else if ({3'b0, lookup_input_i[15:3]} < y_dc_max_code_q[12])
            y_dc_width_r = 4'd12;
        else if ({2'b0, lookup_input_i[15:2]} < y_dc_max_code_q[13])
            y_dc_width_r = 4'd13;
        else if ({1'b0, lookup_input_i[15:1]} < y_dc_max_code_q[14])
            y_dc_width_r = 4'd14;
        else
            y_dc_width_r = 4'd15;
    end

    reg [3:0] y_ac_width_r;
    always @ *
    begin
        y_ac_width_r = 4'b0;

        if ({15'b0, lookup_input_i[15]} < y_ac_max_code_q[0])
            y_ac_width_r = 4'd0;
        else if ({14'b0, lookup_input_i[15:14]} < y_ac_max_code_q[1])
            y_ac_width_r = 4'd1;
        else if ({13'b0, lookup_input_i[15:13]} < y_ac_max_code_q[2])
            y_ac_width_r = 4'd2;
        else if ({12'b0, lookup_input_i[15:12]} < y_ac_max_code_q[3])
            y_ac_width_r = 4'd3;
        else if ({11'b0, lookup_input_i[15:11]} < y_ac_max_code_q[4])
            y_ac_width_r = 4'd4;
        else if ({10'b0, lookup_input_i[15:10]} < y_ac_max_code_q[5])
            y_ac_width_r = 4'd5;
        else if ({9'b0, lookup_input_i[15:9]} < y_ac_max_code_q[6])
            y_ac_width_r = 4'd6;
        else if ({8'b0, lookup_input_i[15:8]} < y_ac_max_code_q[7])
            y_ac_width_r = 4'd7;
        else if ({7'b0, lookup_input_i[15:7]} < y_ac_max_code_q[8])
            y_ac_width_r = 4'd8;
        else if ({6'b0, lookup_input_i[15:6]} < y_ac_max_code_q[9])
            y_ac_width_r = 4'd9;
        else if ({5'b0, lookup_input_i[15:5]} < y_ac_max_code_q[10])
            y_ac_width_r = 4'd10;
        else if ({4'b0, lookup_input_i[15:4]} < y_ac_max_code_q[11])
            y_ac_width_r = 4'd11;
        else if ({3'b0, lookup_input_i[15:3]} < y_ac_max_code_q[12])
            y_ac_width_r = 4'd12;
        else if ({2'b0, lookup_input_i[15:2]} < y_ac_max_code_q[13])
            y_ac_width_r = 4'd13;
        else if ({1'b0, lookup_input_i[15:1]} < y_ac_max_code_q[14])
            y_ac_width_r = 4'd14;
        else
            y_ac_width_r = 4'd15;
    end

    reg [3:0] cx_dc_width_r;
    always @ *
    begin
        cx_dc_width_r = 4'b0;

        if ({15'b0, lookup_input_i[15]} < cx_dc_max_code_q[0])
            cx_dc_width_r = 4'd0;
        else if ({14'b0, lookup_input_i[15:14]} < cx_dc_max_code_q[1])
            cx_dc_width_r = 4'd1;
        else if ({13'b0, lookup_input_i[15:13]} < cx_dc_max_code_q[2])
            cx_dc_width_r = 4'd2;
        else if ({12'b0, lookup_input_i[15:12]} < cx_dc_max_code_q[3])
            cx_dc_width_r = 4'd3;
        else if ({11'b0, lookup_input_i[15:11]} < cx_dc_max_code_q[4])
            cx_dc_width_r = 4'd4;
        else if ({10'b0, lookup_input_i[15:10]} < cx_dc_max_code_q[5])
            cx_dc_width_r = 4'd5;
        else if ({9'b0, lookup_input_i[15:9]} < cx_dc_max_code_q[6])
            cx_dc_width_r = 4'd6;
        else if ({8'b0, lookup_input_i[15:8]} < cx_dc_max_code_q[7])
            cx_dc_width_r = 4'd7;
        else if ({7'b0, lookup_input_i[15:7]} < cx_dc_max_code_q[8])
            cx_dc_width_r = 4'd8;
        else if ({6'b0, lookup_input_i[15:6]} < cx_dc_max_code_q[9])
            cx_dc_width_r = 4'd9;
        else if ({5'b0, lookup_input_i[15:5]} < cx_dc_max_code_q[10])
            cx_dc_width_r = 4'd10;
        else if ({4'b0, lookup_input_i[15:4]} < cx_dc_max_code_q[11])
            cx_dc_width_r = 4'd11;
        else if ({3'b0, lookup_input_i[15:3]} < cx_dc_max_code_q[12])
            cx_dc_width_r = 4'd12;
        else if ({2'b0, lookup_input_i[15:2]} < cx_dc_max_code_q[13])
            cx_dc_width_r = 4'd13;
        else if ({1'b0, lookup_input_i[15:1]} < cx_dc_max_code_q[14])
            cx_dc_width_r = 4'd14;
        else
            cx_dc_width_r = 4'd15;
    end

    reg [3:0] cx_ac_width_r;
    always @ *
    begin
        cx_ac_width_r = 4'b0;

        if ({15'b0, lookup_input_i[15]} < cx_ac_max_code_q[0])
            cx_ac_width_r = 4'd0;
        else if ({14'b0, lookup_input_i[15:14]} < cx_ac_max_code_q[1])
            cx_ac_width_r = 4'd1;
        else if ({13'b0, lookup_input_i[15:13]} < cx_ac_max_code_q[2])
            cx_ac_width_r = 4'd2;
        else if ({12'b0, lookup_input_i[15:12]} < cx_ac_max_code_q[3])
            cx_ac_width_r = 4'd3;
        else if ({11'b0, lookup_input_i[15:11]} < cx_ac_max_code_q[4])
            cx_ac_width_r = 4'd4;
        else if ({10'b0, lookup_input_i[15:10]} < cx_ac_max_code_q[5])
            cx_ac_width_r = 4'd5;
        else if ({9'b0, lookup_input_i[15:9]} < cx_ac_max_code_q[6])
            cx_ac_width_r = 4'd6;
        else if ({8'b0, lookup_input_i[15:8]} < cx_ac_max_code_q[7])
            cx_ac_width_r = 4'd7;
        else if ({7'b0, lookup_input_i[15:7]} < cx_ac_max_code_q[8])
            cx_ac_width_r = 4'd8;
        else if ({6'b0, lookup_input_i[15:6]} < cx_ac_max_code_q[9])
            cx_ac_width_r = 4'd9;
        else if ({5'b0, lookup_input_i[15:5]} < cx_ac_max_code_q[10])
            cx_ac_width_r = 4'd10;
        else if ({4'b0, lookup_input_i[15:4]} < cx_ac_max_code_q[11])
            cx_ac_width_r = 4'd11;
        else if ({3'b0, lookup_input_i[15:3]} < cx_ac_max_code_q[12])
            cx_ac_width_r = 4'd12;
        else if ({2'b0, lookup_input_i[15:2]} < cx_ac_max_code_q[13])
            cx_ac_width_r = 4'd13;
        else if ({1'b0, lookup_input_i[15:1]} < cx_ac_max_code_q[14])
            cx_ac_width_r = 4'd14;
        else
            cx_ac_width_r = 4'd15;
    end

    //-----------------------------------------------------------------
    // Lookup: Register lookup width
    //-----------------------------------------------------------------
    reg [3:0]  lookup_width_r;

    always @ *
    begin
        lookup_width_r = 4'b0;

        case (lookup_table_i)
        2'd0:    lookup_width_r = y_dc_width_r;
        2'd1:    lookup_width_r = y_ac_width_r;
        2'd2:    lookup_width_r = cx_dc_width_r;
        default: lookup_width_r = cx_ac_width_r;
        endcase
    end

    reg [3:0]  lookup_width_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_width_q <= 4'b0;
    else
        lookup_width_q <= lookup_width_r;

    reg [1:0]  lookup_table_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_table_q <= 2'b0;
    else
        lookup_table_q <= lookup_table_i;

    //-----------------------------------------------------------------
    // Lookup: Create RAM lookup address
    //-----------------------------------------------------------------
    reg [15:0] lookup_addr_r;
    reg [15:0] input_code_r;

    always @ *
    begin
        lookup_addr_r  = 16'b0;
        input_code_r   = 16'b0;

        case (lookup_table_q)
        2'd0:
        begin
            input_code_r   = lookup_input_i >> (15 - lookup_width_q);
            lookup_addr_r  = input_code_r - y_dc_min_code_q[lookup_width_q] + {6'b0, y_dc_ptr_q[lookup_width_q]};
        end
        2'd1:
        begin
            input_code_r   = lookup_input_i >> (15 - lookup_width_q);
            lookup_addr_r  = input_code_r - y_ac_min_code_q[lookup_width_q] + {6'b0, y_ac_ptr_q[lookup_width_q]};
        end
        2'd2:
        begin
            input_code_r   = lookup_input_i >> (15 - lookup_width_q);
            lookup_addr_r  = input_code_r - cx_dc_min_code_q[lookup_width_q] + {6'b0, cx_dc_ptr_q[lookup_width_q]};
        end
        default:
        begin
            input_code_r   = lookup_input_i >> (15 - lookup_width_q);
            lookup_addr_r  = input_code_r - cx_ac_min_code_q[lookup_width_q] + {6'b0, cx_ac_ptr_q[lookup_width_q]};
        end
        endcase
    end

    //-----------------------------------------------------------------
    // RAM for storing Huffman decode values
    //-----------------------------------------------------------------
    // LUT for decode values
    reg [7:0]  ram[0:1023];

    always @ (posedge clk_i)
    begin
        if (alloc_entry_w)
            ram[next_ptr_q] <= cfg_data_i;
    end

    reg [7:0] data_value_q;

    always @ (posedge clk_i)
    begin
        data_value_q <= ram[lookup_addr_r[9:0]];
    end

    reg lookup_valid_q;
    always @ (posedge clk_i )
    if (rst_i)
        lookup_valid_q <= 1'b0;
    else
        lookup_valid_q <= lookup_req_i;

    reg lookup_valid2_q;
    always @ (posedge clk_i )
    if (rst_i)
        lookup_valid2_q <= 1'b0;
    else
        lookup_valid2_q <= lookup_valid_q;

    reg [4:0]  lookup_width2_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_width2_q <= 5'b0;
    else
        lookup_width2_q <= {1'b0, lookup_width_q} + 5'd1;

    assign lookup_valid_o = lookup_valid2_q;
    assign lookup_value_o = data_value_q;
    assign lookup_width_o = lookup_width2_q;
end
//---------------------------------------------------------------------
// Support only standard huffman tables (from JPEG spec).
//---------------------------------------------------------------------
else
begin
    //-----------------------------------------------------------------
    // Y DC Table (standard)
    //-----------------------------------------------------------------
    wire [7:0] y_dc_value_w;
    wire [4:0] y_dc_width_w;

    jpeg_dht_std_y_dc
    u_fixed_y_dc
    (
         .lookup_input_i(lookup_input_i)
        ,.lookup_value_o(y_dc_value_w)
        ,.lookup_width_o(y_dc_width_w)
    );

    //-----------------------------------------------------------------
    // Y AC Table (standard)
    //-----------------------------------------------------------------
    wire [7:0] y_ac_value_w;
    wire [4:0] y_ac_width_w;

    jpeg_dht_std_y_ac
    u_fixed_y_ac
    (
         .lookup_input_i(lookup_input_i)
        ,.lookup_value_o(y_ac_value_w)
        ,.lookup_width_o(y_ac_width_w)
    );

    //-----------------------------------------------------------------
    // Cx DC Table (standard)
    //-----------------------------------------------------------------
    wire [7:0] cx_dc_value_w;
    wire [4:0] cx_dc_width_w;

    jpeg_dht_std_cx_dc
    u_fixed_cx_dc
    (
         .lookup_input_i(lookup_input_i)
        ,.lookup_value_o(cx_dc_value_w)
        ,.lookup_width_o(cx_dc_width_w)
    );

    //-----------------------------------------------------------------
    // Cx AC Table (standard)
    //-----------------------------------------------------------------
    wire [7:0] cx_ac_value_w;
    wire [4:0] cx_ac_width_w;

    jpeg_dht_std_cx_ac
    u_fixed_cx_ac
    (
         .lookup_input_i(lookup_input_i)
        ,.lookup_value_o(cx_ac_value_w)
        ,.lookup_width_o(cx_ac_width_w)
    );

    //-----------------------------------------------------------------
    // Lookup
    //-----------------------------------------------------------------
    reg lookup_valid_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_valid_q <= 1'b0;
    else
        lookup_valid_q <= lookup_req_i;

    assign lookup_valid_o = lookup_valid_q;

    reg [7:0] lookup_value_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_value_q <= 8'b0;
    else
    begin
        case (lookup_table_i)
        2'd0: lookup_value_q <= y_dc_value_w;
        2'd1: lookup_value_q <= y_ac_value_w;
        2'd2: lookup_value_q <= cx_dc_value_w;
        2'd3: lookup_value_q <= cx_ac_value_w;
        endcase
    end

    assign lookup_value_o = lookup_value_q;

    reg [4:0] lookup_width_q;

    always @ (posedge clk_i )
    if (rst_i)
        lookup_width_q <= 5'b0;
    else
    begin
        case (lookup_table_i)
        2'd0: lookup_width_q <= y_dc_width_w;
        2'd1: lookup_width_q <= y_ac_width_w;
        2'd2: lookup_width_q <= cx_dc_width_w;
        2'd3: lookup_width_q <= cx_ac_width_w;
        endcase
    end

    assign lookup_width_o = lookup_width_q;

    assign cfg_accept_o = 1'b1;
end
endgenerate


endmodule


================================================
FILE: src_v/jpeg_dht_std_cx_ac.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------
module jpeg_dht_std_cx_ac
(
     input  [ 15:0]  lookup_input_i
    ,output [  4:0]  lookup_width_o
    ,output [  7:0]  lookup_value_o
);

//-----------------------------------------------------------------
// Cx AC Table (standard)
//-----------------------------------------------------------------
reg [7:0] cx_ac_value_r;
reg [4:0] cx_ac_width_r;

always @ *
begin
    cx_ac_value_r = 8'b0;
    cx_ac_width_r = 5'b0;

    if (lookup_input_i[15:14] == 2'h0)
    begin
         cx_ac_value_r = 8'h00;
         cx_ac_width_r = 5'd2;
    end
    else if (lookup_input_i[15:14] == 2'h1)
    begin
         cx_ac_value_r = 8'h01;
         cx_ac_width_r = 5'd2;
    end
    else if (lookup_input_i[15:13] == 3'h4)
    begin
         cx_ac_value_r = 8'h02;
         cx_ac_width_r = 5'd3;
    end
    else if (lookup_input_i[15:12] == 4'ha)
    begin
         cx_ac_value_r = 8'h03;
         cx_ac_width_r = 5'd4;
    end
    else if (lookup_input_i[15:12] == 4'hb)
    begin
         cx_ac_value_r = 8'h11;
         cx_ac_width_r = 5'd4;
    end
    else if (lookup_input_i[15:11] == 5'h18)
    begin
         cx_ac_value_r = 8'h04;
         cx_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:11] == 5'h19)
    begin
         cx_ac_value_r = 8'h05;
         cx_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:11] == 5'h1a)
    begin
         cx_ac_value_r = 8'h21;
         cx_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:11] == 5'h1b)
    begin
         cx_ac_value_r = 8'h31;
         cx_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:10] == 6'h38)
    begin
         cx_ac_value_r = 8'h06;
         cx_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:10] == 6'h39)
    begin
         cx_ac_value_r = 8'h12;
         cx_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:10] == 6'h3a)
    begin
         cx_ac_value_r = 8'h41;
         cx_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:10] == 6'h3b)
    begin
         cx_ac_value_r = 8'h51;
         cx_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:9] == 7'h78)
    begin
         cx_ac_value_r = 8'h07;
         cx_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:9] == 7'h79)
    begin
         cx_ac_value_r = 8'h61;
         cx_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:9] == 7'h7a)
    begin
         cx_ac_value_r = 8'h71;
         cx_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:8] == 8'hf6)
    begin
         cx_ac_value_r = 8'h13;
         cx_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:8] == 8'hf7)
    begin
         cx_ac_value_r = 8'h22;
         cx_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:8] == 8'hf8)
    begin
         cx_ac_value_r = 8'h32;
         cx_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:8] == 8'hf9)
    begin
         cx_ac_value_r = 8'h81;
         cx_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:7] == 9'h1f4)
    begin
         cx_ac_value_r = 8'h08;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f5)
    begin
         cx_ac_value_r = 8'h14;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f6)
    begin
         cx_ac_value_r = 8'h42;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f7)
    begin
         cx_ac_value_r = 8'h91;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f8)
    begin
         cx_ac_value_r = 8'ha1;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f9)
    begin
         cx_ac_value_r = 8'hb1;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1fa)
    begin
         cx_ac_value_r = 8'hc1;
         cx_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:6] == 10'h3f6)
    begin
         cx_ac_value_r = 8'h09;
         cx_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f7)
    begin
         cx_ac_value_r = 8'h23;
         cx_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f8)
    begin
         cx_ac_value_r = 8'h33;
         cx_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f9)
    begin
         cx_ac_value_r = 8'h52;
         cx_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3fa)
    begin
         cx_ac_value_r = 8'hf0;
         cx_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:5] == 11'h7f6)
    begin
         cx_ac_value_r = 8'h15;
         cx_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f7)
    begin
         cx_ac_value_r = 8'h62;
         cx_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f8)
    begin
         cx_ac_value_r = 8'h72;
         cx_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f9)
    begin
         cx_ac_value_r = 8'hd1;
         cx_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:4] == 12'hff4)
    begin
         cx_ac_value_r = 8'h0a;
         cx_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff5)
    begin
         cx_ac_value_r = 8'h16;
         cx_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff6)
    begin
         cx_ac_value_r = 8'h24;
         cx_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff7)
    begin
         cx_ac_value_r = 8'h34;
         cx_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:2] == 14'h3fe0)
    begin
         cx_ac_value_r = 8'he1;
         cx_ac_width_r = 5'd14;
    end
    else if (lookup_input_i[15:1] == 15'h7fc2)
    begin
         cx_ac_value_r = 8'h25;
         cx_ac_width_r = 5'd15;
    end
    else if (lookup_input_i[15:1] == 15'h7fc3)
    begin
         cx_ac_value_r = 8'hf1;
         cx_ac_width_r = 5'd15;
    end
    else if (lookup_input_i[15:0] == 16'hff88)
    begin
         cx_ac_value_r = 8'h17;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff89)
    begin
         cx_ac_value_r = 8'h18;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8a)
    begin
         cx_ac_value_r = 8'h19;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8b)
    begin
         cx_ac_value_r = 8'h1a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8c)
    begin
         cx_ac_value_r = 8'h26;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8d)
    begin
         cx_ac_value_r = 8'h27;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8e)
    begin
         cx_ac_value_r = 8'h28;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8f)
    begin
         cx_ac_value_r = 8'h29;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff90)
    begin
         cx_ac_value_r = 8'h2a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff91)
    begin
         cx_ac_value_r = 8'h35;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff92)
    begin
         cx_ac_value_r = 8'h36;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff93)
    begin
         cx_ac_value_r = 8'h37;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff94)
    begin
         cx_ac_value_r = 8'h38;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff95)
    begin
         cx_ac_value_r = 8'h39;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff96)
    begin
         cx_ac_value_r = 8'h3a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff97)
    begin
         cx_ac_value_r = 8'h43;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff98)
    begin
         cx_ac_value_r = 8'h44;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff99)
    begin
         cx_ac_value_r = 8'h45;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9a)
    begin
         cx_ac_value_r = 8'h46;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9b)
    begin
         cx_ac_value_r = 8'h47;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9c)
    begin
         cx_ac_value_r = 8'h48;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9d)
    begin
         cx_ac_value_r = 8'h49;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9e)
    begin
         cx_ac_value_r = 8'h4a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9f)
    begin
         cx_ac_value_r = 8'h53;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa0)
    begin
         cx_ac_value_r = 8'h54;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa1)
    begin
         cx_ac_value_r = 8'h55;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa2)
    begin
         cx_ac_value_r = 8'h56;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa3)
    begin
         cx_ac_value_r = 8'h57;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa4)
    begin
         cx_ac_value_r = 8'h58;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa5)
    begin
         cx_ac_value_r = 8'h59;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa6)
    begin
         cx_ac_value_r = 8'h5a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa7)
    begin
         cx_ac_value_r = 8'h63;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa8)
    begin
         cx_ac_value_r = 8'h64;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa9)
    begin
         cx_ac_value_r = 8'h65;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffaa)
    begin
         cx_ac_value_r = 8'h66;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffab)
    begin
         cx_ac_value_r = 8'h67;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffac)
    begin
         cx_ac_value_r = 8'h68;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffad)
    begin
         cx_ac_value_r = 8'h69;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffae)
    begin
         cx_ac_value_r = 8'h6a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffaf)
    begin
         cx_ac_value_r = 8'h73;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb0)
    begin
         cx_ac_value_r = 8'h74;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb1)
    begin
         cx_ac_value_r = 8'h75;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb2)
    begin
         cx_ac_value_r = 8'h76;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb3)
    begin
         cx_ac_value_r = 8'h77;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb4)
    begin
         cx_ac_value_r = 8'h78;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb5)
    begin
         cx_ac_value_r = 8'h79;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb6)
    begin
         cx_ac_value_r = 8'h7a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb7)
    begin
         cx_ac_value_r = 8'h82;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb8)
    begin
         cx_ac_value_r = 8'h83;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb9)
    begin
         cx_ac_value_r = 8'h84;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffba)
    begin
         cx_ac_value_r = 8'h85;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbb)
    begin
         cx_ac_value_r = 8'h86;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbc)
    begin
         cx_ac_value_r = 8'h87;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbd)
    begin
         cx_ac_value_r = 8'h88;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbe)
    begin
         cx_ac_value_r = 8'h89;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbf)
    begin
         cx_ac_value_r = 8'h8a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc0)
    begin
         cx_ac_value_r = 8'h92;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc1)
    begin
         cx_ac_value_r = 8'h93;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc2)
    begin
         cx_ac_value_r = 8'h94;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc3)
    begin
         cx_ac_value_r = 8'h95;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc4)
    begin
         cx_ac_value_r = 8'h96;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc5)
    begin
         cx_ac_value_r = 8'h97;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc6)
    begin
         cx_ac_value_r = 8'h98;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc7)
    begin
         cx_ac_value_r = 8'h99;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc8)
    begin
         cx_ac_value_r = 8'h9a;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc9)
    begin
         cx_ac_value_r = 8'ha2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffca)
    begin
         cx_ac_value_r = 8'ha3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcb)
    begin
         cx_ac_value_r = 8'ha4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcc)
    begin
         cx_ac_value_r = 8'ha5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcd)
    begin
         cx_ac_value_r = 8'ha6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffce)
    begin
         cx_ac_value_r = 8'ha7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcf)
    begin
         cx_ac_value_r = 8'ha8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd0)
    begin
         cx_ac_value_r = 8'ha9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd1)
    begin
         cx_ac_value_r = 8'haa;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd2)
    begin
         cx_ac_value_r = 8'hb2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd3)
    begin
         cx_ac_value_r = 8'hb3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd4)
    begin
         cx_ac_value_r = 8'hb4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd5)
    begin
         cx_ac_value_r = 8'hb5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd6)
    begin
         cx_ac_value_r = 8'hb6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd7)
    begin
         cx_ac_value_r = 8'hb7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd8)
    begin
         cx_ac_value_r = 8'hb8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd9)
    begin
         cx_ac_value_r = 8'hb9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffda)
    begin
         cx_ac_value_r = 8'hba;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdb)
    begin
         cx_ac_value_r = 8'hc2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdc)
    begin
         cx_ac_value_r = 8'hc3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdd)
    begin
         cx_ac_value_r = 8'hc4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffde)
    begin
         cx_ac_value_r = 8'hc5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdf)
    begin
         cx_ac_value_r = 8'hc6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe0)
    begin
         cx_ac_value_r = 8'hc7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe1)
    begin
         cx_ac_value_r = 8'hc8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe2)
    begin
         cx_ac_value_r = 8'hc9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe3)
    begin
         cx_ac_value_r = 8'hca;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe4)
    begin
         cx_ac_value_r = 8'hd2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe5)
    begin
         cx_ac_value_r = 8'hd3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe6)
    begin
         cx_ac_value_r = 8'hd4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe7)
    begin
         cx_ac_value_r = 8'hd5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe8)
    begin
         cx_ac_value_r = 8'hd6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe9)
    begin
         cx_ac_value_r = 8'hd7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffea)
    begin
         cx_ac_value_r = 8'hd8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffeb)
    begin
         cx_ac_value_r = 8'hd9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffec)
    begin
         cx_ac_value_r = 8'hda;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffed)
    begin
         cx_ac_value_r = 8'he2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffee)
    begin
         cx_ac_value_r = 8'he3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffef)
    begin
         cx_ac_value_r = 8'he4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff0)
    begin
         cx_ac_value_r = 8'he5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff1)
    begin
         cx_ac_value_r = 8'he6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff2)
    begin
         cx_ac_value_r = 8'he7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff3)
    begin
         cx_ac_value_r = 8'he8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff4)
    begin
         cx_ac_value_r = 8'he9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff5)
    begin
         cx_ac_value_r = 8'hea;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff6)
    begin
         cx_ac_value_r = 8'hf2;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff7)
    begin
         cx_ac_value_r = 8'hf3;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff8)
    begin
         cx_ac_value_r = 8'hf4;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff9)
    begin
         cx_ac_value_r = 8'hf5;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffa)
    begin
         cx_ac_value_r = 8'hf6;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffb)
    begin
         cx_ac_value_r = 8'hf7;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffc)
    begin
         cx_ac_value_r = 8'hf8;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffd)
    begin
         cx_ac_value_r = 8'hf9;
         cx_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffe)
    begin
         cx_ac_value_r = 8'hfa;
         cx_ac_width_r = 5'd16;
    end
end

assign lookup_width_o = cx_ac_width_r;
assign lookup_value_o = cx_ac_value_r;

endmodule


================================================
FILE: src_v/jpeg_dht_std_cx_dc.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------
module jpeg_dht_std_cx_dc
(
     input  [ 15:0]  lookup_input_i
    ,output [  4:0]  lookup_width_o
    ,output [  7:0]  lookup_value_o
);

//-----------------------------------------------------------------
// Cx DC Table (standard)
//-----------------------------------------------------------------
reg [7:0] cx_dc_value_r;
reg [4:0] cx_dc_width_r;

always @ *
begin
    cx_dc_value_r = 8'b0;
    cx_dc_width_r = 5'b0;

    if (lookup_input_i[15:14] == 2'h0)
    begin
         cx_dc_value_r = 8'h00;
         cx_dc_width_r = 5'd2;
    end
    else if (lookup_input_i[15:14] == 2'h1)
    begin
         cx_dc_value_r = 8'h01;
         cx_dc_width_r = 5'd2;
    end
    else if (lookup_input_i[15:14] == 2'h2)
    begin
         cx_dc_value_r = 8'h02;
         cx_dc_width_r = 5'd2;
    end
    else if (lookup_input_i[15:13] == 3'h6)
    begin
         cx_dc_value_r = 8'h03;
         cx_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:12] == 4'he)
    begin
         cx_dc_value_r = 8'h04;
         cx_dc_width_r = 5'd4;
    end
    else if (lookup_input_i[15:11] == 5'h1e)
    begin
         cx_dc_value_r = 8'h05;
         cx_dc_width_r = 5'd5;
    end
    else if (lookup_input_i[15:10] == 6'h3e)
    begin
         cx_dc_value_r = 8'h06;
         cx_dc_width_r = 5'd6;
    end
    else if (lookup_input_i[15:9] == 7'h7e)
    begin
         cx_dc_value_r = 8'h07;
         cx_dc_width_r = 5'd7;
    end
    else if (lookup_input_i[15:8] == 8'hfe)
    begin
         cx_dc_value_r = 8'h08;
         cx_dc_width_r = 5'd8;
    end
    else if (lookup_input_i[15:7] == 9'h1fe)
    begin
         cx_dc_value_r = 8'h09;
         cx_dc_width_r = 5'd9;
    end
    else if (lookup_input_i[15:6] == 10'h3fe)
    begin
         cx_dc_value_r = 8'h0a;
         cx_dc_width_r = 5'd10;
    end
    else if (lookup_input_i[15:5] == 11'h7fe)
    begin
         cx_dc_value_r = 8'h0b;
         cx_dc_width_r = 5'd11;
    end
end

assign lookup_width_o = cx_dc_width_r;
assign lookup_value_o = cx_dc_value_r;

endmodule



================================================
FILE: src_v/jpeg_dht_std_y_ac.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------
module jpeg_dht_std_y_ac
(
     input  [ 15:0]  lookup_input_i
    ,output [  4:0]  lookup_width_o
    ,output [  7:0]  lookup_value_o
);

//-----------------------------------------------------------------
// Y AC Table (standard)
//-----------------------------------------------------------------
reg [7:0] y_ac_value_r;
reg [4:0] y_ac_width_r;

always @ *
begin
    y_ac_value_r = 8'b0;
    y_ac_width_r = 5'b0;

    if (lookup_input_i[15:14] == 2'h0)
    begin
         y_ac_value_r = 8'h01;
         y_ac_width_r = 5'd2;
    end
    else if (lookup_input_i[15:14] == 2'h1)
    begin
         y_ac_value_r = 8'h02;
         y_ac_width_r = 5'd2;
    end
    else if (lookup_input_i[15:13] == 3'h4)
    begin
         y_ac_value_r = 8'h03;
         y_ac_width_r = 5'd3;
    end
    else if (lookup_input_i[15:12] == 4'ha)
    begin
         y_ac_value_r = 8'h00;
         y_ac_width_r = 5'd4;
    end
    else if (lookup_input_i[15:12] == 4'hb)
    begin
         y_ac_value_r = 8'h04;
         y_ac_width_r = 5'd4;
    end
    else if (lookup_input_i[15:12] == 4'hc)
    begin
         y_ac_value_r = 8'h11;
         y_ac_width_r = 5'd4;
    end
    else if (lookup_input_i[15:11] == 5'h1a)
    begin
         y_ac_value_r = 8'h05;
         y_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:11] == 5'h1b)
    begin
         y_ac_value_r = 8'h12;
         y_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:11] == 5'h1c)
    begin
         y_ac_value_r = 8'h21;
         y_ac_width_r = 5'd5;
    end
    else if (lookup_input_i[15:10] == 6'h3a)
    begin
         y_ac_value_r = 8'h31;
         y_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:10] == 6'h3b)
    begin
         y_ac_value_r = 8'h41;
         y_ac_width_r = 5'd6;
    end
    else if (lookup_input_i[15:9] == 7'h78)
    begin
         y_ac_value_r = 8'h06;
         y_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:9] == 7'h79)
    begin
         y_ac_value_r = 8'h13;
         y_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:9] == 7'h7a)
    begin
         y_ac_value_r = 8'h51;
         y_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:9] == 7'h7b)
    begin
         y_ac_value_r = 8'h61;
         y_ac_width_r = 5'd7;
    end
    else if (lookup_input_i[15:8] == 8'hf8)
    begin
         y_ac_value_r = 8'h07;
         y_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:8] == 8'hf9)
    begin
         y_ac_value_r = 8'h22;
         y_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:8] == 8'hfa)
    begin
         y_ac_value_r = 8'h71;
         y_ac_width_r = 5'd8;
    end
    else if (lookup_input_i[15:7] == 9'h1f6)
    begin
         y_ac_value_r = 8'h14;
         y_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f7)
    begin
         y_ac_value_r = 8'h32;
         y_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f8)
    begin
         y_ac_value_r = 8'h81;
         y_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1f9)
    begin
         y_ac_value_r = 8'h91;
         y_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:7] == 9'h1fa)
    begin
         y_ac_value_r = 8'ha1;
         y_ac_width_r = 5'd9;
    end
    else if (lookup_input_i[15:6] == 10'h3f6)
    begin
         y_ac_value_r = 8'h08;
         y_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f7)
    begin
         y_ac_value_r = 8'h23;
         y_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f8)
    begin
         y_ac_value_r = 8'h42;
         y_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3f9)
    begin
         y_ac_value_r = 8'hb1;
         y_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:6] == 10'h3fa)
    begin
         y_ac_value_r = 8'hc1;
         y_ac_width_r = 5'd10;
    end
    else if (lookup_input_i[15:5] == 11'h7f6)
    begin
         y_ac_value_r = 8'h15;
         y_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f7)
    begin
         y_ac_value_r = 8'h52;
         y_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f8)
    begin
         y_ac_value_r = 8'hd1;
         y_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:5] == 11'h7f9)
    begin
         y_ac_value_r = 8'hf0;
         y_ac_width_r = 5'd11;
    end
    else if (lookup_input_i[15:4] == 12'hff4)
    begin
         y_ac_value_r = 8'h24;
         y_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff5)
    begin
         y_ac_value_r = 8'h33;
         y_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff6)
    begin
         y_ac_value_r = 8'h62;
         y_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:4] == 12'hff7)
    begin
         y_ac_value_r = 8'h72;
         y_ac_width_r = 5'd12;
    end
    else if (lookup_input_i[15:1] == 15'h7fc0)
    begin
         y_ac_value_r = 8'h82;
         y_ac_width_r = 5'd15;
    end
    else if (lookup_input_i[15:0] == 16'hff82)
    begin
         y_ac_value_r = 8'h09;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff83)
    begin
         y_ac_value_r = 8'h0a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff84)
    begin
         y_ac_value_r = 8'h16;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff85)
    begin
         y_ac_value_r = 8'h17;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff86)
    begin
         y_ac_value_r = 8'h18;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff87)
    begin
         y_ac_value_r = 8'h19;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff88)
    begin
         y_ac_value_r = 8'h1a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff89)
    begin
         y_ac_value_r = 8'h25;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8a)
    begin
         y_ac_value_r = 8'h26;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8b)
    begin
         y_ac_value_r = 8'h27;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8c)
    begin
         y_ac_value_r = 8'h28;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8d)
    begin
         y_ac_value_r = 8'h29;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8e)
    begin
         y_ac_value_r = 8'h2a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff8f)
    begin
         y_ac_value_r = 8'h34;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff90)
    begin
         y_ac_value_r = 8'h35;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff91)
    begin
         y_ac_value_r = 8'h36;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff92)
    begin
         y_ac_value_r = 8'h37;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff93)
    begin
         y_ac_value_r = 8'h38;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff94)
    begin
         y_ac_value_r = 8'h39;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff95)
    begin
         y_ac_value_r = 8'h3a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff96)
    begin
         y_ac_value_r = 8'h43;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff97)
    begin
         y_ac_value_r = 8'h44;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff98)
    begin
         y_ac_value_r = 8'h45;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff99)
    begin
         y_ac_value_r = 8'h46;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9a)
    begin
         y_ac_value_r = 8'h47;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9b)
    begin
         y_ac_value_r = 8'h48;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9c)
    begin
         y_ac_value_r = 8'h49;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9d)
    begin
         y_ac_value_r = 8'h4a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9e)
    begin
         y_ac_value_r = 8'h53;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hff9f)
    begin
         y_ac_value_r = 8'h54;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa0)
    begin
         y_ac_value_r = 8'h55;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa1)
    begin
         y_ac_value_r = 8'h56;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa2)
    begin
         y_ac_value_r = 8'h57;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa3)
    begin
         y_ac_value_r = 8'h58;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa4)
    begin
         y_ac_value_r = 8'h59;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa5)
    begin
         y_ac_value_r = 8'h5a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa6)
    begin
         y_ac_value_r = 8'h63;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa7)
    begin
         y_ac_value_r = 8'h64;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa8)
    begin
         y_ac_value_r = 8'h65;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffa9)
    begin
         y_ac_value_r = 8'h66;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffaa)
    begin
         y_ac_value_r = 8'h67;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffab)
    begin
         y_ac_value_r = 8'h68;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffac)
    begin
         y_ac_value_r = 8'h69;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffad)
    begin
         y_ac_value_r = 8'h6a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffae)
    begin
         y_ac_value_r = 8'h73;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffaf)
    begin
         y_ac_value_r = 8'h74;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb0)
    begin
         y_ac_value_r = 8'h75;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb1)
    begin
         y_ac_value_r = 8'h76;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb2)
    begin
         y_ac_value_r = 8'h77;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb3)
    begin
         y_ac_value_r = 8'h78;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb4)
    begin
         y_ac_value_r = 8'h79;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb5)
    begin
         y_ac_value_r = 8'h7a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb6)
    begin
         y_ac_value_r = 8'h83;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb7)
    begin
         y_ac_value_r = 8'h84;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb8)
    begin
         y_ac_value_r = 8'h85;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffb9)
    begin
         y_ac_value_r = 8'h86;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffba)
    begin
         y_ac_value_r = 8'h87;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbb)
    begin
         y_ac_value_r = 8'h88;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbc)
    begin
         y_ac_value_r = 8'h89;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbd)
    begin
         y_ac_value_r = 8'h8a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbe)
    begin
         y_ac_value_r = 8'h92;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffbf)
    begin
         y_ac_value_r = 8'h93;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc0)
    begin
         y_ac_value_r = 8'h94;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc1)
    begin
         y_ac_value_r = 8'h95;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc2)
    begin
         y_ac_value_r = 8'h96;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc3)
    begin
         y_ac_value_r = 8'h97;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc4)
    begin
         y_ac_value_r = 8'h98;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc5)
    begin
         y_ac_value_r = 8'h99;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc6)
    begin
         y_ac_value_r = 8'h9a;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc7)
    begin
         y_ac_value_r = 8'ha2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc8)
    begin
         y_ac_value_r = 8'ha3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffc9)
    begin
         y_ac_value_r = 8'ha4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffca)
    begin
         y_ac_value_r = 8'ha5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcb)
    begin
         y_ac_value_r = 8'ha6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcc)
    begin
         y_ac_value_r = 8'ha7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcd)
    begin
         y_ac_value_r = 8'ha8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffce)
    begin
         y_ac_value_r = 8'ha9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffcf)
    begin
         y_ac_value_r = 8'haa;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd0)
    begin
         y_ac_value_r = 8'hb2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd1)
    begin
         y_ac_value_r = 8'hb3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd2)
    begin
         y_ac_value_r = 8'hb4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd3)
    begin
         y_ac_value_r = 8'hb5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd4)
    begin
         y_ac_value_r = 8'hb6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd5)
    begin
         y_ac_value_r = 8'hb7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd6)
    begin
         y_ac_value_r = 8'hb8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd7)
    begin
         y_ac_value_r = 8'hb9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd8)
    begin
         y_ac_value_r = 8'hba;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffd9)
    begin
         y_ac_value_r = 8'hc2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffda)
    begin
         y_ac_value_r = 8'hc3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdb)
    begin
         y_ac_value_r = 8'hc4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdc)
    begin
         y_ac_value_r = 8'hc5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdd)
    begin
         y_ac_value_r = 8'hc6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffde)
    begin
         y_ac_value_r = 8'hc7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffdf)
    begin
         y_ac_value_r = 8'hc8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe0)
    begin
         y_ac_value_r = 8'hc9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe1)
    begin
         y_ac_value_r = 8'hca;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe2)
    begin
         y_ac_value_r = 8'hd2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe3)
    begin
         y_ac_value_r = 8'hd3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe4)
    begin
         y_ac_value_r = 8'hd4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe5)
    begin
         y_ac_value_r = 8'hd5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe6)
    begin
         y_ac_value_r = 8'hd6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe7)
    begin
         y_ac_value_r = 8'hd7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe8)
    begin
         y_ac_value_r = 8'hd8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffe9)
    begin
         y_ac_value_r = 8'hd9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffea)
    begin
         y_ac_value_r = 8'hda;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffeb)
    begin
         y_ac_value_r = 8'he1;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffec)
    begin
         y_ac_value_r = 8'he2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffed)
    begin
         y_ac_value_r = 8'he3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffee)
    begin
         y_ac_value_r = 8'he4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hffef)
    begin
         y_ac_value_r = 8'he5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff0)
    begin
         y_ac_value_r = 8'he6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff1)
    begin
         y_ac_value_r = 8'he7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff2)
    begin
         y_ac_value_r = 8'he8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff3)
    begin
         y_ac_value_r = 8'he9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff4)
    begin
         y_ac_value_r = 8'hea;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff5)
    begin
         y_ac_value_r = 8'hf1;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff6)
    begin
         y_ac_value_r = 8'hf2;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff7)
    begin
         y_ac_value_r = 8'hf3;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff8)
    begin
         y_ac_value_r = 8'hf4;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfff9)
    begin
         y_ac_value_r = 8'hf5;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffa)
    begin
         y_ac_value_r = 8'hf6;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffb)
    begin
         y_ac_value_r = 8'hf7;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffc)
    begin
         y_ac_value_r = 8'hf8;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffd)
    begin
         y_ac_value_r = 8'hf9;
         y_ac_width_r = 5'd16;
    end
    else if (lookup_input_i[15:0] == 16'hfffe)
    begin
         y_ac_value_r = 8'hfa;
         y_ac_width_r = 5'd16;
    end
end

assign lookup_width_o = y_ac_width_r;
assign lookup_value_o = y_ac_value_r;

endmodule


================================================
FILE: src_v/jpeg_dht_std_y_dc.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------
module jpeg_dht_std_y_dc
(
     input  [ 15:0]  lookup_input_i
    ,output [  4:0]  lookup_width_o
    ,output [  7:0]  lookup_value_o
);

//-----------------------------------------------------------------
// Y DC Table (standard)
//-----------------------------------------------------------------
reg [7:0] y_dc_value_r;
reg [4:0] y_dc_width_r;

always @ *
begin
    y_dc_value_r = 8'b0;
    y_dc_width_r = 5'b0;

    if (lookup_input_i[15:14] == 2'h0)
    begin
         y_dc_value_r = 8'h00;
         y_dc_width_r = 5'd2;
    end
    else if (lookup_input_i[15:13] == 3'h2)
    begin
         y_dc_value_r = 8'h01;
         y_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:13] == 3'h3)
    begin
         y_dc_value_r = 8'h02;
         y_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:13] == 3'h4)
    begin
         y_dc_value_r = 8'h03;
         y_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:13] == 3'h5)
    begin
         y_dc_value_r = 8'h04;
         y_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:13] == 3'h6)
    begin
         y_dc_value_r = 8'h05;
         y_dc_width_r = 5'd3;
    end
    else if (lookup_input_i[15:12] == 4'he)
    begin
         y_dc_value_r = 8'h06;
         y_dc_width_r = 5'd4;
    end
    else if (lookup_input_i[15:11] == 5'h1e)
    begin
         y_dc_value_r = 8'h07;
         y_dc_width_r = 5'd5;
    end
    else if (lookup_input_i[15:10] == 6'h3e)
    begin
         y_dc_value_r = 8'h08;
         y_dc_width_r = 5'd6;
    end
    else if (lookup_input_i[15:9] == 7'h7e)
    begin
         y_dc_value_r = 8'h09;
         y_dc_width_r = 5'd7;
    end
    else if (lookup_input_i[15:8] == 8'hfe)
    begin
         y_dc_value_r = 8'h0a;
         y_dc_width_r = 5'd8;
    end
    else if (lookup_input_i[15:7] == 9'h1fe)
    begin
         y_dc_value_r = 8'h0b;
         y_dc_width_r = 5'd9;
    end
end

assign lookup_width_o = y_dc_width_r;
assign lookup_value_o = y_dc_value_r;

endmodule

================================================
FILE: src_v/jpeg_dqt.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_dqt
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input  [  1:0]  img_dqt_table_y_i
    ,input  [  1:0]  img_dqt_table_cb_i
    ,input  [  1:0]  img_dqt_table_cr_i
    ,input           cfg_valid_i
    ,input  [  7:0]  cfg_data_i
    ,input           cfg_last_i
    ,input           inport_valid_i
    ,input  [ 15:0]  inport_data_i
    ,input  [  5:0]  inport_idx_i
    ,input  [ 31:0]  inport_id_i
    ,input           inport_eob_i
    ,input           outport_accept_i

    // Outputs
    ,output          cfg_accept_o
    ,output          inport_blk_space_o
    ,output          outport_valid_o
    ,output [ 15:0]  outport_data_o
    ,output [  5:0]  outport_idx_o
    ,output [ 31:0]  outport_id_o
    ,output          outport_eob_o
);



//-----------------------------------------------------------------
// DQT tables
//-----------------------------------------------------------------
// 4 * 256
reg [7:0] table_dqt_q[0:255];

//-----------------------------------------------------------------
// Capture Index
//-----------------------------------------------------------------
reg [7:0] idx_q;

always @ (posedge clk_i )
if (rst_i)
    idx_q <= 8'hFF;
else if (cfg_valid_i && cfg_last_i && cfg_accept_o)
    idx_q <= 8'hFF;
else if (cfg_valid_i && cfg_accept_o)
    idx_q <= idx_q + 8'd1;

assign cfg_accept_o = 1'b1;

//-----------------------------------------------------------------
// Write DQT table
//-----------------------------------------------------------------
reg [1:0] cfg_table_q;

always @ (posedge clk_i )
if (rst_i)
    cfg_table_q <= 2'b0;
else if (cfg_valid_i && cfg_accept_o && idx_q == 8'hFF)
    cfg_table_q <= cfg_data_i[1:0];

wire [7:0] cfg_table_addr_w = {cfg_table_q, idx_q[5:0]};

wire [1:0] table_src_w[3:0];

assign table_src_w[0] = img_dqt_table_y_i;
assign table_src_w[1] = img_dqt_table_cb_i;
assign table_src_w[2] = img_dqt_table_cr_i;
assign table_src_w[3] = 2'b0;

wire [7:0] table_rd_idx_w   = {table_src_w[inport_id_i[31:30]], inport_idx_i};

wire       dqt_write_w      = cfg_valid_i && cfg_accept_o && idx_q != 8'hFF;
wire [7:0] dqt_table_addr_w = dqt_write_w ? cfg_table_addr_w : table_rd_idx_w;

reg [7:0] dqt_entry_q;

always @ (posedge clk_i )
begin
    if (dqt_write_w)
        table_dqt_q[dqt_table_addr_w] <= cfg_data_i;

    dqt_entry_q <= table_dqt_q[dqt_table_addr_w];
end

//-----------------------------------------------------------------
// dezigzag: Reverse zigzag process
//-----------------------------------------------------------------
function [5:0] dezigzag;
    input [5:0] idx;
    reg [5:0] out_idx;
begin
    case (idx)
    6'd0: out_idx = 6'd0;
    6'd1: out_idx = 6'd1;
    6'd2: out_idx = 6'd8;
    6'd3: out_idx = 6'd16;
    6'd4: out_idx = 6'd9;
    6'd5: out_idx = 6'd2;
    6'd6: out_idx = 6'd3;
    6'd7: out_idx = 6'd10;
    6'd8: out_idx = 6'd17;
    6'd9: out_idx = 6'd24;
    6'd10: out_idx = 6'd32;
    6'd11: out_idx = 6'd25;
    6'd12: out_idx = 6'd18;
    6'd13: out_idx = 6'd11;
    6'd14: out_idx = 6'd4;
    6'd15: out_idx = 6'd5;
    6'd16: out_idx = 6'd12;
    6'd17: out_idx = 6'd19;
    6'd18: out_idx = 6'd26;
    6'd19: out_idx = 6'd33;
    6'd20: out_idx = 6'd40;
    6'd21: out_idx = 6'd48;
    6'd22: out_idx = 6'd41;
    6'd23: out_idx = 6'd34;
    6'd24: out_idx = 6'd27;
    6'd25: out_idx = 6'd20;
    6'd26: out_idx = 6'd13;
    6'd27: out_idx = 6'd6;
    6'd28: out_idx = 6'd7;
    6'd29: out_idx = 6'd14;
    6'd30: out_idx = 6'd21;
    6'd31: out_idx = 6'd28;
    6'd32: out_idx = 6'd35;
    6'd33: out_idx = 6'd42;
    6'd34: out_idx = 6'd49;
    6'd35: out_idx = 6'd56;
    6'd36: out_idx = 6'd57;
    6'd37: out_idx = 6'd50;
    6'd38: out_idx = 6'd43;
    6'd39: out_idx = 6'd36;
    6'd40: out_idx = 6'd29;
    6'd41: out_idx = 6'd22;
    6'd42: out_idx = 6'd15;
    6'd43: out_idx = 6'd23;
    6'd44: out_idx = 6'd30;
    6'd45: out_idx = 6'd37;
    6'd46: out_idx = 6'd44;
    6'd47: out_idx = 6'd51;
    6'd48: out_idx = 6'd58;
    6'd49: out_idx = 6'd59;
    6'd50: out_idx = 6'd52;
    6'd51: out_idx = 6'd45;
    6'd52: out_idx = 6'd38;
    6'd53: out_idx = 6'd31;
    6'd54: out_idx = 6'd39;
    6'd55: out_idx = 6'd46;
    6'd56: out_idx = 6'd53;
    6'd57: out_idx = 6'd60;
    6'd58: out_idx = 6'd61;
    6'd59: out_idx = 6'd54;
    6'd60: out_idx = 6'd47;
    6'd61: out_idx = 6'd55;
    6'd62: out_idx = 6'd62;
    default: out_idx = 6'd63; 
    endcase

    dezigzag = out_idx;
end
endfunction

//-----------------------------------------------------------------
// Process dequantisation and dezigzag
//-----------------------------------------------------------------
reg        inport_valid_q;
reg [15:0] inport_data_q;
reg [5:0]  inport_idx_q;
reg [31:0] inport_id_q;
reg        inport_eob_q;

always @ (posedge clk_i )
if (rst_i)
    inport_valid_q <= 1'b0;
else
    inport_valid_q <= inport_valid_i && ~img_start_i;

always @ (posedge clk_i )
if (rst_i)
    inport_idx_q <= 6'b0;
else
    inport_idx_q <= inport_idx_i;

always @ (posedge clk_i )
if (rst_i)
    inport_data_q <= 16'b0;
else
    inport_data_q <= inport_data_i;

always @ (posedge clk_i )
if (rst_i)
    inport_id_q <= 32'b0;
else if (inport_valid_i)
    inport_id_q <= inport_id_i;

always @ (posedge clk_i )
if (rst_i)
    inport_eob_q <= 1'b0;
else
    inport_eob_q <= inport_eob_i;

//-----------------------------------------------------------------
// Output
//-----------------------------------------------------------------
reg               outport_valid_q;
reg signed [15:0] outport_data_q;
reg [5:0]         outport_idx_q;
reg [31:0]        outport_id_q;
reg               outport_eob_q;

always @ (posedge clk_i )
if (rst_i)
    outport_valid_q <= 1'b0;
else
    outport_valid_q <= inport_valid_q && ~img_start_i;

always @ (posedge clk_i )
if (rst_i)
    outport_data_q <= 16'b0;
else
    outport_data_q <= inport_data_q * dqt_entry_q;

always @ (posedge clk_i )
if (rst_i)
    outport_idx_q <= 6'b0;
else
    outport_idx_q <= dezigzag(inport_idx_q);

always @ (posedge clk_i )
if (rst_i)
    outport_id_q <= 32'b0;
else
    outport_id_q <= inport_id_q;

always @ (posedge clk_i )
if (rst_i)
    outport_eob_q <= 1'b0;
else
    outport_eob_q <= inport_eob_q;

assign outport_valid_o = outport_valid_q;
assign outport_data_o  = outport_data_q;
assign outport_idx_o   = outport_idx_q;
assign outport_id_o    = outport_id_q;    
assign outport_eob_o   = outport_eob_q;

// TODO: Perf
assign inport_blk_space_o = outport_accept_i && !(outport_eob_q || inport_eob_q);

`ifdef verilator
function get_valid; /*verilator public*/
begin
    get_valid = outport_valid_o;
end
endfunction
function [15:0] get_sample; /*verilator public*/
begin
    get_sample = outport_data_o;
end
endfunction
function [5:0] get_sample_idx; /*verilator public*/
begin
    get_sample_idx = outport_idx_o;
end
endfunction
`endif

endmodule


================================================
FILE: src_v/jpeg_idct.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input           inport_valid_i
    ,input  [ 15:0]  inport_data_i
    ,input  [  5:0]  inport_idx_i
    ,input           inport_eob_i
    ,input  [ 31:0]  inport_id_i
    ,input           outport_accept_i

    // Outputs
    ,output          inport_accept_o
    ,output          outport_valid_o
    ,output [ 31:0]  outport_data_o
    ,output [  5:0]  outport_idx_o
    ,output [ 31:0]  outport_id_o
);




wire          input_valid_w;
wire [ 15:0]  input_data0_w;
wire [ 15:0]  input_data1_w;
wire [ 15:0]  input_data2_w;
wire [ 15:0]  input_data3_w;
wire [  2:0]  input_idx_w;
wire          input_ready_w;


jpeg_idct_ram
u_input
(
     .clk_i(clk_i)
    ,.rst_i(rst_i)

    ,.img_start_i(img_start_i)
    ,.img_end_i(img_end_i)

    ,.inport_valid_i(inport_valid_i)
    ,.inport_data_i(inport_data_i)
    ,.inport_idx_i(inport_idx_i)
    ,.inport_eob_i(inport_eob_i)
    ,.inport_accept_o(inport_accept_o)

    ,.outport_valid_o(input_valid_w)
    ,.outport_data0_o(input_data0_w)
    ,.outport_data1_o(input_data1_w)
    ,.outport_data2_o(input_data2_w)
    ,.outport_data3_o(input_data3_w)
    ,.outport_idx_o(input_idx_w)
    ,.outport_ready_i(outport_accept_i)
);

wire          idct_x_valid_w;
wire [ 31:0]  idct_x_data_w;
wire [  5:0]  idct_x_idx_w;
wire          idct_x_accept_w;

jpeg_idct_x
u_idct_x
(
     .clk_i(clk_i)
    ,.rst_i(rst_i)

    ,.img_start_i(img_start_i)
    ,.img_end_i(img_end_i)

    ,.inport_valid_i(input_valid_w)
    ,.inport_data0_i(input_data0_w)
    ,.inport_data1_i(input_data1_w)
    ,.inport_data2_i(input_data2_w)
    ,.inport_data3_i(input_data3_w)
    ,.inport_idx_i(input_idx_w)

    ,.outport_valid_o(idct_x_valid_w)
    ,.outport_data_o(idct_x_data_w)
    ,.outport_idx_o(idct_x_idx_w)
);

wire          transpose_valid_w;
wire [ 31:0]  transpose_data0_w;
wire [ 31:0]  transpose_data1_w;
wire [ 31:0]  transpose_data2_w;
wire [ 31:0]  transpose_data3_w;
wire [  2:0]  transpose_idx_w;
wire          transpose_ready_w = 1'b1;

jpeg_idct_transpose
u_transpose
(
     .clk_i(clk_i)
    ,.rst_i(rst_i)

    ,.img_start_i(img_start_i)
    ,.img_end_i(img_end_i)

    ,.inport_valid_i(idct_x_valid_w)
    ,.inport_data_i(idct_x_data_w)
    ,.inport_idx_i(idct_x_idx_w)
    ,.inport_accept_o(idct_x_accept_w)

    ,.outport_valid_o(transpose_valid_w)
    ,.outport_data0_o(transpose_data0_w)
    ,.outport_data1_o(transpose_data1_w)
    ,.outport_data2_o(transpose_data2_w)
    ,.outport_data3_o(transpose_data3_w)
    ,.outport_idx_o(transpose_idx_w)
    ,.outport_ready_i(transpose_ready_w)
);

jpeg_idct_y
u_idct_y
(
     .clk_i(clk_i)
    ,.rst_i(rst_i)

    ,.img_start_i(img_start_i)
    ,.img_end_i(img_end_i)

    ,.inport_valid_i(transpose_valid_w)
    ,.inport_data0_i(transpose_data0_w)
    ,.inport_data1_i(transpose_data1_w)
    ,.inport_data2_i(transpose_data2_w)
    ,.inport_data3_i(transpose_data3_w)
    ,.inport_idx_i(transpose_idx_w)

    ,.outport_valid_o(outport_valid_o)
    ,.outport_data_o(outport_data_o)
    ,.outport_idx_o(outport_idx_o)
);


jpeg_idct_fifo
#(
     .WIDTH(32)
    ,.DEPTH(8)
    ,.ADDR_W(3)
)
u_id_fifo
(
     .clk_i(clk_i)
    ,.rst_i(rst_i)

    ,.flush_i(img_start_i)

    ,.push_i(inport_eob_i)
    ,.data_in_i(inport_id_i)
    ,.accept_o()

    ,.valid_o()
    ,.data_out_o(outport_id_o)
    ,.pop_i(outport_valid_o && outport_idx_o == 6'd63)
);

`ifdef verilator
function get_valid; /*verilator public*/
begin
    get_valid = outport_valid_o;
end
endfunction
function [5:0] get_sample_idx; /*verilator public*/
begin
    get_sample_idx = outport_idx_o;
end
endfunction
function [31:0] get_sample; /*verilator public*/
begin
    get_sample = outport_data_o;
end
endfunction
`endif


endmodule


================================================
FILE: src_v/jpeg_idct_fifo.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_fifo
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
     parameter WIDTH            = 8
    ,parameter DEPTH            = 4
    ,parameter ADDR_W           = 2
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input  [WIDTH-1:0]  data_in_i
    ,input           push_i
    ,input           pop_i
    ,input           flush_i

    // Outputs
    ,output [WIDTH-1:0]  data_out_o
    ,output          accept_o
    ,output          valid_o
);



//-----------------------------------------------------------------
// Local Params
//-----------------------------------------------------------------
localparam COUNT_W = ADDR_W + 1;

//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [WIDTH-1:0]   ram_q[DEPTH-1:0];
reg [ADDR_W-1:0]  rd_ptr_q;
reg [ADDR_W-1:0]  wr_ptr_q;
reg [COUNT_W-1:0] count_q;

//-----------------------------------------------------------------
// Sequential
//-----------------------------------------------------------------
always @ (posedge clk_i or posedge rst_i)
if (rst_i)
begin
    count_q   <= {(COUNT_W) {1'b0}};
    rd_ptr_q  <= {(ADDR_W) {1'b0}};
    wr_ptr_q  <= {(ADDR_W) {1'b0}};
end
else if (flush_i)
begin
    count_q   <= {(COUNT_W) {1'b0}};
    rd_ptr_q  <= {(ADDR_W) {1'b0}};
    wr_ptr_q  <= {(ADDR_W) {1'b0}};
end
else
begin
    // Push
    if (push_i & accept_o)
    begin
        ram_q[wr_ptr_q] <= data_in_i;
        wr_ptr_q        <= wr_ptr_q + 1;
    end

    // Pop
    if (pop_i & valid_o)
        rd_ptr_q      <= rd_ptr_q + 1;

    // Count up
    if ((push_i & accept_o) & ~(pop_i & valid_o))
        count_q <= count_q + 1;
    // Count down
    else if (~(push_i & accept_o) & (pop_i & valid_o))
        count_q <= count_q - 1;
end

//-------------------------------------------------------------------
// Combinatorial
//-------------------------------------------------------------------
/* verilator lint_off WIDTH */
assign valid_o       = (count_q != 0);
assign accept_o      = (count_q != DEPTH);
/* verilator lint_on WIDTH */

assign data_out_o    = ram_q[rd_ptr_q];



endmodule


================================================
FILE: src_v/jpeg_idct_ram.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_ram
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input           inport_valid_i
    ,input  [ 15:0]  inport_data_i
    ,input  [  5:0]  inport_idx_i
    ,input           inport_eob_i
    ,input           outport_ready_i

    // Outputs
    ,output          inport_accept_o
    ,output          outport_valid_o
    ,output [ 15:0]  outport_data0_o
    ,output [ 15:0]  outport_data1_o
    ,output [ 15:0]  outport_data2_o
    ,output [ 15:0]  outport_data3_o
    ,output [  2:0]  outport_idx_o
);



reg [1:0]   block_wr_q;
reg [1:0]   block_rd_q;
reg [5:0]   rd_idx_q;
reg [3:0]   rd_addr_q;

wire [5:0]  wr_ptr_w = {block_wr_q, inport_idx_i[5:3], inport_idx_i[0]};

wire [15:0] outport_data0_w;
wire [15:0] outport_data1_w;
wire [15:0] outport_data2_w;
wire [15:0] outport_data3_w;

wire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd0 || inport_idx_i[2:0] == 3'd1);
wire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd2 || inport_idx_i[2:0] == 3'd3);
wire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd4 || inport_idx_i[2:0] == 3'd5);
wire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd6 || inport_idx_i[2:0] == 3'd7);

jpeg_idct_ram_dp
u_ram0
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr0_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(16'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data0_w)
);

jpeg_idct_ram_dp
u_ram1
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr1_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(16'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data1_w)
);

jpeg_idct_ram_dp
u_ram2
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr2_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(16'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data2_w)
);

jpeg_idct_ram_dp
u_ram3
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr3_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(16'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data3_w)
);

//-----------------------------------------------------------------
// Data Qualifiers
//-----------------------------------------------------------------
reg [63:0]        data_valid0_r;
reg [63:0]        data_valid0_q;

always @ *
begin
    data_valid0_r = data_valid0_q;

    // End of block read out - reset data valid state
    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        case (block_rd_q)
        2'd0:    data_valid0_r[15:0]  = 16'b0;
        2'd1:    data_valid0_r[31:16] = 16'b0;
        2'd2:    data_valid0_r[47:32] = 16'b0;
        default: data_valid0_r[63:48] = 16'b0;
        endcase
    end

    if (wr0_w)
        data_valid0_r[wr_ptr_w] = 1'b1;
end

always @ (posedge clk_i )
if (rst_i)
    data_valid0_q <= 64'b0;
else if (img_start_i)
    data_valid0_q <= 64'b0;
else
    data_valid0_q <= data_valid0_r;

reg [63:0]        data_valid1_r;
reg [63:0]        data_valid1_q;

always @ *
begin
    data_valid1_r = data_valid1_q;

    // End of block read out - reset data valid state
    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        case (block_rd_q)
        2'd0:    data_valid1_r[15:0]  = 16'b0;
        2'd1:    data_valid1_r[31:16] = 16'b0;
        2'd2:    data_valid1_r[47:32] = 16'b0;
        default: data_valid1_r[63:48] = 16'b0;
        endcase
    end

    if (wr1_w)
        data_valid1_r[wr_ptr_w] = 1'b1;
end

always @ (posedge clk_i )
if (rst_i)
    data_valid1_q <= 64'b0;
else if (img_start_i)
    data_valid1_q <= 64'b0;
else
    data_valid1_q <= data_valid1_r;

reg [63:0]        data_valid2_r;
reg [63:0]        data_valid2_q;

always @ *
begin
    data_valid2_r = data_valid2_q;

    // End of block read out - reset data valid state
    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        case (block_rd_q)
        2'd0:    data_valid2_r[15:0]  = 16'b0;
        2'd1:    data_valid2_r[31:16] = 16'b0;
        2'd2:    data_valid2_r[47:32] = 16'b0;
        default: data_valid2_r[63:48] = 16'b0;
        endcase
    end

    if (wr2_w)
        data_valid2_r[wr_ptr_w] = 1'b1;
end

always @ (posedge clk_i )
if (rst_i)
    data_valid2_q <= 64'b0;
else if (img_start_i)
    data_valid2_q <= 64'b0;
else
    data_valid2_q <= data_valid2_r;

reg [63:0]        data_valid3_r;
reg [63:0]        data_valid3_q;

always @ *
begin
    data_valid3_r = data_valid3_q;

    // End of block read out - reset data valid state
    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        case (block_rd_q)
        2'd0:    data_valid3_r[15:0]  = 16'b0;
        2'd1:    data_valid3_r[31:16] = 16'b0;
        2'd2:    data_valid3_r[47:32] = 16'b0;
        default: data_valid3_r[63:48] = 16'b0;
        endcase
    end

    if (wr3_w)
        data_valid3_r[wr_ptr_w] = 1'b1;
end

always @ (posedge clk_i )
if (rst_i)
    data_valid3_q <= 64'b0;
else if (img_start_i)
    data_valid3_q <= 64'b0;
else
    data_valid3_q <= data_valid3_r;


//-----------------------------------------------------------------
// Input Buffer
//-----------------------------------------------------------------
reg [3:0] block_ready_q;

always @ (posedge clk_i )
if (rst_i)
begin
    block_ready_q     <= 4'b0;
    block_wr_q        <= 2'b0;
    block_rd_q        <= 2'b0;
end
else if (img_start_i)
begin
    block_ready_q     <= 4'b0;
    block_wr_q        <= 2'b0;
    block_rd_q        <= 2'b0;
end
else
begin
    if (inport_eob_i && inport_accept_o)
    begin
        block_ready_q[block_wr_q] <= 1'b1;
        block_wr_q                <= block_wr_q + 2'd1;
    end

    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        block_ready_q[block_rd_q] <= 1'b0;
        block_rd_q                <= block_rd_q + 2'd1;
    end
end

assign inport_accept_o = ~block_ready_q[block_wr_q];

//-----------------------------------------------------------------
// FSM
//-----------------------------------------------------------------
localparam STATE_W           = 2;
localparam STATE_IDLE        = 2'd0;
localparam STATE_SETUP       = 2'd1;
localparam STATE_ACTIVE      = 2'd2;

reg [STATE_W-1:0] state_q;
reg [STATE_W-1:0] next_state_r;

always @ *
begin
    next_state_r = state_q;

    case (state_q)
    STATE_IDLE:
    begin
        if (block_ready_q[block_rd_q] && outport_ready_i)
            next_state_r = STATE_SETUP;
    end
    STATE_SETUP:
    begin
        next_state_r = STATE_ACTIVE;
    end
    STATE_ACTIVE:
    begin
        if (outport_valid_o && rd_idx_q == 6'd63)
            next_state_r = STATE_IDLE;
    end
    default: ;
    endcase

    if (img_start_i)
        next_state_r = STATE_IDLE;
end

always @ (posedge clk_i )
if (rst_i)
    state_q <= STATE_IDLE;
else
    state_q <= next_state_r;

always @ (posedge clk_i )
if (rst_i)
    rd_idx_q <= 6'b0;
else if (img_start_i)
    rd_idx_q <= 6'b0;
else if (state_q == STATE_ACTIVE)
    rd_idx_q <= rd_idx_q + 6'd1;

always @ (posedge clk_i )
if (rst_i)
    rd_addr_q <= 4'b0;
else if (state_q == STATE_IDLE)
    rd_addr_q <= 4'b0;
else if (state_q == STATE_SETUP)
    rd_addr_q <= 4'd1;
else if (state_q == STATE_ACTIVE)
begin
    case (rd_idx_q[2:0])
    3'd0: rd_addr_q <= rd_addr_q - 1;
    3'd1: rd_addr_q <= rd_addr_q + 1;
    3'd2: ;
    3'd3: rd_addr_q <= rd_addr_q - 1;
    3'd4: rd_addr_q <= rd_addr_q + 1;
    3'd5: rd_addr_q <= rd_addr_q - 1;
    3'd6: rd_addr_q <= rd_addr_q + 2;
    3'd7: rd_addr_q <= rd_addr_q + 1;
    endcase
end

reg data_val0_q;
reg data_val1_q;
reg data_val2_q;
reg data_val3_q;

always @ (posedge clk_i )
if (rst_i)
begin
    data_val0_q <= 1'b0;
    data_val1_q <= 1'b0;
    data_val2_q <= 1'b0;
    data_val3_q <= 1'b0;
end
else
begin
    data_val0_q <= data_valid0_q[{block_rd_q, rd_addr_q}];
    data_val1_q <= data_valid1_q[{block_rd_q, rd_addr_q}];
    data_val2_q <= data_valid2_q[{block_rd_q, rd_addr_q}];
    data_val3_q <= data_valid3_q[{block_rd_q, rd_addr_q}];
end

assign outport_valid_o = (state_q == STATE_ACTIVE);
assign outport_idx_o   = rd_idx_q[2:0];
assign outport_data0_o = {16{data_val0_q}} & outport_data0_w;
assign outport_data1_o = {16{data_val1_q}} & outport_data1_w;
assign outport_data2_o = {16{data_val2_q}} & outport_data2_w;
assign outport_data3_o = {16{data_val3_q}} & outport_data3_w;


endmodule


================================================
FILE: src_v/jpeg_idct_ram_dp.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_ram_dp
(
    // Inputs
     input           clk0_i
    ,input           rst0_i
    ,input  [  5:0]  addr0_i
    ,input  [ 15:0]  data0_i
    ,input           wr0_i
    ,input           clk1_i
    ,input           rst1_i
    ,input  [  5:0]  addr1_i
    ,input  [ 15:0]  data1_i
    ,input           wr1_i

    // Outputs
    ,output [ 15:0]  data0_o
    ,output [ 15:0]  data1_o
);



//-----------------------------------------------------------------
// Dual Port RAM
// Mode: Read First
//-----------------------------------------------------------------
/* verilator lint_off MULTIDRIVEN */
reg [15:0]   ram [63:0] /*verilator public*/;
/* verilator lint_on MULTIDRIVEN */

reg [15:0] ram_read0_q;
reg [15:0] ram_read1_q;


// Synchronous write
always @ (posedge clk0_i)
begin
    if (wr0_i)
        ram[addr0_i][15:0] <= data0_i[15:0];

    ram_read0_q <= ram[addr0_i];
end

always @ (posedge clk1_i)
begin
    if (wr1_i)
        ram[addr1_i][15:0] <= data1_i[15:0];

    ram_read1_q <= ram[addr1_i];
end


assign data0_o = ram_read0_q;
assign data1_o = ram_read1_q;



endmodule


================================================
FILE: src_v/jpeg_idct_transpose.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_transpose
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input           inport_valid_i
    ,input  [ 31:0]  inport_data_i
    ,input  [  5:0]  inport_idx_i
    ,input           outport_ready_i

    // Outputs
    ,output          inport_accept_o
    ,output          outport_valid_o
    ,output [ 31:0]  outport_data0_o
    ,output [ 31:0]  outport_data1_o
    ,output [ 31:0]  outport_data2_o
    ,output [ 31:0]  outport_data3_o
    ,output [  2:0]  outport_idx_o
);



reg         block_wr_q;
reg         block_rd_q;
reg [5:0]   rd_idx_q;
reg [3:0]   rd_addr_q;

wire [4:0]  wr_ptr_w = {block_wr_q, inport_idx_i[3:0]};

wire [31:0] outport_data0_w;
wire [31:0] outport_data1_w;
wire [31:0] outport_data2_w;
wire [31:0] outport_data3_w;

wire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd0);
wire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd1);
wire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd2);
wire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd3);

jpeg_idct_transpose_ram
u_ram0
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr0_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(32'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data0_w)
);

jpeg_idct_transpose_ram
u_ram1
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr1_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(32'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data1_w)
);

jpeg_idct_transpose_ram
u_ram2
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr2_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(32'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data2_w)
);

jpeg_idct_transpose_ram
u_ram3
(
     .clk0_i(clk_i)
    ,.rst0_i(rst_i)
    ,.clk1_i(clk_i)
    ,.rst1_i(rst_i)

    ,.addr0_i(wr_ptr_w)
    ,.data0_i(inport_data_i)
    ,.wr0_i(wr3_w)
    ,.data0_o()

    ,.addr1_i({block_rd_q, rd_addr_q})
    ,.data1_i(32'b0)
    ,.wr1_i(1'b0)
    ,.data1_o(outport_data3_w)
);

//-----------------------------------------------------------------
// Input Buffer
//-----------------------------------------------------------------
reg [1:0] block_ready_q;

always @ (posedge clk_i )
if (rst_i)
begin
    block_ready_q     <= 2'b0;
    block_wr_q        <= 1'b0;
    block_rd_q        <= 1'b0;
end
else if (img_start_i)
begin
    block_ready_q     <= 2'b0;
    block_wr_q        <= 1'b0;
    block_rd_q        <= 1'b0;
end
else
begin
    if (inport_valid_i && inport_idx_i == 6'd63 && inport_accept_o)
    begin
        block_ready_q[block_wr_q] <= 1'b1;
        block_wr_q                <= ~block_wr_q;
    end

    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)
    begin
        block_ready_q[block_rd_q] <= 1'b0;
        block_rd_q <= ~block_rd_q;
    end
end

assign inport_accept_o = ~block_ready_q[block_wr_q];

//-----------------------------------------------------------------
// FSM
//-----------------------------------------------------------------
localparam STATE_W           = 2;
localparam STATE_IDLE        = 2'd0;
localparam STATE_SETUP       = 2'd1;
localparam STATE_ACTIVE      = 2'd2;

reg [STATE_W-1:0] state_q;
reg [STATE_W-1:0] next_state_r;

always @ *
begin
    next_state_r = state_q;

    case (state_q)
    STATE_IDLE:
    begin
        if (block_ready_q[block_rd_q] && outport_ready_i)
            next_state_r = STATE_SETUP;
    end
    STATE_SETUP:
    begin
        next_state_r = STATE_ACTIVE;
    end
    STATE_ACTIVE:
    begin
        if (outport_valid_o && rd_idx_q == 6'd63)
            next_state_r = STATE_IDLE;
    end
    default: ;
    endcase

    if (img_start_i)
        next_state_r = STATE_IDLE;
end

always @ (posedge clk_i )
if (rst_i)
    state_q <= STATE_IDLE;
else
    state_q <= next_state_r;

always @ (posedge clk_i )
if (rst_i)
    rd_idx_q <= 6'b0;
else if (img_start_i)
    rd_idx_q <= 6'b0;
else if (state_q == STATE_ACTIVE)
    rd_idx_q <= rd_idx_q + 6'd1;

always @ (posedge clk_i )
if (rst_i)
    rd_addr_q <= 4'b0;
else if (state_q == STATE_IDLE)
    rd_addr_q <= 4'b0;
else if (state_q == STATE_SETUP)
    rd_addr_q <= 4'd8;
else if (state_q == STATE_ACTIVE)
begin
    case (rd_idx_q[2:0])
    3'd0: rd_addr_q <= rd_addr_q - 4'd8;
    3'd1: rd_addr_q <= rd_addr_q + 4'd8;
    3'd2: ;
    3'd3: rd_addr_q <= rd_addr_q - 4'd8;
    3'd4: rd_addr_q <= rd_addr_q + 4'd8;
    3'd5: rd_addr_q <= rd_addr_q - 4'd8;
    3'd6: rd_addr_q <= rd_addr_q + 4'd1;
    3'd7: rd_addr_q <= rd_addr_q + 4'd8;
    endcase
end

assign outport_valid_o = (state_q == STATE_ACTIVE);
assign outport_idx_o   = rd_idx_q[2:0];
assign outport_data0_o = outport_data0_w;
assign outport_data1_o = outport_data1_w;
assign outport_data2_o = outport_data2_w;
assign outport_data3_o = outport_data3_w;


endmodule


================================================
FILE: src_v/jpeg_idct_transpose_ram.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_transpose_ram
(
    // Inputs
     input           clk0_i
    ,input           rst0_i
    ,input  [  4:0]  addr0_i
    ,input  [ 31:0]  data0_i
    ,input           wr0_i
    ,input           clk1_i
    ,input           rst1_i
    ,input  [  4:0]  addr1_i
    ,input  [ 31:0]  data1_i
    ,input           wr1_i

    // Outputs
    ,output [ 31:0]  data0_o
    ,output [ 31:0]  data1_o
);



//-----------------------------------------------------------------
// Dual Port RAM
// Mode: Read First
//-----------------------------------------------------------------
/* verilator lint_off MULTIDRIVEN */
reg [31:0]   ram [31:0] /*verilator public*/;
/* verilator lint_on MULTIDRIVEN */

reg [31:0] ram_read0_q;
reg [31:0] ram_read1_q;


// Synchronous write
always @ (posedge clk0_i)
begin
    if (wr0_i)
        ram[addr0_i][31:0] <= data0_i[31:0];

    ram_read0_q <= ram[addr0_i];
end

always @ (posedge clk1_i)
begin
    if (wr1_i)
        ram[addr1_i][31:0] <= data1_i[31:0];

    ram_read1_q <= ram[addr1_i];
end


assign data0_o = ram_read0_q;
assign data1_o = ram_read1_q;



endmodule


================================================
FILE: src_v/jpeg_idct_x.v
================================================
//-----------------------------------------------------------------
//                      Baseline JPEG Decoder
//                             V0.1
//                       Ultra-Embedded.com
//                        Copyright 2020
//
//                   admin@ultra-embedded.com
//-----------------------------------------------------------------
//                      License: Apache 2.0
// This IP can be freely used in commercial projects, however you may
// want access to unreleased materials such as verification environments,
// or test vectors, as well as changes to the IP for integration purposes.
// If this is the case, contact the above address.
// I am interested to hear how and where this IP is used, so please get
// in touch!
//-----------------------------------------------------------------
// Copyright 2020 Ultra-Embedded.com
// 
// 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
// 
//     http://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.
//-----------------------------------------------------------------

module jpeg_idct_x
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
     parameter OUT_SHIFT        = 11
    ,parameter INPUT_WIDTH      = 16
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
    // Inputs
     input           clk_i
    ,input           rst_i
    ,input           img_start_i
    ,input           img_end_i
    ,input           inport_valid_i
    ,input  [ 15:0]  inport_data0_i
    ,input  [ 15:0]  inport_data1_i
    ,input  [ 15:0]  inport_data2_i
    ,input  [ 15:0]  inport_data3_i
    ,input  [  2:0]  inport_idx_i

    // Outputs
    ,output          outport_valid_o
    ,output [ 31:0]  outport_data_o
    ,output [  5:0]  outport_idx_o
);




localparam [15:0] C1_16 = 4017; // cos( pi/16) x4096
localparam [15:0] C2_16 = 3784; // cos(2pi/16) x4096
localparam [15:0] C3_16 = 3406; // cos(3pi/16) x4096
localparam [15:0] C4_16 = 2896; // cos(4pi/16) x4096
localparam [15:0] C5_16 = 2276; // cos(5pi/16) x4096
localparam [15:0] C6_16 = 1567; // cos(6pi/16) x4096
localparam [15:0] C7_16 = 799;  // cos(7pi/16) x4096

wire signed [31:0] block_in_0_1 = {{16{inport_data0_i[15]}}, inport_data0_i};
wire signed [31:0] block_in_2_3 = {{16{inport_data1_i[15]}}, inport_data1_i};
wire signed [31:0] block_in_4_5 = {{16{inport_data2_i[15]}}, inport_data2_i};
wire signed [31:0] block_in_6_7 = {{16{inport_data3_i[15]}}, inport_data3_i};

//-----------------------------------------------------------------
// IDCT
//-----------------------------------------------------------------
reg signed [31:0] i0;
reg signed [31:0] mul0_a;
reg signed [31:0] mul0_b;
reg signed [31:0] mul1_a;
reg signed [31:0] mul1_b;
reg signed [31:0] mul2_a;
reg signed [31:0] mul2_b;
reg signed [31:0] mul3_a;
reg signed [31:0] mul3_b;
reg signed [31:0] mul4_a;
reg signed [31:0] mul4_b;

always @ (posedge clk_i )
if (rst_i)
begin
    i0     <= 32'b0;
    mul0_a <= 32'b0;
    mul0_b <= 32'b0;
    mul1_a <= 32'b0;
    mul1_b <= 32'b0;
    mul2_a <= 32'b0;
    mul2_b <= 32'b0;
    mul3_a <= 32'b0;
    mul3_b <= 32'b0;
    mul4_a <= 32'b0;
    mul4_b <= 32'b0;
end
else
begin
    /* verilator lint_off WIDTH */
    case (inport_idx_i)
    3'd0:
    begin
        i0     <= block_in_0_1 + block_in_4_5;
        mul0_a <= block_in_2_3;
        mul0_b <= C2_16;
        mul1_a <= block_in_6_7;
        mul1_b <= C6_16;
    end
    3'd1:
    begin
        mul0_a <= block_in_0_1;
        mul0_b <= C1_16;
        mul1_a <= block_in_6_7;
        mul1_b <= C7_16;
        mul2_a <= block_in_4_5;
        mul2_b <= C5_16;
        mul3_a <= block_in_2_3;
        mul3_b <= C3_16;
        mul4_a <= i0;
        mul4_b <= C4_16;
    end
    3'd2:
    begin
        i0     <= block_in_0_1 - block_in_4_5;
    end
    3'd3:
    begin
        mul0_a <= block_in_0_1;
        mul0_b <= C7_16;
        mul1_a <= block_in_6_7;
        mul1_b <= C1_16;
        mul2_a <= block_in_4_5;
        mul2_b <= C3_16;
        mul3_a <= block_in_2_3;
        mul3_b <= C5_16;
    end
    3'd4:
    begin
        mul0_a <= block_in_0_1;
        mul0_b <= C7_16;
        mul1_a <= block_in_6_7;
        mul1_b <= C1_16;
        mul2_a <= block_in_4_5;
        mul2_b <= C3_16;
        mul3_a <= block_in_2_3;
        mul3_b <= C5_16;
    end
    3'd5:
    begin
        mul0_a <= block_in_2_3;
        mul0_b <= C6_16;
        mul1_a <= block_in_6_7;
        mul1_b <= C2_16;
        mul4_a <= i0;
        mul4_b <= C4_16;
    end
    default:
        ;
    endcase
    /* verilator lint_on WIDTH */
end

reg signed [31:0] mul0_q;
reg signed [31:0] mul1_q;
reg signed [31:0] mul2_q;
reg signed [31:0] mul3_q;
reg signed [31:0] mul4_q;

always @ (posedge clk_i )
if (rst_i)
begin
    mul0_q <= 32'b0;
    mul1_q <= 32'b0;
    mul2_q <= 32'b0;
    mul3_q <= 32'b0;
    mul4_q <= 32'b0;
end
else
begin
    mul0_q <= mul0_a * mul0_b;
    mul1_q <= mul1_a * mul1_b;
    mul2_q <= mul2_a * mul2_b;
    mul3_q <= mul3_a * mul3_b;
    mul4_q <= mul4_a * mul4_b;
end

reg signed [31:0] mul0;
reg signed [31:0] mul1;
reg signed [31:0] mul2;
reg signed [31:0] mul3;
reg signed [31:0] mul4;

always @ (posedge clk_i )
if (rst_i)
begin
    mul0 <= 32'b0;
    mul1 <= 32'b0;
    mul2 <= 32'b0;
    mul3 <= 32'b0;
    mul4 <= 32'b0;
end
else
begin
    mul0 <= mul0_q;
    mul1 <= mul1_q;
    mul2 <= mul2_q;
    mul3 <= mul3_q;
    mul4 <= mul4_q;
end

reg        out_stg0_valid_q;
reg [2:0]  out_stg0_idx_q;

always @ (posedge clk_i )
if (rst_i)
begin
    out_stg0_valid_q <= 1'b0;
    out_stg0_idx_q   <= 3'b0;
end
else
begin
    out_stg0_valid_q <= inport_valid_i;
    out_stg0_idx_q   <= inport_idx_i;
end

reg        out_stg1_valid_q;
reg [2:0]  out_stg1_idx_q;

always @ (posedge clk_i )
if (rst_i)
begin
    out_stg1_valid_q <= 1'b0;
    out_stg1_idx_q   <= 3'b0;
end
else
begin
    out_stg1_valid_q <= out_stg0_valid_q;
    out_stg1_idx_q   <= out_stg0_idx_q;
end

reg        out_stg2_valid_q;
reg [2:0]  out_stg2_idx_q;

always @ (posedge clk_i )
if (rst_i)
begin
    out_stg2_valid_q <= 1'b0;
    out_stg2_idx_q   <= 3'b0;
end
else
begin
    out_stg2_valid_q <= out_stg1_valid_q;
    out_stg2_idx_q   <= out_stg1_idx_q;
end

reg signed [31:0] o_s5;
reg signed [31:0] o_s6;
reg signed [31:0] o_s7;
reg signed [31:0] o_t0;
reg signed [31:0] o_t1;
reg signed [31:0] o_t2;
reg signed [31:0] o_t3;
reg signed [31:0] o_t4;
reg signed [31:0] o_t5;
reg signed [31:0] o_t6;
reg signed [31:0] o_t7;
reg signed [31:0] o_t6_5;
reg signed [31:0] o_t5_6;

always @ (posedge clk_i )
if (rst_i)
begin
    o_s5   <= 32'b0;
    o_s6   <= 32'b0;
    o_s7   <= 32'b0;
    o_t0   <= 32'b0;
    o_t1   <= 32'b0;
    o_t2   <= 32'b0;
    o_t3   <= 32'b0;
    o_t4   <= 32'b0;
    o_t5   <= 32'b0;
    o_t6   <= 32'b0;
    o_t7   <= 32'b0;
    o_t6_5 <= 32'b0;
    o_t5_6 <= 32'b0;
end
else
begin
    case (out_stg2_idx_q)
    3'd0:
    begin
        o_t3 <= mul0 + mul1; // s3
    end
    3'd1:
    begin
        o_s7 <= mul0 + mul1;
        o_s6 <= mul2 + mul3;
        o_t0 <= mul4;        // s0
    end
    3'd2:
    begin
        o_t0 <= o_t0 + o_t3; // t0
        o_t3 <= o_t0 - o_t3; // t3
        o_t7 <= o_s6 + o_s7;
    end
    3'd3:
    begin
        o_t4 <= (mul0 - mul1) + (mul2 - mul3);
    end
    3'd4:
    begin
        o_t0 <= mul0 - mul1; // s4
        o_s5 <= mul2 - mul3;    
    end
    3'd5:
    begin
        o_t3 <= mul0 - mul1; // s2
        o_t4 <= mul4; // s1
        o_t5 <= o_t0 - o_s5;
        o_t6 <= o_s7 - 
Download .txt
gitextract_xejh9o8w/

├── LICENSE
├── README.md
├── c_model/
│   ├── README.md
│   ├── jpeg_bit_buffer.h
│   ├── jpeg_dht.h
│   ├── jpeg_dqt.h
│   ├── jpeg_idct.h
│   ├── jpeg_mcu_block.h
│   ├── main.cpp
│   └── makefile
└── src_v/
    ├── jpeg_bitbuffer.v
    ├── jpeg_core.v
    ├── jpeg_dht.v
    ├── jpeg_dht_std_cx_ac.v
    ├── jpeg_dht_std_cx_dc.v
    ├── jpeg_dht_std_y_ac.v
    ├── jpeg_dht_std_y_dc.v
    ├── jpeg_dqt.v
    ├── jpeg_idct.v
    ├── jpeg_idct_fifo.v
    ├── jpeg_idct_ram.v
    ├── jpeg_idct_ram_dp.v
    ├── jpeg_idct_transpose.v
    ├── jpeg_idct_transpose_ram.v
    ├── jpeg_idct_x.v
    ├── jpeg_idct_y.v
    ├── jpeg_input.v
    ├── jpeg_mcu_id.v
    ├── jpeg_mcu_proc.v
    ├── jpeg_output.v
    ├── jpeg_output_cx_ram.v
    ├── jpeg_output_fifo.v
    └── jpeg_output_y_ram.v
Download .txt
SYMBOL INDEX (13 symbols across 6 files)

FILE: c_model/jpeg_bit_buffer.h
  function class (line 23) | class jpeg_bit_buffer
  function push (line 53) | bool push(uint8_t b)
  function read_word (line 79) | uint32_t read_word(void)
  function advance (line 96) | void advance(int bits)
  function eof (line 102) | bool eof(void)

FILE: c_model/jpeg_dht.h
  function class (line 24) | class jpeg_dht

FILE: c_model/jpeg_dqt.h
  function class (line 29) | class jpeg_dqt

FILE: c_model/jpeg_idct.h
  function class (line 13) | class jpeg_idct

FILE: c_model/jpeg_mcu_block.h
  function class (line 18) | class jpeg_mcu_block

FILE: c_model/main.cpp
  type eJpgMode (line 23) | enum eJpgMode
  function ConvertYUV2RGB (line 48) | static void ConvertYUV2RGB(int block_num, int *y, int *cb, int *cr)
  function DecodeImage (line 112) | static bool DecodeImage(void)
  function main (line 265) | int main(int argc, char* argv[])
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (294K chars).
[
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 3306,
    "preview": "# High throughput JPEG decoder\n\nGithub: [https://github.com/ultraembedded/core_jpeg](https://github.com/ultraembedded/co"
  },
  {
    "path": "c_model/README.md",
    "chars": 580,
    "preview": "## JPEG Decoder C Model\n\nThis a simple C model of a JPEG decoder that can decode baseline JPEG images.\nThe purpose of th"
  },
  {
    "path": "c_model/jpeg_bit_buffer.h",
    "chars": 2331,
    "preview": "#ifndef JPEG_BIT_BUFFER_H\n#define JPEG_BIT_BUFFER_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include"
  },
  {
    "path": "c_model/jpeg_dht.h",
    "chars": 4106,
    "preview": "#ifndef JPEG_DHT_H\n#define JPEG_DHT_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#i"
  },
  {
    "path": "c_model/jpeg_dqt.h",
    "chars": 2824,
    "preview": "#ifndef JPEG_DQT_H\n#define JPEG_DQT_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#i"
  },
  {
    "path": "c_model/jpeg_idct.h",
    "chars": 3828,
    "preview": "#ifndef JPEG_IDCT_H\n#define JPEG_IDCT_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n"
  },
  {
    "path": "c_model/jpeg_mcu_block.h",
    "chars": 3801,
    "preview": "#ifndef JPEG_MCU_BLOCK_H\n#define JPEG_MCU_BLOCK_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <"
  },
  {
    "path": "c_model/main.cpp",
    "chars": 19685,
    "preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <unistd.h>\n#include <assert.h>\n\n"
  },
  {
    "path": "c_model/makefile",
    "chars": 1742,
    "preview": "###############################################################################\n# Makefile\n#############################"
  },
  {
    "path": "src_v/jpeg_bitbuffer.v",
    "chars": 4661,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_core.v",
    "chars": 9309,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dht.v",
    "chars": 29210,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dht_std_cx_ac.v",
    "chars": 22789,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dht_std_cx_dc.v",
    "chars": 3507,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dht_std_y_ac.v",
    "chars": 22468,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dht_std_y_dc.v",
    "chars": 3467,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_dqt.v",
    "chars": 8418,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct.v",
    "chars": 5326,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_fifo.v",
    "chars": 3918,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_ram.v",
    "chars": 10263,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_ram_dp.v",
    "chars": 2588,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_transpose.v",
    "chars": 6683,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_transpose_ram.v",
    "chars": 2595,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_x.v",
    "chars": 10141,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_idct_y.v",
    "chars": 12024,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_input.v",
    "chars": 17968,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_mcu_id.v",
    "chars": 5638,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_mcu_proc.v",
    "chars": 12600,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_output.v",
    "chars": 9914,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_output_cx_ram.v",
    "chars": 15242,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_output_fifo.v",
    "chars": 3920,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  },
  {
    "path": "src_v/jpeg_output_y_ram.v",
    "chars": 5943,
    "preview": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//    "
  }
]

About this extraction

This page contains the full source code of the ultraembedded/core_jpeg GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (275.5 KB), approximately 85.9k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!