[
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# High throughput JPEG decoder\n\nGithub: [https://github.com/ultraembedded/core_jpeg](https://github.com/ultraembedded/core_jpeg)\n\nThis project is a JPEG decoder core for FPGA written in Verilog.\n\n![JPEG Core](docs/block_diagram.png)\n\n## Features\n* Baseline JPEG Decoder IP (sequential encoded images).\n* 32-bit AXI Stream input.\n* Input format: JPEG (JPEG File Interchange Format)\n* Output format: 24-bit RGB output in 8x8 blocks (row-major ordering).\n* Support for Monochrome, 4:4:4, 4:2:0 chroma subsampling support.\n* Support for fixed standard Huffman tables (reduced logic usage, fast).\n* Support for dynamic Huffman tables (from JPEG input stream -> slower decode, more logic).\n* Dynamic DQT tables from JPEG input stream.\n* Synthesizable Verilog 2001, Verilator and FPGA friendly.\n* Multipliers and tables / FIFO's map efficiently to FPGA resources (DSP48, blockRAM, etc).\n* Verified using co-simulation against a C-model and tested on FPGA with thousands of images.\n\n## Design Aims\n1. Fast decode performance suitable for video playback\n2. Support a minimal JPEG baseline feature set.\n3. Be well tested (with verification against a reference C-model).\n4. Map to FPGA resources such as BlockRAM, DSP macros wherever possible.\n\n## FPGA Mapping\nThe current version of the JPEG decoder uses the following resources on a Xilinx 7 series FPGA (post-implementation);  \n![Resource Usage](docs/resources.png)\n\nThe design is also able to meet timing >= 75MHz.\n\n## Performance\nPeak JPEG decode performance is as follows;\n* Monochrome  = 66 cycles per 8x8 pixels  (1.0 cycles per pixel)\n* YCbCr 4:2:0 = 137 cycles per 8x8 pixels (2.1 cycles per pixel)\n* YCbCr 4:4:4 = 198 cycles per 8x8 pixels (3.1 cycles per pixel)\n\n## Use Case\nThe 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).  \nMotion 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.\n\nVideo playback usually requires at least 25 frames per second, hence there is a budget of less than 40ms per JPEG frame.  \nThis fact drives the design choices taken for this implementation.\n\nClearly, 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.\n\n## Limitations\nThe current release does not support;\n* Restart markers\n* 4:2:2 H/V chroma subsampling (only 4:4:4 and 4:2:0 are supported).\n\nUnder the GNU Image Manipulation Program, the following 'X' options are **not** supported currently;\n![Unsupported Opts](docs/supported_opts.png)\n\nNote: Support for 'optimised' Huffman tables is possible when design parameter SUPPORT_WRITABLE_DHT=1.  \nThis functionality increases the core size substantially and reduces performance.\n\n## Future Work / TODO\n* Add support for the first layer of progressive JPEG images.\n* Add option to reduce arithmetic precision to reduce design size.\n* Add lightweight variant of the core with reduced performance (for smaller FPGAs)."
  },
  {
    "path": "c_model/README.md",
    "content": "## JPEG Decoder C Model\n\nThis a simple C model of a JPEG decoder that can decode baseline JPEG images.\nThe purpose of this is to provide a reference to test the digital HW design against.\n\nIt supports;\n* YCbCr 4:4:4 (no chroma subsampling), 4:2:0 and monochrome images.\n* Conversion to a bitmap file (PPM / P6 format).\n* Optimised (Huffman tables) images.\n\nIt does not support (currently);\n* Progressive\n* YCbCr 4:2:2 chroma subsampling\n* Restart markers\n* App data, COM sections, will be ignored.\n\n\n### Building / Usage\n```\n# Build\nmake\n\n# Run\n./jpeg my_image.jpg bitmap.ppm\n```\n"
  },
  {
    "path": "c_model/jpeg_bit_buffer.h",
    "content": "#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 <string.h>\n#include <assert.h>\n\n#define dprintf\n\n#ifndef TEST_HOOKS_BITBUFFER\n#define TEST_HOOKS_BITBUFFER(x)\n#endif\n\n#ifndef TEST_HOOKS_BITBUFFER_DECL\n#define TEST_HOOKS_BITBUFFER_DECL\n#endif\n\n//-----------------------------------------------------------------------------\n// jpeg_bit_buffer:\n//-----------------------------------------------------------------------------\nclass jpeg_bit_buffer\n{\npublic:\n    jpeg_bit_buffer() \n    {\n        m_buffer = NULL;\n        reset(-1);\n    }\n\n    void reset(int max_size = -1)\n    {\n        if (m_buffer)\n        {\n            delete [] m_buffer;\n            m_buffer = NULL;\n        }\n\n        if (max_size <= 0)\n            m_max_size = 1 << 20;\n        else\n            m_max_size = max_size;\n\n        m_buffer = new uint8_t[m_max_size];\n        memset(m_buffer, 0, m_max_size);\n        m_wr_offset = 0;\n        m_last      = 0;\n        m_rd_offset = 0;\n    }\n\n    // Push byte into stream (return false if marker found)\n    bool push(uint8_t b)\n    {\n        uint8_t last = m_last;\n\n        // Skip padding\n        if (last == 0xFF && b == 0x00)\n            ;\n        // Marker found\n        else if (last == 0xFF && b != 0x00)\n        {\n            m_wr_offset--;\n            return false;\n        }\n        // Push byte into buffer\n        else\n        {\n            assert(m_wr_offset < m_max_size);\n            m_buffer[m_wr_offset++] = b;\n        }\n\n        m_last = b;\n\n        return true;\n    }\n\n    // Read upto 32-bit (aligned to MSB)\n    uint32_t read_word(void)\n    {\n        if (eof())\n            return 0;\n\n        int byte   = m_rd_offset / 8;\n        int bit    = m_rd_offset % 8; // 0 - 7\n        uint64_t w = 0;\n        for (int x=0;x<5;x++)\n        {\n            w |= m_buffer[byte+x];\n            w <<= 8;\n        }\n        w <<= bit;\n        return w >> 16;\n    }\n\n    void advance(int bits)\n    {\n        TEST_HOOKS_BITBUFFER(bits);\n        m_rd_offset += bits;\n    }\n\n    bool eof(void)\n    {\n        return (((m_rd_offset+7) / 8) >= m_wr_offset);\n    }\n\n    TEST_HOOKS_BITBUFFER_DECL;\n\nprivate:\n    uint8_t *m_buffer;\n    uint8_t  m_last;\n    int      m_max_size;\n    int      m_wr_offset;\n    int      m_rd_offset; // in bits\n};\n\n#endif\n"
  },
  {
    "path": "c_model/jpeg_dht.h",
    "content": "#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#include <assert.h>\n\n#define DHT_TABLE_Y_DC      0x00\n#define DHT_TABLE_Y_DC_IDX  0\n#define DHT_TABLE_Y_AC      0x10\n#define DHT_TABLE_Y_AC_IDX  1\n#define DHT_TABLE_CX_DC     0x01\n#define DHT_TABLE_CX_DC_IDX 2\n#define DHT_TABLE_CX_AC     0x11\n#define DHT_TABLE_CX_AC_IDX 3\n\n#define dprintf\n\n//-----------------------------------------------------------------------------\n// jpeg_dqt:\n//-----------------------------------------------------------------------------\nclass jpeg_dht\n{\npublic:\n    jpeg_dht() { reset(); }\n\n    void reset(void)\n    {\n        for (int i=0;i<4;i++)\n            memset(&m_dht_table[i], 0, sizeof(t_huffman_table));\n    }\n\n    int process(uint8_t *data, int len)\n    {\n        uint8_t *buf = data;\n        int consumed = 0;\n\n        // DHT tables can be combined into one section (it seems)\n        while (consumed <= (len-17))\n        {\n            // Huffman table info, first four MSBs represent table type (0 for DC, 1 for AC), last four LSBs represent table #\n            uint8_t  table_info  = *buf++;\n\n            int table_idx = 0;\n            switch (table_info)\n            {\n                case DHT_TABLE_Y_DC:\n                    table_idx = DHT_TABLE_Y_DC_IDX;\n                    break;\n                case DHT_TABLE_Y_AC:\n                    table_idx = DHT_TABLE_Y_AC_IDX;\n                    break;\n                case DHT_TABLE_CX_DC:\n                    table_idx = DHT_TABLE_CX_DC_IDX;\n                    break;\n                case DHT_TABLE_CX_AC:\n                    table_idx = DHT_TABLE_CX_AC_IDX;\n                    break;\n                default:\n                    assert(!\"ERROR: Bad JPEG\");\n                    break;\n            }\n            dprintf(\"DHT (Table idx %d)\\n\", table_idx);\n\n            // Reset table\n            memset(&m_dht_table[table_idx], 0, sizeof(m_dht_table[0]));\n\n            // Extract symbol count\n            uint8_t symb_count[16];\n            for (int x=0;x<16;x++)\n            {\n                symb_count[x] = *buf++;\n                dprintf(\" bit length: %d, symbols: %d\\n\", x, symb_count[x]);\n            }\n\n            // Extract table values\n            // Build the Huffman map of (length, code) -> value\n            uint16_t code = 0;\n            int entry = 0;\n            for (int x=0;x<16;x++)\n            {\n                for (int j=0;j<symb_count[x];j++)\n                {\n                    uint8_t dht_val = *buf++;\n                    m_dht_table[table_idx].code[entry]     = code;\n                    m_dht_table[table_idx].code_len[entry] = x+1;\n                    m_dht_table[table_idx].value[entry++]  = dht_val;\n                    dprintf(\" %d: %x -> %x\\n\", entry, code, dht_val);\n\n                    code++;\n                }\n                code <<= 1;\n            }\n            m_dht_table[table_idx].entries = entry;\n\n            consumed = buf - data;\n        }\n\n        return buf - data;\n    }\n\n    // lookup: Perform huffman lookup (starting from bit 15 of w)\n    int lookup(int table_idx, uint16_t w, uint8_t &value)\n    {\n        for (int i=0;i<m_dht_table[table_idx].entries;i++)\n        {\n            int      width   = m_dht_table[table_idx].code_len[i];\n            uint16_t bitmap  = m_dht_table[table_idx].code[i];\n            \n            \n            uint16_t shift_val = w >> (16-width);\n            //printf(\"- %d: check against %04x \", width, shift_val);\n            //print_bin(shift_val, width);\n            //printf(\" == %04x -> %02x\\n\", bitmap, value);\n            if (shift_val == bitmap)\n            {\n                value   = m_dht_table[table_idx].value[i];\n                return width;\n            }\n        }\n        return 0;\n    }\n\nprivate:\n    typedef struct\n    {\n        // 16-bit (max) code\n        uint16_t code[255];\n        // Code length\n        uint8_t  code_len[255];\n        // Value to translate to\n        uint8_t  value[255];\n        int      entries;\n    } t_huffman_table;\n\n    t_huffman_table m_dht_table[4];\n};\n\n#endif\n"
  },
  {
    "path": "c_model/jpeg_dqt.h",
    "content": "#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#include <assert.h>\n\n// Zigzag table\nstatic const int m_zigzag_table[]=\n{\n     0, 1, 8, 16,9, 2, 3,10,\n    17,24,32,25,18,11, 4, 5,\n    12,19,26,33,40,48,41,34,\n    27,20,13, 6, 7,14,21,28,\n    35,42,49,56,57,50,43,36,\n    29,22,15,23,30,37,44,51,\n    58,59,52,45,38,31,39,46,\n    53,60,61,54,47,55,62,63,\n    0\n};\n\n#define dprintf\n\n//-----------------------------------------------------------------------------\n// jpeg_dqt:\n//-----------------------------------------------------------------------------\nclass jpeg_dqt\n{\npublic:\n    jpeg_dqt() { reset(); }\n\n    //-------------------------------------------------------------------------\n    // reset: Reset DQT tables\n    //-------------------------------------------------------------------------\n    void reset(void)\n    {\n        memset(&m_table_dqt[0], 0, 64 * 4);\n    }\n\n    //-------------------------------------------------------------------------\n    // process: Store DQT table from input stream\n    //-------------------------------------------------------------------------\n    int process(uint8_t *data, int len)\n    {\n        uint8_t *buf = data;\n\n        // Table number\n        uint8_t  table_num = (*buf++) & 0x3;\n        dprintf(\" DQT: Table %d\\n\", table_num);\n\n        for (int x=0;x<64;x++)\n        {\n            // 8-bit\n            uint8_t qv = *buf++;\n            dprintf(\" %d: %x\\n\", x, qv);\n            m_table_dqt[table_num][x] = qv;\n        }\n\n        return buf - data;\n    }\n\n    //-------------------------------------------------------------------------\n    // lookup: DQT table entry lookup\n    //-------------------------------------------------------------------------\n    uint8_t lookup(int table_num, int position)\n    {\n        return m_table_dqt[table_num][position];\n    }\n\n    //-------------------------------------------------------------------------\n    // process_samples: Multiply out samples and de-zigzag ready for IDCT\n    // samples: (idx, value)\n    //-------------------------------------------------------------------------\n    void process_samples(int quant_table, int *sample_in, int *block_out, int count)\n    {\n        // Apply quantisation and zigzag\n        memset(block_out, 0, sizeof(block_out[0])*64);\n        for (int i=0;i<count;i++)\n        {\n            int16_t smpl      = (int16_t)(sample_in[i] & 0xFFFF);\n            int   block_idx   = (sample_in[i] >> 16);\n            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]);\n            block_out[m_zigzag_table[block_idx]] = smpl * lookup(quant_table,block_idx);\n        }\n    }\n\nprivate:\n    uint8_t  m_table_dqt[4][64];\n};\n\n#endif\n"
  },
  {
    "path": "c_model/jpeg_idct.h",
    "content": "#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#include <assert.h>\n\n//-----------------------------------------------------------------------------\n// jpeg_idct:\n//-----------------------------------------------------------------------------\nclass jpeg_idct\n{\npublic:\n    jpeg_idct() { reset(); }\n    void reset(void) { }\n\n    //-----------------------------------------------------------------------------\n    // process: Perform inverse DCT on already dequantized data.\n    // [Not quite sure who to attribute this implementation to...]\n    //-----------------------------------------------------------------------------\n    void process(int *data_in, int *data_out)\n    {\n        int s0,s1,s2,s3,s4,s5,s6,s7;\n        int t0,t1,t2,t3,t4,t5,t6,t7;\n\n        int working_buf[64];\n        int *temp_buf = working_buf;\n\n        // X - Rows\n        for(int i=0;i<8;i++)\n        {\n            s0 = (data_in[0] + data_in[4])       * C4;\n            s1 = (data_in[0] - data_in[4])       * C4;\n            s3 = (data_in[2] * C2) + (data_in[6] * C6);\n            s2 = (data_in[2] * C6) - (data_in[6] * C2);\n            s7 = (data_in[1] * C1) + (data_in[7] * C7);\n            s4 = (data_in[1] * C7) - (data_in[7] * C1);\n            s6 = (data_in[5] * C5) + (data_in[3] * C3);\n            s5 = (data_in[5] * C3) - (data_in[3] * C5);\n\n            // Next row\n            data_in += 8;\n\n            t0 = s0 + s3;\n            t3 = s0 - s3;\n            t1 = s1 + s2;\n            t2 = s1 - s2;\n            t4 = s4 + s5;\n            t5 = s4 - s5;\n            t7 = s7 + s6;\n            t6 = s7 - s6;\n\n            s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2)\n            s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2)\n\n            *temp_buf++ = (t0 + t7) >> 11;\n            *temp_buf++ = (t1 + s6) >> 11;\n            *temp_buf++ = (t2 + s5) >> 11;\n            *temp_buf++ = (t3 + t4) >> 11;\n            *temp_buf++ = (t3 - t4) >> 11;\n            *temp_buf++ = (t2 - s5) >> 11;\n            *temp_buf++ = (t1 - s6) >> 11;\n            *temp_buf++ = (t0 - t7) >> 11;\n        }\n\n        // Y - Columns\n        temp_buf = working_buf;\n        for(int i=0;i<8;i++)\n        {\n            s0 = (temp_buf[0] + temp_buf[32])     * C4;\n            s1 = (temp_buf[0] - temp_buf[32])     * C4;\n            s3 = temp_buf[16] * C2 + temp_buf[48] * C6;\n            s2 = temp_buf[16] * C6 - temp_buf[48] * C2;\n            s7 = temp_buf[8]  * C1 + temp_buf[56] * C7;\n            s4 = temp_buf[8]  * C7 - temp_buf[56] * C1;\n            s6 = temp_buf[40] * C5 + temp_buf[24] * C3;\n            s5 = temp_buf[40] * C3 - temp_buf[24] * C5;\n\n            t0 = s0 + s3;\n            t1 = s1 + s2;\n            t2 = s1 - s2;\n            t3 = s0 - s3;\n            t4 = s4 + s5;\n            t5 = s4 - s5;\n            t6 = s7 - s6;\n            t7 = s6 + s7;\n\n            s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2)\n            s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2)\n\n            data_out[0]  = ((t0 + t7) >> 15);\n            data_out[56] = ((t0 - t7) >> 15);\n            data_out[8]  = ((t1 + s6) >> 15);\n            data_out[48] = ((t1 - s6) >> 15);\n            data_out[16] = ((t2 + s5) >> 15);\n            data_out[40] = ((t2 - s5) >> 15);\n            data_out[24] = ((t3 + t4) >> 15);\n            data_out[32] = ((t3 - t4) >> 15);\n            \n            temp_buf++;\n            data_out++;\n        }\n        data_out -= 8;\n    }\n\n    static const int C1 = 4017; // cos( pi/16) x4096\n    static const int C2 = 3784; // cos(2pi/16) x4096\n    static const int C3 = 3406; // cos(3pi/16) x4096\n    static const int C4 = 2896; // cos(4pi/16) x4096\n    static const int C5 = 2276; // cos(5pi/16) x4096\n    static const int C6 = 1567; // cos(6pi/16) x4096\n    static const int C7 = 799;  // cos(7pi/16) x4096\n};\n\n#endif\n"
  },
  {
    "path": "c_model/jpeg_mcu_block.h",
    "content": "#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 <string.h>\n#include <assert.h>\n\n#include \"jpeg_bit_buffer.h\"\n#include \"jpeg_dht.h\"\n\n#define dprintf\n\n//-----------------------------------------------------------------------------\n// jpeg_mcu_block:\n//-----------------------------------------------------------------------------\nclass jpeg_mcu_block\n{\npublic:\n    jpeg_mcu_block(jpeg_bit_buffer *bit_buf, jpeg_dht *dht)\n    {\n        m_bit_buffer = bit_buf;\n        m_dht        = dht;\n        reset();\n    }\n\n    void reset(void) { }\n\n    //-----------------------------------------------------------------------------\n    // decode: Run huffman entropy decoder on input stream, expand to DC + upto \n    //         63 AC samples.\n    //-----------------------------------------------------------------------------\n    int decode(int table_idx, int16_t &olddccoeff, int32_t *block_out)\n    {\n        int samples = 0;\n\n        for (int coeff=0;coeff<64;coeff++)\n        {\n            // Read 32-bit word\n            uint32_t input_word = m_bit_buffer->read_word();\n\n            // Start with upper 16-bits\n            uint16_t input_data = input_word >> 16;\n\n            // Perform huffman decode on input data (code=RLE,num_bits)\n            uint8_t code   = 0;\n            int code_width = m_dht->lookup(table_idx + (coeff != 0), input_data, code);\n            int coef_bits  = code & 0xF;\n\n            // Move input point past decoded data\n            if (coeff == 0)\n                m_bit_buffer->advance(code_width + coef_bits);\n            // End of block or ZRL (no coefficient)\n            else if (code == 0 || code == 0xF0)\n                m_bit_buffer->advance(code_width);\n            else\n                m_bit_buffer->advance(code_width + coef_bits);\n\n            // Use remaining data for actual coeffecient\n            input_data = input_word >> (16 - code_width);\n\n            // DC\n            if (coeff == 0)\n            {\n                input_data >>= (16 - code);\n\n                int16_t dcoeff = decode_number(input_data, coef_bits) + olddccoeff;\n                olddccoeff = dcoeff;\n                block_out[samples++] = (0 << 16) | (dcoeff & 0xFFFF);\n            }\n            // AC\n            else\n            {\n                // End of block\n                if (code == 0)\n                {\n                    dprintf(\"SMPL: EOB\\n\");\n                    coeff = 64;\n                    break;\n                }\n\n                // The first part of the AC key_len is the number of leading zeros\n                if (code == 0xF0)\n                {\n                    // When the ZRL code comes, it is regarded as 15 zero data\n                    dprintf(\"SMPL: ZRL\\n\");\n                    coeff += 15; // +1 in the loop\n                    continue;\n                }\n                else if (code > 15)\n                    coeff   += code >> 4;\n\n                input_data >>= (16 - coef_bits);\n\n                if (coeff < 64)\n                {\n                    int16_t acoeff = decode_number(input_data, coef_bits);\n                    block_out[samples++] = (coeff << 16) | (acoeff & 0xFFFF);\n                }\n            }\n        }\n\n        return samples;\n    }\n\n\nprivate:\n    //-----------------------------------------------------------------------------\n    // decode_number: Extract number from code / width\n    //-----------------------------------------------------------------------------\n    int16_t decode_number(uint16_t code, int bits)\n    {   \n        if (!(code & (1<<(bits-1))) && bits != 0)\n        {\n            code |= (~0) << bits;\n            code += 1;\n        }\n        return code;\n    }\n\nprivate:\n    jpeg_bit_buffer *m_bit_buffer;\n    jpeg_dht *m_dht;\n\n};\n\n#endif\n"
  },
  {
    "path": "c_model/main.cpp",
    "content": "#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#include \"jpeg_dqt.h\"\n#include \"jpeg_dht.h\"\n#include \"jpeg_idct.h\"\n#include \"jpeg_bit_buffer.h\"\n#include \"jpeg_mcu_block.h\"\n\nstatic jpeg_dqt        m_dqt;\nstatic jpeg_dht        m_dht;\nstatic jpeg_idct       m_idct;\nstatic jpeg_bit_buffer m_bit_buffer;\nstatic jpeg_mcu_block  m_mcu_dec(&m_bit_buffer, &m_dht);\n\nstatic uint16_t m_width;\nstatic uint16_t m_height;\n\ntypedef enum eJpgMode\n{\n    JPEG_MONOCHROME,\n    JPEG_YCBCR_444,\n    JPEG_YCBCR_420,\n    JPEG_UNSUPPORTED\n} t_jpeg_mode;\n\nstatic t_jpeg_mode m_mode;\n\nstatic uint8_t m_dqt_table[3];\n\n#define get_byte(_buf, _idx)  _buf[_idx++]\n#define get_word(_buf, _idx)  ((_buf[_idx++] << 8) | (_buf[_idx++]))\n\nstatic uint8_t *m_output_r;\nstatic uint8_t *m_output_g;\nstatic uint8_t *m_output_b;\n\n#define dprintf\n#define dprintf_blk(_name, _arr, _max) for (int __i=0;__i<_max;__i++) { dprintf(\"%s: %d -> %d\\n\", _name, __i, _arr[__i]); }\n\n//-----------------------------------------------------------------------------\n// ConvertYUV2RGB: Convert from YUV to RGB\n//-----------------------------------------------------------------------------\nstatic void ConvertYUV2RGB(int block_num, int *y, int *cb, int *cr)\n{\n    int x_blocks = (m_width / 8);\n\n    // If width is not a multiple of 8, round up\n    if (m_width % 8)\n        x_blocks++;\n\n    int x_start = (block_num % x_blocks) * 8;\n    int y_start = (block_num / x_blocks) * 8;\n\n    if (m_mode == JPEG_MONOCHROME)\n    {\n        for (int i=0;i<64;i++)\n        {\n            int r = 128 + y[i];\n            int g = 128 + y[i];\n            int b = 128 + y[i];\n\n            // Avoid overflows\n            r = (r & 0xffffff00) ? (r >> 24) ^ 0xff : r;\n            g = (g & 0xffffff00) ? (g >> 24) ^ 0xff : g;\n            b = (b & 0xffffff00) ? (b >> 24) ^ 0xff : b;\n\n            int _x = x_start + (i % 8);\n            int _y = y_start + (i / 8);\n            int offset = (_y * m_width) + _x;\n\n            dprintf(\"RGB: r=%d g=%d b=%d -> %d\\n\", r, g, b, offset);\n            m_output_r[offset] = r;\n            m_output_g[offset] = g;\n            m_output_b[offset] = b;\n        }\n    }\n    else\n    {\n        for (int i=0;i<64;i++)\n        {\n            int r = 128 + y[i] + (cr[i] * 1.402);\n            int g = 128 + y[i] - (cb[i] * 0.34414) - (cr[i] * 0.71414);\n            int b = 128 + y[i] + (cb[i] * 1.772);\n\n            // Avoid overflows\n            r = (r & 0xffffff00) ? (r >> 24) ^ 0xff : r;\n            g = (g & 0xffffff00) ? (g >> 24) ^ 0xff : g;\n            b = (b & 0xffffff00) ? (b >> 24) ^ 0xff : b;\n\n            int _x = x_start + (i % 8);\n            int _y = y_start + (i / 8);\n            int offset = (_y * m_width) + _x;\n\n            if (_x < m_width && _y < m_height)\n            {\n                dprintf(\"RGB: r=%d g=%d b=%d -> %d [x=%d,y=%d]\\n\", r, g, b, offset, _x, _y);\n                m_output_r[offset] = r;\n                m_output_g[offset] = g;\n                m_output_b[offset] = b;\n            }\n        }\n    }\n}\n//-----------------------------------------------------------------------------\n// DecodeImage: Decode image data section (supports 4:4:4, 4:2:0, monochrom)\n//-----------------------------------------------------------------------------\nstatic bool DecodeImage(void)\n{\n    int16_t dc_coeff_Y = 0;\n    int16_t dc_coeff_Cb= 0;\n    int16_t dc_coeff_Cr= 0;\n    int32_t sample_out[64];\n    int     block_out[64];\n    int     y_dct_out[4*64];\n    int     cb_dct_out[64];\n    int     cr_dct_out[64];\n    int     count = 0;\n    int     loop = 0;\n\n    int block_num = 0;\n    while (!m_bit_buffer.eof())\n    {\n        // [Y0 Y1 Y2 Y3 Cb Cr] x N\n        if (m_mode == JPEG_YCBCR_420)\n        {\n            // Y0\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[0]);\n\n            // Y1\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[64]);\n\n            // Y2\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[128]);\n\n            // Y3\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[192]);\n\n            // Cb\n            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cb, sample_out);\n            m_dqt.process_samples(m_dqt_table[1], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &cb_dct_out[0]);\n\n            // Cr\n            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cr, sample_out);\n            m_dqt.process_samples(m_dqt_table[2], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &cr_dct_out[0]);\n\n            // Expand Cb/Cr samples to match Y0-3\n            int cb_dct_out_x2[256];\n            int cr_dct_out_x2[256];\n\n            for (int i=0;i<64;i++)\n            {\n                int x = i % 8;\n                int y = i / 16;\n                int sub_idx = (y * 8) + (x / 2);\n                cb_dct_out_x2[i] = cb_dct_out[sub_idx];\n                cr_dct_out_x2[i] = cr_dct_out[sub_idx];\n            }\n\n            for (int i=0;i<64;i++)\n            {\n                int x = i % 8;\n                int y = i / 16;\n                int sub_idx = (y * 8) + 4 + (x / 2);\n                cb_dct_out_x2[64 + i] = cb_dct_out[sub_idx];\n                cr_dct_out_x2[64 + i] = cr_dct_out[sub_idx];\n            }\n\n            for (int i=0;i<64;i++)\n            {\n                int x = i % 8;\n                int y = i / 16;\n                int sub_idx = 32 + (y * 8) + (x / 2);\n                cb_dct_out_x2[128+i] = cb_dct_out[sub_idx];\n                cr_dct_out_x2[128+i] = cr_dct_out[sub_idx];\n            }\n\n            for (int i=0;i<64;i++)\n            {\n                int x = i % 8;\n                int y = i / 16;\n                int sub_idx = 32 + (y * 8) + 4 + (x / 2);\n                cb_dct_out_x2[192 + i] = cb_dct_out[sub_idx];\n                cr_dct_out_x2[192 + i] = cr_dct_out[sub_idx];\n            }\n\n            int mcu_width = m_width / 8;\n            if (m_width % 8)\n                mcu_width++;\n\n            // Output all 4 blocks of pixels\n            ConvertYUV2RGB((block_num/2) + 0, &y_dct_out[0],  &cb_dct_out_x2[0], &cr_dct_out_x2[0]);\n            ConvertYUV2RGB((block_num/2) + 1, &y_dct_out[64], &cb_dct_out_x2[64], &cr_dct_out_x2[64]);\n            ConvertYUV2RGB((block_num/2) + mcu_width + 0, &y_dct_out[128], &cb_dct_out_x2[128], &cr_dct_out_x2[128]);\n            ConvertYUV2RGB((block_num/2) + mcu_width + 1, &y_dct_out[192], &cb_dct_out_x2[192], &cr_dct_out_x2[192]);\n            block_num += 4;\n\n            if (++loop == (mcu_width / 2))\n            {\n                block_num += (mcu_width * 2);\n                loop = 0;\n            }\n        }\n        // [Y Cb Cr] x N\n        else if (m_mode == JPEG_YCBCR_444)\n        {\n            // Y\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[0]);\n\n            // Cb\n            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cb, sample_out);\n            m_dqt.process_samples(m_dqt_table[1], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &cb_dct_out[0]);\n\n            // Cr\n            count = m_mcu_dec.decode(DHT_TABLE_CX_DC_IDX, dc_coeff_Cr, sample_out);\n            m_dqt.process_samples(m_dqt_table[2], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &cr_dct_out[0]);\n\n            ConvertYUV2RGB(block_num++, y_dct_out, cb_dct_out, cr_dct_out);\n        }\n        // [Y] x N\n        else if (m_mode == JPEG_MONOCHROME)\n        {\n            // Y\n            count = m_mcu_dec.decode(DHT_TABLE_Y_DC_IDX, dc_coeff_Y, sample_out);\n            m_dqt.process_samples(m_dqt_table[0], sample_out, block_out, count);\n            dprintf_blk(\"DCT-IN\", block_out, 64);\n            m_idct.process(block_out, &y_dct_out[0]);\n\n            ConvertYUV2RGB(block_num++, y_dct_out, cb_dct_out, cr_dct_out);\n        }\n    }\n\n    return true;\n}\n//-----------------------------------------------------------------------------\n// main:\n//-----------------------------------------------------------------------------\nint main(int argc, char* argv[])\n{\n    if (argc < 3)\n    {\n        printf(\"./jpeg src_image.jpg dst_image.ppm\\n\");\n        return -1;\n    }\n\n    const char *src_image = argv[1];\n    const char *dst_image = argv[2];\n\n    // Load source file\n    uint8_t *buf = NULL;\n    int      len = 0;\n    FILE *f = fopen(src_image, \"rb\");\n    if (f)\n    {\n        long size;\n\n        // Get size\n        fseek(f, 0, SEEK_END);\n        size = ftell(f);\n        rewind(f);\n\n        // Read file data in\n        buf = (uint8_t*)malloc(size);\n        assert(buf);\n        len = fread(buf, 1, size, f);\n\n        fclose(f);\n    }\n    else\n    {\n        printf(\"./jpeg src_image.jpg dst_image.ppm\\n\");\n        return -1;\n    }\n\n    m_dqt.reset();\n    m_dht.reset();\n    m_idct.reset();\n    m_mode = JPEG_UNSUPPORTED;\n    m_output_r = NULL;\n    m_output_g = NULL;\n    m_output_b = NULL;\n\n    uint8_t last_b = 0;\n    bool decode_done = false;\n    for (int i=0;i<len;)\n    {\n        uint8_t b = buf[i++];\n\n        //-----------------------------------------------------------------------------\n        // SOI: Start of image\n        //-----------------------------------------------------------------------------\n        if (last_b == 0xFF && b == 0xd8)\n            printf(\"Section: SOI\\n\");\n        //-----------------------------------------------------------------------------\n        // SOF0: Indicates that this is a baseline DCT-based JPEG\n        //-----------------------------------------------------------------------------\n        else if (last_b == 0xFF && b == 0xc0)\n        {\n            printf(\"Section: SOF0\\n\");\n            int seg_start = i;\n\n            // Length of the segment\n            uint16_t seg_len   = get_word(buf, i);\n\n            // Precision of the frame data\n            uint8_t  precision = get_byte(buf,i);\n\n            // Image height in pixels\n            m_height = get_word(buf, i);\n\n            // Image width in pixels\n            m_width = get_word(buf, i);\n\n            // Allocate pixel buffer\n            m_output_r = new uint8_t[m_height * m_width];\n            m_output_g = new uint8_t[m_height * m_width];\n            m_output_b = new uint8_t[m_height * m_width];\n            memset(m_output_r, 0, m_height * m_width);\n            memset(m_output_g, 0, m_height * m_width);\n            memset(m_output_b, 0, m_height * m_width);\n\n            // # of components (n) in frame, 1 for monochrom, 3 for colour images\n            uint8_t num_comps = get_byte(buf,i);\n            assert(num_comps <= 3);\n\n            printf(\" x=%d, y=%d, components=%d\\n\", m_width, m_height, num_comps);\n            uint8_t comp_id[3];\n            uint8_t comp_sample_factor[3];\n            uint8_t horiz_factor[3];\n            uint8_t vert_factor[3];\n\n            for (int x=0;x<num_comps;x++)\n            {\n                // First byte identifies the component\n                comp_id[x] = get_byte(buf,i);\n                // id: 1 = Y, 2 = Cb, 3 = Cr\n\n                // Second byte represents sampling factor (first four MSBs represent horizonal, last four LSBs represent vertical)\n                comp_sample_factor[x] = get_byte(buf,i);\n                horiz_factor[x]       = comp_sample_factor[x] >> 4;\n                vert_factor[x]        = comp_sample_factor[x] & 0xF;\n\n                // Third byte represents which quantization table to use for this component\n                m_dqt_table[x]        = get_byte(buf,i);\n                printf(\" num: %d a: %02x b: %02x\\n\", comp_id[x], comp_sample_factor[x], m_dqt_table[x]);\n                printf(\" horiz_factor: %d, vert_factor: %d\\n\", horiz_factor[x], vert_factor[x]);\n            }\n\n            m_mode = JPEG_UNSUPPORTED;\n\n            // Single component (Y)\n            if (num_comps == 1)\n            {\n                printf(\" Mode: Monochrome\\n\");\n                m_mode = JPEG_MONOCHROME;\n            }\n            // Colour image (YCbCr)\n            else if (num_comps == 3)\n            {\n                // YCbCr ordering expected\n                if (comp_id[0] == 1 && comp_id[1] == 2 && comp_id[2] == 3)\n                {\n                    if (horiz_factor[0] == 1 && vert_factor[0] == 1 &&\n                        horiz_factor[1] == 1 && vert_factor[1] == 1 &&\n                        horiz_factor[2] == 1 && vert_factor[2] == 1)\n                    {\n                        m_mode = JPEG_YCBCR_444;\n                        printf(\" Mode: YCbCr 4:4:4\\n\");\n                    }\n                    else if (horiz_factor[0] == 2 && vert_factor[0] == 2 &&\n                             horiz_factor[1] == 1 && vert_factor[1] == 1 &&\n                             horiz_factor[2] == 1 && vert_factor[2] == 1)\n                    {\n                        m_mode = JPEG_YCBCR_420;\n                        printf(\" Mode: YCbCr 4:2:0\\n\");\n                    }\n                }\n            }\n\n            i = seg_start + seg_len;\n        }\n        //-----------------------------------------------------------------------------\n        // DQT: Quantisation table\n        //-----------------------------------------------------------------------------\n        else if (last_b == 0xFF && b == 0xdb)\n        {\n            printf(\"Section: DQT Table\\n\");\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            m_dqt.process(&buf[i], seg_len);\n            i = seg_start + seg_len;\n        }\n        //-----------------------------------------------------------------------------\n        // DHT: Huffman table\n        //-----------------------------------------------------------------------------\n        else if (last_b == 0xFF && b == 0xc4)\n        {\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            printf(\"Section: DHT Table\\n\");\n            m_dht.process(&buf[i], seg_len);\n            i = seg_start + seg_len;\n        }\n        //-----------------------------------------------------------------------------\n        // EOI: End of image\n        //-----------------------------------------------------------------------------\n        else if (last_b == 0xFF && b == 0xd9)\n        {\n            printf(\"Section: EOI\\n\");\n            break;\n        }\n        //-----------------------------------------------------------------------------\n        // SOS: Start of Scan Segment (SOS)\n        //-----------------------------------------------------------------------------\n        else if (last_b == 0xFF && b == 0xda)\n        {\n            printf(\"Section: SOS\\n\");\n            int seg_start = i;\n\n            if (m_mode == JPEG_UNSUPPORTED)\n            {\n                printf(\"ERROR: Unsupported JPEG mode\\n\");\n                break;\n            }\n\n            uint16_t seg_len   = get_word(buf, i);\n\n            // Component count (n)\n            uint8_t  comp_count = get_byte(buf,i);\n\n            // Component data\n            for (int x=0;x<comp_count;x++)\n            {\n                // First byte denotes component ID\n                uint8_t comp_id = get_byte(buf,i);\n\n                // Second byte denotes the Huffman table used (first four MSBs denote Huffman table for DC, and last four LSBs denote Huffman table for AC)\n                uint8_t comp_table = get_byte(buf,i);\n\n                printf(\" %d: ID=%x Table=%x\\n\", x, comp_id, comp_table);\n            }\n\n            // Skip bytes\n            get_byte(buf,i);\n            get_byte(buf,i);\n            get_byte(buf,i);\n\n            i = seg_start + seg_len;\n\n            //-----------------------------------------------------------------------\n            // Process data segment\n            //-----------------------------------------------------------------------\n            m_bit_buffer.reset(len);\n            while (i < len)\n            {\n                b = buf[i];\n                if (m_bit_buffer.push(b))\n                    i++;\n                // Marker detected (reverse one byte)\n                else\n                {\n                    i--;\n                    break;\n                }\n            }\n\n            decode_done = DecodeImage();\n        }\n        //-----------------------------------------------------------------------------\n        // Unsupported / Skipped\n        //-----------------------------------------------------------------------------        \n        else if (last_b == 0xFF && b == 0xc2)\n        {\n            printf(\"Section: SOF2\\n\");\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            i = seg_start + seg_len;\n\n            printf(\"ERROR: Progressive JPEG not supported\\n\");\n            break; // ERROR: Not supported\n        }\n        else if (last_b == 0xFF && b == 0xdd)\n        {\n            printf(\"Section: DRI\\n\");\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            i = seg_start + seg_len;            \n        }\n        else if (last_b == 0xFF && b >= 0xd0 && b <= 0xd7)\n        {\n            printf(\"Section: RST%d\\n\", b - 0xd0);\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            i = seg_start + seg_len;\n        }\n        else if (last_b == 0xFF && b >= 0xe0 && b <= 0xef)\n        {\n            printf(\"Section: APP%d\\n\", b - 0xe0);\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            i = seg_start + seg_len;\n        }\n        else if (last_b == 0xFF && b == 0xfe)\n        {\n            printf(\"Section: COM\\n\");\n            int seg_start = i;\n            uint16_t seg_len   = get_word(buf, i);\n            i = seg_start + seg_len;\n        }\n\n        last_b = b;\n    }\n\n    if (decode_done)\n    {\n        FILE *f = fopen(dst_image, \"w\");\n        if (f)\n        {\n            fprintf(f, \"P6\\n\");\n            fprintf(f, \"%d %d\\n\", m_width, m_height);\n            fprintf(f, \"255\\n\");\n            for (int y=0;y<m_height;y++)\n                for (int x=0;x<m_width;x++)\n                {\n                    putc(m_output_r[(y*m_width)+x], f);\n                    putc(m_output_g[(y*m_width)+x], f);\n                    putc(m_output_b[(y*m_width)+x], f);\n                }\n            fclose(f);\n        }\n        else\n        {\n            fprintf(stderr, \"ERROR: Could not write file\\n\");\n            decode_done = false;\n        }\n    }\n\n    if (m_output_r) delete [] m_output_r;\n    if (m_output_g) delete [] m_output_g;\n    if (m_output_b) delete [] m_output_b;\n    return decode_done ? 0 : -1;\n}\n"
  },
  {
    "path": "c_model/makefile",
    "content": "###############################################################################\n# Makefile\n###############################################################################\n\n# Target\nTARGET\t   ?= jpeg\n\n# Source Files\nSRC_DIR    = .\n\nCFLAGS\t    = -O2 -fPIC\nCFLAGS     += -Wno-format\n\nINCLUDE_PATH += $(SRC_DIR)\nCFLAGS       += $(patsubst %,-I%,$(INCLUDE_PATH))\n\nLDFLAGS     = \nLIBS        = \n\n###############################################################################\n# Variables\n###############################################################################\nOBJ_DIR      ?= obj/\n\n###############################################################################\n# Variables: Lists of objects, source and deps\n###############################################################################\n# SRC / Object list\nsrc2obj       = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1)))\n\nSRC          ?= $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp))\nOBJ          ?= $(foreach src,$(SRC),$(call src2obj,$(src)))\n\n###############################################################################\n# Rules: Compilation macro\n###############################################################################\ndefine template_cpp\n$(call src2obj,$(1)): $(1) | $(OBJ_DIR)\n\t@echo \"# Compiling $(notdir $(1))\"\n\t@g++ $(CFLAGS) -c $$< -o $$@\nendef\n\n###############################################################################\n# Rules\n###############################################################################\nall: $(TARGET) \n\t\n$(OBJ_DIR):\n\t@mkdir -p $@\n\n$(foreach src,$(SRC),$(eval $(call template_cpp,$(src))))\t\n\n$(TARGET): $(OBJ) makefile\n\t@echo \"# Linking $(notdir $@)\"\n\t@g++ $(LDFLAGS) $(OBJ) $(LIBS) -o $@\n\nclean:\n\t-rm -rf $(OBJ_DIR) $(TARGET)\n"
  },
  {
    "path": "src_v/jpeg_bitbuffer.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_bitbuffer\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [  7:0]  inport_data_i\n    ,input           inport_last_i\n    ,input  [  5:0]  outport_pop_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 31:0]  outport_data_o\n    ,output          outport_last_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Registers\n//-----------------------------------------------------------------\nreg [7:0] ram_q[7:0];\nreg [5:0] rd_ptr_q;\nreg [5:0] wr_ptr_q;\nreg [6:0] count_q;\nreg       drain_q;\n\n//-----------------------------------------------------------------\n// Input side FIFO\n//-----------------------------------------------------------------\nreg [6:0] count_r; \nalways @ *\nbegin\n    count_r = count_q;\n\n    // Count up\n    if (inport_valid_i && inport_accept_o)\n        count_r = count_r + 7'd8;\n\n    // Count down\n    if (outport_valid_o && (|outport_pop_i))\n        count_r = count_r - outport_pop_i;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    count_q   <= 7'b0;\n    rd_ptr_q  <= 6'b0;\n    wr_ptr_q  <= 6'b0;\n    drain_q   <= 1'b0;\nend\nelse if (img_start_i)\nbegin\n    count_q   <= 7'b0;\n    rd_ptr_q  <= 6'b0;\n    wr_ptr_q  <= 6'b0;\n    drain_q   <= 1'b0;\nend\nelse\nbegin\n    // End of image\n    if (inport_last_i)\n        drain_q <= 1'b1;\n\n    // Push\n    if (inport_valid_i && inport_accept_o)\n    begin\n        ram_q[wr_ptr_q[5:3]] <= inport_data_i;\n        wr_ptr_q             <= wr_ptr_q + 6'd8;\n    end\n\n    // Pop\n    if (outport_valid_o && (|outport_pop_i))\n        rd_ptr_q <= rd_ptr_q + outport_pop_i;\n\n    count_q <= count_r;\nend\n\nassign inport_accept_o = (count_q <= 7'd56);\n\n//-------------------------------------------------------------------\n// Output side FIFO\n//-------------------------------------------------------------------\nreg [39:0] fifo_data_r;\n\nalways @ *\nbegin\n    fifo_data_r = 40'b0;\n\n    case (rd_ptr_q[5:3])\n    3'd0: fifo_data_r = {ram_q[0], ram_q[1], ram_q[2], ram_q[3], ram_q[4]};\n    3'd1: fifo_data_r = {ram_q[1], ram_q[2], ram_q[3], ram_q[4], ram_q[5]};\n    3'd2: fifo_data_r = {ram_q[2], ram_q[3], ram_q[4], ram_q[5], ram_q[6]};\n    3'd3: fifo_data_r = {ram_q[3], ram_q[4], ram_q[5], ram_q[6], ram_q[7]};\n    3'd4: fifo_data_r = {ram_q[4], ram_q[5], ram_q[6], ram_q[7], ram_q[0]};\n    3'd5: fifo_data_r = {ram_q[5], ram_q[6], ram_q[7], ram_q[0], ram_q[1]};\n    3'd6: fifo_data_r = {ram_q[6], ram_q[7], ram_q[0], ram_q[1], ram_q[2]};\n    3'd7: fifo_data_r = {ram_q[7], ram_q[0], ram_q[1], ram_q[2], ram_q[3]};\n    endcase\nend\n\nwire [39:0] data_shifted_w = fifo_data_r << rd_ptr_q[2:0];\n\nassign outport_valid_o  = (count_q >= 7'd32) || (drain_q && count_q != 7'd0);\nassign outport_data_o   = data_shifted_w[39:8];\nassign outport_last_o   = 1'b0;\n\n\n`ifdef verilator\nfunction get_valid; /*verilator public*/\nbegin\n    get_valid = inport_valid_i && inport_accept_o;\nend\nendfunction\nfunction [7:0] get_data; /*verilator public*/\nbegin\n    get_data = inport_data_i;\nend\nendfunction\n`endif\n\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_core.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_core\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter SUPPORT_WRITABLE_DHT = 0\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data_i\n    ,input  [  3:0]  inport_strb_i\n    ,input           inport_last_i\n    ,input           outport_accept_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 15:0]  outport_width_o\n    ,output [ 15:0]  outport_height_o\n    ,output [ 15:0]  outport_pixel_x_o\n    ,output [ 15:0]  outport_pixel_y_o\n    ,output [  7:0]  outport_pixel_r_o\n    ,output [  7:0]  outport_pixel_g_o\n    ,output [  7:0]  outport_pixel_b_o\n    ,output          idle_o\n);\n\nwire  [ 15:0]  idct_outport_data_w;\nwire           dqt_inport_valid_w;\nwire  [ 31:0]  dqt_inport_id_w;\nwire  [ 31:0]  output_outport_data_w;\nwire  [  5:0]  idct_inport_idx_w;\nwire           dqt_inport_eob_w;\nwire           img_start_w;\nwire  [ 15:0]  img_height_w;\nwire           output_inport_accept_w;\nwire  [ 15:0]  img_width_w;\nwire           dht_cfg_valid_w;\nwire           lookup_req_w;\nwire           lookup_valid_w;\nwire  [  1:0]  img_dqt_table_cb_w;\nwire  [  7:0]  dht_cfg_data_w;\nwire           img_end_w;\nwire  [ 31:0]  idct_inport_id_w;\nwire  [  4:0]  lookup_width_w;\nwire           idct_inport_accept_w;\nwire  [  5:0]  output_inport_idx_w;\nwire  [ 15:0]  dqt_outport_data_w;\nwire           dqt_inport_blk_space_w;\nwire           idct_inport_valid_w;\nwire  [  7:0]  dqt_cfg_data_w;\nwire  [  1:0]  img_dqt_table_y_w;\nwire           idct_inport_eob_w;\nwire           dht_cfg_accept_w;\nwire  [ 31:0]  output_inport_id_w;\nwire           output_inport_valid_w;\nwire  [ 15:0]  lookup_input_w;\nwire           dqt_cfg_accept_w;\nwire  [  7:0]  lookup_value_w;\nwire  [  1:0]  lookup_table_w;\nwire           dht_cfg_last_w;\nwire  [  5:0]  dqt_inport_idx_w;\nwire  [  1:0]  img_mode_w;\nwire  [  1:0]  img_dqt_table_cr_w;\nwire           bb_inport_valid_w;\nwire           bb_outport_last_w;\nwire           bb_inport_last_w;\nwire  [  5:0]  bb_outport_pop_w;\nwire  [  7:0]  bb_inport_data_w;\nwire           dqt_cfg_valid_w;\nwire           bb_outport_valid_w;\nwire           bb_inport_accept_w;\nwire  [ 31:0]  bb_outport_data_w;\nwire           dqt_cfg_last_w;\n\n\njpeg_input\nu_jpeg_input\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.inport_valid_i(inport_valid_i)\n    ,.inport_data_i(inport_data_i)\n    ,.inport_strb_i(inport_strb_i)\n    ,.inport_last_i(inport_last_i)\n    ,.dqt_cfg_accept_i(dqt_cfg_accept_w)\n    ,.dht_cfg_accept_i(dht_cfg_accept_w)\n    ,.data_accept_i(bb_inport_accept_w)\n\n    // Outputs\n    ,.inport_accept_o(inport_accept_o)\n    ,.img_start_o(img_start_w)\n    ,.img_end_o(img_end_w)\n    ,.img_width_o(img_width_w)\n    ,.img_height_o(img_height_w)\n    ,.img_mode_o(img_mode_w)\n    ,.img_dqt_table_y_o(img_dqt_table_y_w)\n    ,.img_dqt_table_cb_o(img_dqt_table_cb_w)\n    ,.img_dqt_table_cr_o(img_dqt_table_cr_w)\n    ,.dqt_cfg_valid_o(dqt_cfg_valid_w)\n    ,.dqt_cfg_data_o(dqt_cfg_data_w)\n    ,.dqt_cfg_last_o(dqt_cfg_last_w)\n    ,.dht_cfg_valid_o(dht_cfg_valid_w)\n    ,.dht_cfg_data_o(dht_cfg_data_w)\n    ,.dht_cfg_last_o(dht_cfg_last_w)\n    ,.data_valid_o(bb_inport_valid_w)\n    ,.data_data_o(bb_inport_data_w)\n    ,.data_last_o(bb_inport_last_w)\n);\n\n\njpeg_dht\n#(\n     .SUPPORT_WRITABLE_DHT(SUPPORT_WRITABLE_DHT)\n)\nu_jpeg_dht\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.cfg_valid_i(dht_cfg_valid_w)\n    ,.cfg_data_i(dht_cfg_data_w)\n    ,.cfg_last_i(dht_cfg_last_w)\n    ,.lookup_req_i(lookup_req_w)\n    ,.lookup_table_i(lookup_table_w)\n    ,.lookup_input_i(lookup_input_w)\n\n    // Outputs\n    ,.cfg_accept_o(dht_cfg_accept_w)\n    ,.lookup_valid_o(lookup_valid_w)\n    ,.lookup_width_o(lookup_width_w)\n    ,.lookup_value_o(lookup_value_w)\n);\n\n\njpeg_idct\nu_jpeg_idct\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.img_start_i(img_start_w)\n    ,.img_end_i(img_end_w)\n    ,.inport_valid_i(idct_inport_valid_w)\n    ,.inport_data_i(idct_outport_data_w)\n    ,.inport_idx_i(idct_inport_idx_w)\n    ,.inport_eob_i(idct_inport_eob_w)\n    ,.inport_id_i(idct_inport_id_w)\n    ,.outport_accept_i(output_inport_accept_w)\n\n    // Outputs\n    ,.inport_accept_o(idct_inport_accept_w)\n    ,.outport_valid_o(output_inport_valid_w)\n    ,.outport_data_o(output_outport_data_w)\n    ,.outport_idx_o(output_inport_idx_w)\n    ,.outport_id_o(output_inport_id_w)\n);\n\n\njpeg_dqt\nu_jpeg_dqt\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.img_start_i(img_start_w)\n    ,.img_end_i(img_end_w)\n    ,.img_dqt_table_y_i(img_dqt_table_y_w)\n    ,.img_dqt_table_cb_i(img_dqt_table_cb_w)\n    ,.img_dqt_table_cr_i(img_dqt_table_cr_w)\n    ,.cfg_valid_i(dqt_cfg_valid_w)\n    ,.cfg_data_i(dqt_cfg_data_w)\n    ,.cfg_last_i(dqt_cfg_last_w)\n    ,.inport_valid_i(dqt_inport_valid_w)\n    ,.inport_data_i(dqt_outport_data_w)\n    ,.inport_idx_i(dqt_inport_idx_w)\n    ,.inport_id_i(dqt_inport_id_w)\n    ,.inport_eob_i(dqt_inport_eob_w)\n    ,.outport_accept_i(idct_inport_accept_w)\n\n    // Outputs\n    ,.cfg_accept_o(dqt_cfg_accept_w)\n    ,.inport_blk_space_o(dqt_inport_blk_space_w)\n    ,.outport_valid_o(idct_inport_valid_w)\n    ,.outport_data_o(idct_outport_data_w)\n    ,.outport_idx_o(idct_inport_idx_w)\n    ,.outport_id_o(idct_inport_id_w)\n    ,.outport_eob_o(idct_inport_eob_w)\n);\n\n\njpeg_output\nu_jpeg_output\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.img_start_i(img_start_w)\n    ,.img_end_i(img_end_w)\n    ,.img_width_i(img_width_w)\n    ,.img_height_i(img_height_w)\n    ,.img_mode_i(img_mode_w)\n    ,.inport_valid_i(output_inport_valid_w)\n    ,.inport_data_i(output_outport_data_w)\n    ,.inport_idx_i(output_inport_idx_w)\n    ,.inport_id_i(output_inport_id_w)\n    ,.outport_accept_i(outport_accept_i)\n\n    // Outputs\n    ,.inport_accept_o(output_inport_accept_w)\n    ,.outport_valid_o(outport_valid_o)\n    ,.outport_width_o(outport_width_o)\n    ,.outport_height_o(outport_height_o)\n    ,.outport_pixel_x_o(outport_pixel_x_o)\n    ,.outport_pixel_y_o(outport_pixel_y_o)\n    ,.outport_pixel_r_o(outport_pixel_r_o)\n    ,.outport_pixel_g_o(outport_pixel_g_o)\n    ,.outport_pixel_b_o(outport_pixel_b_o)\n    ,.idle_o(idle_o)\n);\n\n\njpeg_bitbuffer\nu_jpeg_bitbuffer\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.img_start_i(img_start_w)\n    ,.img_end_i(img_end_w)\n    ,.inport_valid_i(bb_inport_valid_w)\n    ,.inport_data_i(bb_inport_data_w)\n    ,.inport_last_i(bb_inport_last_w)\n    ,.outport_pop_i(bb_outport_pop_w)\n\n    // Outputs\n    ,.inport_accept_o(bb_inport_accept_w)\n    ,.outport_valid_o(bb_outport_valid_w)\n    ,.outport_data_o(bb_outport_data_w)\n    ,.outport_last_o(bb_outport_last_w)\n);\n\n\njpeg_mcu_proc\nu_jpeg_mcu_proc\n(\n    // Inputs\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.img_start_i(img_start_w)\n    ,.img_end_i(img_end_w)\n    ,.img_width_i(img_width_w)\n    ,.img_height_i(img_height_w)\n    ,.img_mode_i(img_mode_w)\n    ,.inport_valid_i(bb_outport_valid_w)\n    ,.inport_data_i(bb_outport_data_w)\n    ,.inport_last_i(bb_outport_last_w)\n    ,.lookup_valid_i(lookup_valid_w)\n    ,.lookup_width_i(lookup_width_w)\n    ,.lookup_value_i(lookup_value_w)\n    ,.outport_blk_space_i(dqt_inport_blk_space_w)\n\n    // Outputs\n    ,.inport_pop_o(bb_outport_pop_w)\n    ,.lookup_req_o(lookup_req_w)\n    ,.lookup_table_o(lookup_table_w)\n    ,.lookup_input_o(lookup_input_w)\n    ,.outport_valid_o(dqt_inport_valid_w)\n    ,.outport_data_o(dqt_outport_data_w)\n    ,.outport_idx_o(dqt_inport_idx_w)\n    ,.outport_id_o(dqt_inport_id_w)\n    ,.outport_eob_o(dqt_inport_eob_w)\n);\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_dht.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_dht\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter SUPPORT_WRITABLE_DHT = 0\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           cfg_valid_i\n    ,input  [  7:0]  cfg_data_i\n    ,input           cfg_last_i\n    ,input           lookup_req_i\n    ,input  [  1:0]  lookup_table_i\n    ,input  [ 15:0]  lookup_input_i\n\n    // Outputs\n    ,output          cfg_accept_o\n    ,output          lookup_valid_o\n    ,output [  4:0]  lookup_width_o\n    ,output [  7:0]  lookup_value_o\n);\n\n\n\n\nlocalparam DHT_TABLE_Y_DC      = 8'h00;\nlocalparam DHT_TABLE_Y_AC      = 8'h10;\nlocalparam DHT_TABLE_CX_DC     = 8'h01;\nlocalparam DHT_TABLE_CX_AC     = 8'h11;\n\n//---------------------------------------------------------------------\n// Support writable huffman tables (e.g. file contains optimised tables)\n//---------------------------------------------------------------------\ngenerate\nif (SUPPORT_WRITABLE_DHT)\nbegin\n    reg [15:0] y_dc_min_code_q[0:15];\n    reg [15:0] y_dc_max_code_q[0:15];\n    reg [9:0]  y_dc_ptr_q[0:15];\n    reg [15:0] y_ac_min_code_q[0:15];\n    reg [15:0] y_ac_max_code_q[0:15];\n    reg [9:0]  y_ac_ptr_q[0:15];\n    reg [15:0] cx_dc_min_code_q[0:15];\n    reg [15:0] cx_dc_max_code_q[0:15];\n    reg [9:0]  cx_dc_ptr_q[0:15];\n    reg [15:0] cx_ac_min_code_q[0:15];\n    reg [15:0] cx_ac_max_code_q[0:15];\n    reg [9:0]  cx_ac_ptr_q[0:15];\n\n    // DHT tables can be combined into one section...\n    // Reset the table state machine at the end of each table\n    wire cfg_last_w = cfg_last_i || (total_entries_q == idx_q && idx_q >= 12'd16);\n\n    //-----------------------------------------------------------------\n    // Capture Index\n    //-----------------------------------------------------------------\n    reg [11:0] idx_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        idx_q <= 12'hFFF;\n    else if (cfg_valid_i && cfg_last_w && cfg_accept_o)\n        idx_q <= 12'hFFF;\n    else if (cfg_valid_i && cfg_accept_o)\n        idx_q <= idx_q + 12'd1;\n\n    //-----------------------------------------------------------------\n    // Table Index\n    //-----------------------------------------------------------------\n    reg [7:0] cfg_table_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        cfg_table_q <= 8'b0;\n    else if (cfg_valid_i && cfg_accept_o && idx_q == 12'hFFF)\n        cfg_table_q <= cfg_data_i;\n\n    //-----------------------------------------------------------------\n    // Extract symbol count (temporary)\n    //-----------------------------------------------------------------\n    reg [7:0]  num_entries_q[0:15];\n    reg [15:0] has_entries_q; // bitmap\n    reg [11:0] total_entries_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n    begin\n        num_entries_q[0] <= 8'b0;\n        num_entries_q[1] <= 8'b0;\n        num_entries_q[2] <= 8'b0;\n        num_entries_q[3] <= 8'b0;\n        num_entries_q[4] <= 8'b0;\n        num_entries_q[5] <= 8'b0;\n        num_entries_q[6] <= 8'b0;\n        num_entries_q[7] <= 8'b0;\n        num_entries_q[8] <= 8'b0;\n        num_entries_q[9] <= 8'b0;\n        num_entries_q[10] <= 8'b0;\n        num_entries_q[11] <= 8'b0;\n        num_entries_q[12] <= 8'b0;\n        num_entries_q[13] <= 8'b0;\n        num_entries_q[14] <= 8'b0;\n        num_entries_q[15] <= 8'b0;\n        has_entries_q   <= 16'b0;\n        total_entries_q <= 12'd15;\n    end\n    else if (cfg_valid_i && cfg_accept_o && idx_q < 12'd16)\n    begin\n        num_entries_q[idx_q[3:0]] <= cfg_data_i;\n        has_entries_q[idx_q[3:0]] <= (cfg_data_i != 8'b0);\n        total_entries_q           <= total_entries_q + {4'b0, cfg_data_i};\n    end\n    // End of DHT table\n    else if (cfg_valid_i && cfg_last_w && cfg_accept_o)\n    begin\n        num_entries_q[0] <= 8'b0;\n        num_entries_q[1] <= 8'b0;\n        num_entries_q[2] <= 8'b0;\n        num_entries_q[3] <= 8'b0;\n        num_entries_q[4] <= 8'b0;\n        num_entries_q[5] <= 8'b0;\n        num_entries_q[6] <= 8'b0;\n        num_entries_q[7] <= 8'b0;\n        num_entries_q[8] <= 8'b0;\n        num_entries_q[9] <= 8'b0;\n        num_entries_q[10] <= 8'b0;\n        num_entries_q[11] <= 8'b0;\n        num_entries_q[12] <= 8'b0;\n        num_entries_q[13] <= 8'b0;\n        num_entries_q[14] <= 8'b0;\n        num_entries_q[15] <= 8'b0;\n        has_entries_q   <= 16'b0;\n        total_entries_q <= 12'd15;\n    end\n\n    //-----------------------------------------------------------------\n    // Fill tables\n    //-----------------------------------------------------------------\n    reg [3:0]  i_q;\n    reg [7:0]  j_q;\n    reg [15:0] code_q;\n    reg [9:0]  next_ptr_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n    begin\n        y_dc_min_code_q[0] <= 16'b0;\n        y_dc_max_code_q[0] <= 16'b0;\n        y_dc_ptr_q[0]      <= 10'b0;\n        y_dc_min_code_q[1] <= 16'b0;\n        y_dc_max_code_q[1] <= 16'b0;\n        y_dc_ptr_q[1]      <= 10'b0;\n        y_dc_min_code_q[2] <= 16'b0;\n        y_dc_max_code_q[2] <= 16'b0;\n        y_dc_ptr_q[2]      <= 10'b0;\n        y_dc_min_code_q[3] <= 16'b0;\n        y_dc_max_code_q[3] <= 16'b0;\n        y_dc_ptr_q[3]      <= 10'b0;\n        y_dc_min_code_q[4] <= 16'b0;\n        y_dc_max_code_q[4] <= 16'b0;\n        y_dc_ptr_q[4]      <= 10'b0;\n        y_dc_min_code_q[5] <= 16'b0;\n        y_dc_max_code_q[5] <= 16'b0;\n        y_dc_ptr_q[5]      <= 10'b0;\n        y_dc_min_code_q[6] <= 16'b0;\n        y_dc_max_code_q[6] <= 16'b0;\n        y_dc_ptr_q[6]      <= 10'b0;\n        y_dc_min_code_q[7] <= 16'b0;\n        y_dc_max_code_q[7] <= 16'b0;\n        y_dc_ptr_q[7]      <= 10'b0;\n        y_dc_min_code_q[8] <= 16'b0;\n        y_dc_max_code_q[8] <= 16'b0;\n        y_dc_ptr_q[8]      <= 10'b0;\n        y_dc_min_code_q[9] <= 16'b0;\n        y_dc_max_code_q[9] <= 16'b0;\n        y_dc_ptr_q[9]      <= 10'b0;\n        y_dc_min_code_q[10] <= 16'b0;\n        y_dc_max_code_q[10] <= 16'b0;\n        y_dc_ptr_q[10]      <= 10'b0;\n        y_dc_min_code_q[11] <= 16'b0;\n        y_dc_max_code_q[11] <= 16'b0;\n        y_dc_ptr_q[11]      <= 10'b0;\n        y_dc_min_code_q[12] <= 16'b0;\n        y_dc_max_code_q[12] <= 16'b0;\n        y_dc_ptr_q[12]      <= 10'b0;\n        y_dc_min_code_q[13] <= 16'b0;\n        y_dc_max_code_q[13] <= 16'b0;\n        y_dc_ptr_q[13]      <= 10'b0;\n        y_dc_min_code_q[14] <= 16'b0;\n        y_dc_max_code_q[14] <= 16'b0;\n        y_dc_ptr_q[14]      <= 10'b0;\n        y_dc_min_code_q[15] <= 16'b0;\n        y_dc_max_code_q[15] <= 16'b0;\n        y_dc_ptr_q[15]      <= 10'b0;\n        y_ac_min_code_q[0] <= 16'b0;\n        y_ac_max_code_q[0] <= 16'b0;\n        y_ac_ptr_q[0]      <= 10'b0;\n        y_ac_min_code_q[1] <= 16'b0;\n        y_ac_max_code_q[1] <= 16'b0;\n        y_ac_ptr_q[1]      <= 10'b0;\n        y_ac_min_code_q[2] <= 16'b0;\n        y_ac_max_code_q[2] <= 16'b0;\n        y_ac_ptr_q[2]      <= 10'b0;\n        y_ac_min_code_q[3] <= 16'b0;\n        y_ac_max_code_q[3] <= 16'b0;\n        y_ac_ptr_q[3]      <= 10'b0;\n        y_ac_min_code_q[4] <= 16'b0;\n        y_ac_max_code_q[4] <= 16'b0;\n        y_ac_ptr_q[4]      <= 10'b0;\n        y_ac_min_code_q[5] <= 16'b0;\n        y_ac_max_code_q[5] <= 16'b0;\n        y_ac_ptr_q[5]      <= 10'b0;\n        y_ac_min_code_q[6] <= 16'b0;\n        y_ac_max_code_q[6] <= 16'b0;\n        y_ac_ptr_q[6]      <= 10'b0;\n        y_ac_min_code_q[7] <= 16'b0;\n        y_ac_max_code_q[7] <= 16'b0;\n        y_ac_ptr_q[7]      <= 10'b0;\n        y_ac_min_code_q[8] <= 16'b0;\n        y_ac_max_code_q[8] <= 16'b0;\n        y_ac_ptr_q[8]      <= 10'b0;\n        y_ac_min_code_q[9] <= 16'b0;\n        y_ac_max_code_q[9] <= 16'b0;\n        y_ac_ptr_q[9]      <= 10'b0;\n        y_ac_min_code_q[10] <= 16'b0;\n        y_ac_max_code_q[10] <= 16'b0;\n        y_ac_ptr_q[10]      <= 10'b0;\n        y_ac_min_code_q[11] <= 16'b0;\n        y_ac_max_code_q[11] <= 16'b0;\n        y_ac_ptr_q[11]      <= 10'b0;\n        y_ac_min_code_q[12] <= 16'b0;\n        y_ac_max_code_q[12] <= 16'b0;\n        y_ac_ptr_q[12]      <= 10'b0;\n        y_ac_min_code_q[13] <= 16'b0;\n        y_ac_max_code_q[13] <= 16'b0;\n        y_ac_ptr_q[13]      <= 10'b0;\n        y_ac_min_code_q[14] <= 16'b0;\n        y_ac_max_code_q[14] <= 16'b0;\n        y_ac_ptr_q[14]      <= 10'b0;\n        y_ac_min_code_q[15] <= 16'b0;\n        y_ac_max_code_q[15] <= 16'b0;\n        y_ac_ptr_q[15]      <= 10'b0;\n        cx_dc_min_code_q[0] <= 16'b0;\n        cx_dc_max_code_q[0] <= 16'b0;\n        cx_dc_ptr_q[0]      <= 10'b0;\n        cx_dc_min_code_q[1] <= 16'b0;\n        cx_dc_max_code_q[1] <= 16'b0;\n        cx_dc_ptr_q[1]      <= 10'b0;\n        cx_dc_min_code_q[2] <= 16'b0;\n        cx_dc_max_code_q[2] <= 16'b0;\n        cx_dc_ptr_q[2]      <= 10'b0;\n        cx_dc_min_code_q[3] <= 16'b0;\n        cx_dc_max_code_q[3] <= 16'b0;\n        cx_dc_ptr_q[3]      <= 10'b0;\n        cx_dc_min_code_q[4] <= 16'b0;\n        cx_dc_max_code_q[4] <= 16'b0;\n        cx_dc_ptr_q[4]      <= 10'b0;\n        cx_dc_min_code_q[5] <= 16'b0;\n        cx_dc_max_code_q[5] <= 16'b0;\n        cx_dc_ptr_q[5]      <= 10'b0;\n        cx_dc_min_code_q[6] <= 16'b0;\n        cx_dc_max_code_q[6] <= 16'b0;\n        cx_dc_ptr_q[6]      <= 10'b0;\n        cx_dc_min_code_q[7] <= 16'b0;\n        cx_dc_max_code_q[7] <= 16'b0;\n        cx_dc_ptr_q[7]      <= 10'b0;\n        cx_dc_min_code_q[8] <= 16'b0;\n        cx_dc_max_code_q[8] <= 16'b0;\n        cx_dc_ptr_q[8]      <= 10'b0;\n        cx_dc_min_code_q[9] <= 16'b0;\n        cx_dc_max_code_q[9] <= 16'b0;\n        cx_dc_ptr_q[9]      <= 10'b0;\n        cx_dc_min_code_q[10] <= 16'b0;\n        cx_dc_max_code_q[10] <= 16'b0;\n        cx_dc_ptr_q[10]      <= 10'b0;\n        cx_dc_min_code_q[11] <= 16'b0;\n        cx_dc_max_code_q[11] <= 16'b0;\n        cx_dc_ptr_q[11]      <= 10'b0;\n        cx_dc_min_code_q[12] <= 16'b0;\n        cx_dc_max_code_q[12] <= 16'b0;\n        cx_dc_ptr_q[12]      <= 10'b0;\n        cx_dc_min_code_q[13] <= 16'b0;\n        cx_dc_max_code_q[13] <= 16'b0;\n        cx_dc_ptr_q[13]      <= 10'b0;\n        cx_dc_min_code_q[14] <= 16'b0;\n        cx_dc_max_code_q[14] <= 16'b0;\n        cx_dc_ptr_q[14]      <= 10'b0;\n        cx_dc_min_code_q[15] <= 16'b0;\n        cx_dc_max_code_q[15] <= 16'b0;\n        cx_dc_ptr_q[15]      <= 10'b0;\n        cx_ac_min_code_q[0] <= 16'b0;\n        cx_ac_max_code_q[0] <= 16'b0;\n        cx_ac_ptr_q[0]      <= 10'b0;\n        cx_ac_min_code_q[1] <= 16'b0;\n        cx_ac_max_code_q[1] <= 16'b0;\n        cx_ac_ptr_q[1]      <= 10'b0;\n        cx_ac_min_code_q[2] <= 16'b0;\n        cx_ac_max_code_q[2] <= 16'b0;\n        cx_ac_ptr_q[2]      <= 10'b0;\n        cx_ac_min_code_q[3] <= 16'b0;\n        cx_ac_max_code_q[3] <= 16'b0;\n        cx_ac_ptr_q[3]      <= 10'b0;\n        cx_ac_min_code_q[4] <= 16'b0;\n        cx_ac_max_code_q[4] <= 16'b0;\n        cx_ac_ptr_q[4]      <= 10'b0;\n        cx_ac_min_code_q[5] <= 16'b0;\n        cx_ac_max_code_q[5] <= 16'b0;\n        cx_ac_ptr_q[5]      <= 10'b0;\n        cx_ac_min_code_q[6] <= 16'b0;\n        cx_ac_max_code_q[6] <= 16'b0;\n        cx_ac_ptr_q[6]      <= 10'b0;\n        cx_ac_min_code_q[7] <= 16'b0;\n        cx_ac_max_code_q[7] <= 16'b0;\n        cx_ac_ptr_q[7]      <= 10'b0;\n        cx_ac_min_code_q[8] <= 16'b0;\n        cx_ac_max_code_q[8] <= 16'b0;\n        cx_ac_ptr_q[8]      <= 10'b0;\n        cx_ac_min_code_q[9] <= 16'b0;\n        cx_ac_max_code_q[9] <= 16'b0;\n        cx_ac_ptr_q[9]      <= 10'b0;\n        cx_ac_min_code_q[10] <= 16'b0;\n        cx_ac_max_code_q[10] <= 16'b0;\n        cx_ac_ptr_q[10]      <= 10'b0;\n        cx_ac_min_code_q[11] <= 16'b0;\n        cx_ac_max_code_q[11] <= 16'b0;\n        cx_ac_ptr_q[11]      <= 10'b0;\n        cx_ac_min_code_q[12] <= 16'b0;\n        cx_ac_max_code_q[12] <= 16'b0;\n        cx_ac_ptr_q[12]      <= 10'b0;\n        cx_ac_min_code_q[13] <= 16'b0;\n        cx_ac_max_code_q[13] <= 16'b0;\n        cx_ac_ptr_q[13]      <= 10'b0;\n        cx_ac_min_code_q[14] <= 16'b0;\n        cx_ac_max_code_q[14] <= 16'b0;\n        cx_ac_ptr_q[14]      <= 10'b0;\n        cx_ac_min_code_q[15] <= 16'b0;\n        cx_ac_max_code_q[15] <= 16'b0;\n        cx_ac_ptr_q[15]      <= 10'b0;\n        j_q    <= 8'b0;\n        i_q    <= 4'b0;\n        code_q <= 16'b0;\n    end\n    else if (idx_q < 12'd16 || idx_q == 12'hFFF)\n    begin\n        j_q    <= 8'b0;\n        i_q    <= 4'b0;\n        code_q <= 16'b0;\n    end\n    else if (cfg_valid_i && cfg_accept_o)\n    begin\n        if (j_q == 8'b0)\n        begin\n            case (cfg_table_q)\n            DHT_TABLE_Y_DC:\n            begin\n                y_dc_min_code_q[i_q] <= code_q;\n                y_dc_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};\n                y_dc_ptr_q[i_q]      <= next_ptr_q;\n            end\n            DHT_TABLE_Y_AC:\n            begin\n                y_ac_min_code_q[i_q] <= code_q;\n                y_ac_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};\n                y_ac_ptr_q[i_q]      <= next_ptr_q;\n            end\n            DHT_TABLE_CX_DC:\n            begin\n                cx_dc_min_code_q[i_q] <= code_q;\n                cx_dc_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};\n                cx_dc_ptr_q[i_q]      <= next_ptr_q;\n            end\n            default:\n            begin\n                cx_ac_min_code_q[i_q] <= code_q;\n                cx_ac_max_code_q[i_q] <= code_q + {8'b0, num_entries_q[i_q]};\n                cx_ac_ptr_q[i_q]      <= next_ptr_q;\n            end\n            endcase\n        end\n\n        if ((j_q + 8'd1) == num_entries_q[i_q])\n        begin\n            j_q <= 8'b0;\n            i_q <= i_q + 4'd1;\n            code_q <= (code_q + 16'd1) << 1;\n        end\n        else\n        begin\n            code_q <= code_q + 16'd1;\n            j_q    <= j_q + 8'd1;\n        end\n    end\n    // Increment through empty bit widths\n    else if (cfg_valid_i && !cfg_accept_o)\n    begin\n        i_q    <= i_q + 4'd1;\n        code_q <= code_q << 1;\n    end\n\n    assign cfg_accept_o = has_entries_q[i_q] || (idx_q < 12'd16) || (idx_q == 12'hFFF);\n\n    //-----------------------------------------------------------------\n    // Code table write pointer\n    //-----------------------------------------------------------------\n    wire alloc_entry_w = cfg_valid_i && cfg_accept_o && (idx_q >= 12'd16 && idx_q != 12'hFFF);    \n\n    always @ (posedge clk_i )\n    if (rst_i)\n        next_ptr_q <= 10'b0;\n    else if (alloc_entry_w)\n        next_ptr_q <= next_ptr_q + 10'd1;\n\n    //-----------------------------------------------------------------\n    // Lookup: Match shortest bit sequence\n    //-----------------------------------------------------------------\n\n    reg [3:0] y_dc_width_r;\n    always @ *\n    begin\n        y_dc_width_r = 4'b0;\n\n        if ({15'b0, lookup_input_i[15]} < y_dc_max_code_q[0])\n            y_dc_width_r = 4'd0;\n        else if ({14'b0, lookup_input_i[15:14]} < y_dc_max_code_q[1])\n            y_dc_width_r = 4'd1;\n        else if ({13'b0, lookup_input_i[15:13]} < y_dc_max_code_q[2])\n            y_dc_width_r = 4'd2;\n        else if ({12'b0, lookup_input_i[15:12]} < y_dc_max_code_q[3])\n            y_dc_width_r = 4'd3;\n        else if ({11'b0, lookup_input_i[15:11]} < y_dc_max_code_q[4])\n            y_dc_width_r = 4'd4;\n        else if ({10'b0, lookup_input_i[15:10]} < y_dc_max_code_q[5])\n            y_dc_width_r = 4'd5;\n        else if ({9'b0, lookup_input_i[15:9]} < y_dc_max_code_q[6])\n            y_dc_width_r = 4'd6;\n        else if ({8'b0, lookup_input_i[15:8]} < y_dc_max_code_q[7])\n            y_dc_width_r = 4'd7;\n        else if ({7'b0, lookup_input_i[15:7]} < y_dc_max_code_q[8])\n            y_dc_width_r = 4'd8;\n        else if ({6'b0, lookup_input_i[15:6]} < y_dc_max_code_q[9])\n            y_dc_width_r = 4'd9;\n        else if ({5'b0, lookup_input_i[15:5]} < y_dc_max_code_q[10])\n            y_dc_width_r = 4'd10;\n        else if ({4'b0, lookup_input_i[15:4]} < y_dc_max_code_q[11])\n            y_dc_width_r = 4'd11;\n        else if ({3'b0, lookup_input_i[15:3]} < y_dc_max_code_q[12])\n            y_dc_width_r = 4'd12;\n        else if ({2'b0, lookup_input_i[15:2]} < y_dc_max_code_q[13])\n            y_dc_width_r = 4'd13;\n        else if ({1'b0, lookup_input_i[15:1]} < y_dc_max_code_q[14])\n            y_dc_width_r = 4'd14;\n        else\n            y_dc_width_r = 4'd15;\n    end\n\n    reg [3:0] y_ac_width_r;\n    always @ *\n    begin\n        y_ac_width_r = 4'b0;\n\n        if ({15'b0, lookup_input_i[15]} < y_ac_max_code_q[0])\n            y_ac_width_r = 4'd0;\n        else if ({14'b0, lookup_input_i[15:14]} < y_ac_max_code_q[1])\n            y_ac_width_r = 4'd1;\n        else if ({13'b0, lookup_input_i[15:13]} < y_ac_max_code_q[2])\n            y_ac_width_r = 4'd2;\n        else if ({12'b0, lookup_input_i[15:12]} < y_ac_max_code_q[3])\n            y_ac_width_r = 4'd3;\n        else if ({11'b0, lookup_input_i[15:11]} < y_ac_max_code_q[4])\n            y_ac_width_r = 4'd4;\n        else if ({10'b0, lookup_input_i[15:10]} < y_ac_max_code_q[5])\n            y_ac_width_r = 4'd5;\n        else if ({9'b0, lookup_input_i[15:9]} < y_ac_max_code_q[6])\n            y_ac_width_r = 4'd6;\n        else if ({8'b0, lookup_input_i[15:8]} < y_ac_max_code_q[7])\n            y_ac_width_r = 4'd7;\n        else if ({7'b0, lookup_input_i[15:7]} < y_ac_max_code_q[8])\n            y_ac_width_r = 4'd8;\n        else if ({6'b0, lookup_input_i[15:6]} < y_ac_max_code_q[9])\n            y_ac_width_r = 4'd9;\n        else if ({5'b0, lookup_input_i[15:5]} < y_ac_max_code_q[10])\n            y_ac_width_r = 4'd10;\n        else if ({4'b0, lookup_input_i[15:4]} < y_ac_max_code_q[11])\n            y_ac_width_r = 4'd11;\n        else if ({3'b0, lookup_input_i[15:3]} < y_ac_max_code_q[12])\n            y_ac_width_r = 4'd12;\n        else if ({2'b0, lookup_input_i[15:2]} < y_ac_max_code_q[13])\n            y_ac_width_r = 4'd13;\n        else if ({1'b0, lookup_input_i[15:1]} < y_ac_max_code_q[14])\n            y_ac_width_r = 4'd14;\n        else\n            y_ac_width_r = 4'd15;\n    end\n\n    reg [3:0] cx_dc_width_r;\n    always @ *\n    begin\n        cx_dc_width_r = 4'b0;\n\n        if ({15'b0, lookup_input_i[15]} < cx_dc_max_code_q[0])\n            cx_dc_width_r = 4'd0;\n        else if ({14'b0, lookup_input_i[15:14]} < cx_dc_max_code_q[1])\n            cx_dc_width_r = 4'd1;\n        else if ({13'b0, lookup_input_i[15:13]} < cx_dc_max_code_q[2])\n            cx_dc_width_r = 4'd2;\n        else if ({12'b0, lookup_input_i[15:12]} < cx_dc_max_code_q[3])\n            cx_dc_width_r = 4'd3;\n        else if ({11'b0, lookup_input_i[15:11]} < cx_dc_max_code_q[4])\n            cx_dc_width_r = 4'd4;\n        else if ({10'b0, lookup_input_i[15:10]} < cx_dc_max_code_q[5])\n            cx_dc_width_r = 4'd5;\n        else if ({9'b0, lookup_input_i[15:9]} < cx_dc_max_code_q[6])\n            cx_dc_width_r = 4'd6;\n        else if ({8'b0, lookup_input_i[15:8]} < cx_dc_max_code_q[7])\n            cx_dc_width_r = 4'd7;\n        else if ({7'b0, lookup_input_i[15:7]} < cx_dc_max_code_q[8])\n            cx_dc_width_r = 4'd8;\n        else if ({6'b0, lookup_input_i[15:6]} < cx_dc_max_code_q[9])\n            cx_dc_width_r = 4'd9;\n        else if ({5'b0, lookup_input_i[15:5]} < cx_dc_max_code_q[10])\n            cx_dc_width_r = 4'd10;\n        else if ({4'b0, lookup_input_i[15:4]} < cx_dc_max_code_q[11])\n            cx_dc_width_r = 4'd11;\n        else if ({3'b0, lookup_input_i[15:3]} < cx_dc_max_code_q[12])\n            cx_dc_width_r = 4'd12;\n        else if ({2'b0, lookup_input_i[15:2]} < cx_dc_max_code_q[13])\n            cx_dc_width_r = 4'd13;\n        else if ({1'b0, lookup_input_i[15:1]} < cx_dc_max_code_q[14])\n            cx_dc_width_r = 4'd14;\n        else\n            cx_dc_width_r = 4'd15;\n    end\n\n    reg [3:0] cx_ac_width_r;\n    always @ *\n    begin\n        cx_ac_width_r = 4'b0;\n\n        if ({15'b0, lookup_input_i[15]} < cx_ac_max_code_q[0])\n            cx_ac_width_r = 4'd0;\n        else if ({14'b0, lookup_input_i[15:14]} < cx_ac_max_code_q[1])\n            cx_ac_width_r = 4'd1;\n        else if ({13'b0, lookup_input_i[15:13]} < cx_ac_max_code_q[2])\n            cx_ac_width_r = 4'd2;\n        else if ({12'b0, lookup_input_i[15:12]} < cx_ac_max_code_q[3])\n            cx_ac_width_r = 4'd3;\n        else if ({11'b0, lookup_input_i[15:11]} < cx_ac_max_code_q[4])\n            cx_ac_width_r = 4'd4;\n        else if ({10'b0, lookup_input_i[15:10]} < cx_ac_max_code_q[5])\n            cx_ac_width_r = 4'd5;\n        else if ({9'b0, lookup_input_i[15:9]} < cx_ac_max_code_q[6])\n            cx_ac_width_r = 4'd6;\n        else if ({8'b0, lookup_input_i[15:8]} < cx_ac_max_code_q[7])\n            cx_ac_width_r = 4'd7;\n        else if ({7'b0, lookup_input_i[15:7]} < cx_ac_max_code_q[8])\n            cx_ac_width_r = 4'd8;\n        else if ({6'b0, lookup_input_i[15:6]} < cx_ac_max_code_q[9])\n            cx_ac_width_r = 4'd9;\n        else if ({5'b0, lookup_input_i[15:5]} < cx_ac_max_code_q[10])\n            cx_ac_width_r = 4'd10;\n        else if ({4'b0, lookup_input_i[15:4]} < cx_ac_max_code_q[11])\n            cx_ac_width_r = 4'd11;\n        else if ({3'b0, lookup_input_i[15:3]} < cx_ac_max_code_q[12])\n            cx_ac_width_r = 4'd12;\n        else if ({2'b0, lookup_input_i[15:2]} < cx_ac_max_code_q[13])\n            cx_ac_width_r = 4'd13;\n        else if ({1'b0, lookup_input_i[15:1]} < cx_ac_max_code_q[14])\n            cx_ac_width_r = 4'd14;\n        else\n            cx_ac_width_r = 4'd15;\n    end\n\n    //-----------------------------------------------------------------\n    // Lookup: Register lookup width\n    //-----------------------------------------------------------------\n    reg [3:0]  lookup_width_r;\n\n    always @ *\n    begin\n        lookup_width_r = 4'b0;\n\n        case (lookup_table_i)\n        2'd0:    lookup_width_r = y_dc_width_r;\n        2'd1:    lookup_width_r = y_ac_width_r;\n        2'd2:    lookup_width_r = cx_dc_width_r;\n        default: lookup_width_r = cx_ac_width_r;\n        endcase\n    end\n\n    reg [3:0]  lookup_width_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_width_q <= 4'b0;\n    else\n        lookup_width_q <= lookup_width_r;\n\n    reg [1:0]  lookup_table_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_table_q <= 2'b0;\n    else\n        lookup_table_q <= lookup_table_i;\n\n    //-----------------------------------------------------------------\n    // Lookup: Create RAM lookup address\n    //-----------------------------------------------------------------\n    reg [15:0] lookup_addr_r;\n    reg [15:0] input_code_r;\n\n    always @ *\n    begin\n        lookup_addr_r  = 16'b0;\n        input_code_r   = 16'b0;\n\n        case (lookup_table_q)\n        2'd0:\n        begin\n            input_code_r   = lookup_input_i >> (15 - lookup_width_q);\n            lookup_addr_r  = input_code_r - y_dc_min_code_q[lookup_width_q] + {6'b0, y_dc_ptr_q[lookup_width_q]};\n        end\n        2'd1:\n        begin\n            input_code_r   = lookup_input_i >> (15 - lookup_width_q);\n            lookup_addr_r  = input_code_r - y_ac_min_code_q[lookup_width_q] + {6'b0, y_ac_ptr_q[lookup_width_q]};\n        end\n        2'd2:\n        begin\n            input_code_r   = lookup_input_i >> (15 - lookup_width_q);\n            lookup_addr_r  = input_code_r - cx_dc_min_code_q[lookup_width_q] + {6'b0, cx_dc_ptr_q[lookup_width_q]};\n        end\n        default:\n        begin\n            input_code_r   = lookup_input_i >> (15 - lookup_width_q);\n            lookup_addr_r  = input_code_r - cx_ac_min_code_q[lookup_width_q] + {6'b0, cx_ac_ptr_q[lookup_width_q]};\n        end\n        endcase\n    end\n\n    //-----------------------------------------------------------------\n    // RAM for storing Huffman decode values\n    //-----------------------------------------------------------------\n    // LUT for decode values\n    reg [7:0]  ram[0:1023];\n\n    always @ (posedge clk_i)\n    begin\n        if (alloc_entry_w)\n            ram[next_ptr_q] <= cfg_data_i;\n    end\n\n    reg [7:0] data_value_q;\n\n    always @ (posedge clk_i)\n    begin\n        data_value_q <= ram[lookup_addr_r[9:0]];\n    end\n\n    reg lookup_valid_q;\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_valid_q <= 1'b0;\n    else\n        lookup_valid_q <= lookup_req_i;\n\n    reg lookup_valid2_q;\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_valid2_q <= 1'b0;\n    else\n        lookup_valid2_q <= lookup_valid_q;\n\n    reg [4:0]  lookup_width2_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_width2_q <= 5'b0;\n    else\n        lookup_width2_q <= {1'b0, lookup_width_q} + 5'd1;\n\n    assign lookup_valid_o = lookup_valid2_q;\n    assign lookup_value_o = data_value_q;\n    assign lookup_width_o = lookup_width2_q;\nend\n//---------------------------------------------------------------------\n// Support only standard huffman tables (from JPEG spec).\n//---------------------------------------------------------------------\nelse\nbegin\n    //-----------------------------------------------------------------\n    // Y DC Table (standard)\n    //-----------------------------------------------------------------\n    wire [7:0] y_dc_value_w;\n    wire [4:0] y_dc_width_w;\n\n    jpeg_dht_std_y_dc\n    u_fixed_y_dc\n    (\n         .lookup_input_i(lookup_input_i)\n        ,.lookup_value_o(y_dc_value_w)\n        ,.lookup_width_o(y_dc_width_w)\n    );\n\n    //-----------------------------------------------------------------\n    // Y AC Table (standard)\n    //-----------------------------------------------------------------\n    wire [7:0] y_ac_value_w;\n    wire [4:0] y_ac_width_w;\n\n    jpeg_dht_std_y_ac\n    u_fixed_y_ac\n    (\n         .lookup_input_i(lookup_input_i)\n        ,.lookup_value_o(y_ac_value_w)\n        ,.lookup_width_o(y_ac_width_w)\n    );\n\n    //-----------------------------------------------------------------\n    // Cx DC Table (standard)\n    //-----------------------------------------------------------------\n    wire [7:0] cx_dc_value_w;\n    wire [4:0] cx_dc_width_w;\n\n    jpeg_dht_std_cx_dc\n    u_fixed_cx_dc\n    (\n         .lookup_input_i(lookup_input_i)\n        ,.lookup_value_o(cx_dc_value_w)\n        ,.lookup_width_o(cx_dc_width_w)\n    );\n\n    //-----------------------------------------------------------------\n    // Cx AC Table (standard)\n    //-----------------------------------------------------------------\n    wire [7:0] cx_ac_value_w;\n    wire [4:0] cx_ac_width_w;\n\n    jpeg_dht_std_cx_ac\n    u_fixed_cx_ac\n    (\n         .lookup_input_i(lookup_input_i)\n        ,.lookup_value_o(cx_ac_value_w)\n        ,.lookup_width_o(cx_ac_width_w)\n    );\n\n    //-----------------------------------------------------------------\n    // Lookup\n    //-----------------------------------------------------------------\n    reg lookup_valid_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_valid_q <= 1'b0;\n    else\n        lookup_valid_q <= lookup_req_i;\n\n    assign lookup_valid_o = lookup_valid_q;\n\n    reg [7:0] lookup_value_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_value_q <= 8'b0;\n    else\n    begin\n        case (lookup_table_i)\n        2'd0: lookup_value_q <= y_dc_value_w;\n        2'd1: lookup_value_q <= y_ac_value_w;\n        2'd2: lookup_value_q <= cx_dc_value_w;\n        2'd3: lookup_value_q <= cx_ac_value_w;\n        endcase\n    end\n\n    assign lookup_value_o = lookup_value_q;\n\n    reg [4:0] lookup_width_q;\n\n    always @ (posedge clk_i )\n    if (rst_i)\n        lookup_width_q <= 5'b0;\n    else\n    begin\n        case (lookup_table_i)\n        2'd0: lookup_width_q <= y_dc_width_w;\n        2'd1: lookup_width_q <= y_ac_width_w;\n        2'd2: lookup_width_q <= cx_dc_width_w;\n        2'd3: lookup_width_q <= cx_ac_width_w;\n        endcase\n    end\n\n    assign lookup_width_o = lookup_width_q;\n\n    assign cfg_accept_o = 1'b1;\nend\nendgenerate\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_dht_std_cx_ac.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\nmodule jpeg_dht_std_cx_ac\n(\n     input  [ 15:0]  lookup_input_i\n    ,output [  4:0]  lookup_width_o\n    ,output [  7:0]  lookup_value_o\n);\n\n//-----------------------------------------------------------------\n// Cx AC Table (standard)\n//-----------------------------------------------------------------\nreg [7:0] cx_ac_value_r;\nreg [4:0] cx_ac_width_r;\n\nalways @ *\nbegin\n    cx_ac_value_r = 8'b0;\n    cx_ac_width_r = 5'b0;\n\n    if (lookup_input_i[15:14] == 2'h0)\n    begin\n         cx_ac_value_r = 8'h00;\n         cx_ac_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:14] == 2'h1)\n    begin\n         cx_ac_value_r = 8'h01;\n         cx_ac_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:13] == 3'h4)\n    begin\n         cx_ac_value_r = 8'h02;\n         cx_ac_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:12] == 4'ha)\n    begin\n         cx_ac_value_r = 8'h03;\n         cx_ac_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:12] == 4'hb)\n    begin\n         cx_ac_value_r = 8'h11;\n         cx_ac_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:11] == 5'h18)\n    begin\n         cx_ac_value_r = 8'h04;\n         cx_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:11] == 5'h19)\n    begin\n         cx_ac_value_r = 8'h05;\n         cx_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:11] == 5'h1a)\n    begin\n         cx_ac_value_r = 8'h21;\n         cx_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:11] == 5'h1b)\n    begin\n         cx_ac_value_r = 8'h31;\n         cx_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:10] == 6'h38)\n    begin\n         cx_ac_value_r = 8'h06;\n         cx_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:10] == 6'h39)\n    begin\n         cx_ac_value_r = 8'h12;\n         cx_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:10] == 6'h3a)\n    begin\n         cx_ac_value_r = 8'h41;\n         cx_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:10] == 6'h3b)\n    begin\n         cx_ac_value_r = 8'h51;\n         cx_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:9] == 7'h78)\n    begin\n         cx_ac_value_r = 8'h07;\n         cx_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:9] == 7'h79)\n    begin\n         cx_ac_value_r = 8'h61;\n         cx_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:9] == 7'h7a)\n    begin\n         cx_ac_value_r = 8'h71;\n         cx_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:8] == 8'hf6)\n    begin\n         cx_ac_value_r = 8'h13;\n         cx_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:8] == 8'hf7)\n    begin\n         cx_ac_value_r = 8'h22;\n         cx_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:8] == 8'hf8)\n    begin\n         cx_ac_value_r = 8'h32;\n         cx_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:8] == 8'hf9)\n    begin\n         cx_ac_value_r = 8'h81;\n         cx_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f4)\n    begin\n         cx_ac_value_r = 8'h08;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f5)\n    begin\n         cx_ac_value_r = 8'h14;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f6)\n    begin\n         cx_ac_value_r = 8'h42;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f7)\n    begin\n         cx_ac_value_r = 8'h91;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f8)\n    begin\n         cx_ac_value_r = 8'ha1;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f9)\n    begin\n         cx_ac_value_r = 8'hb1;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1fa)\n    begin\n         cx_ac_value_r = 8'hc1;\n         cx_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f6)\n    begin\n         cx_ac_value_r = 8'h09;\n         cx_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f7)\n    begin\n         cx_ac_value_r = 8'h23;\n         cx_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f8)\n    begin\n         cx_ac_value_r = 8'h33;\n         cx_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f9)\n    begin\n         cx_ac_value_r = 8'h52;\n         cx_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3fa)\n    begin\n         cx_ac_value_r = 8'hf0;\n         cx_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f6)\n    begin\n         cx_ac_value_r = 8'h15;\n         cx_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f7)\n    begin\n         cx_ac_value_r = 8'h62;\n         cx_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f8)\n    begin\n         cx_ac_value_r = 8'h72;\n         cx_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f9)\n    begin\n         cx_ac_value_r = 8'hd1;\n         cx_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:4] == 12'hff4)\n    begin\n         cx_ac_value_r = 8'h0a;\n         cx_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff5)\n    begin\n         cx_ac_value_r = 8'h16;\n         cx_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff6)\n    begin\n         cx_ac_value_r = 8'h24;\n         cx_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff7)\n    begin\n         cx_ac_value_r = 8'h34;\n         cx_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:2] == 14'h3fe0)\n    begin\n         cx_ac_value_r = 8'he1;\n         cx_ac_width_r = 5'd14;\n    end\n    else if (lookup_input_i[15:1] == 15'h7fc2)\n    begin\n         cx_ac_value_r = 8'h25;\n         cx_ac_width_r = 5'd15;\n    end\n    else if (lookup_input_i[15:1] == 15'h7fc3)\n    begin\n         cx_ac_value_r = 8'hf1;\n         cx_ac_width_r = 5'd15;\n    end\n    else if (lookup_input_i[15:0] == 16'hff88)\n    begin\n         cx_ac_value_r = 8'h17;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff89)\n    begin\n         cx_ac_value_r = 8'h18;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8a)\n    begin\n         cx_ac_value_r = 8'h19;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8b)\n    begin\n         cx_ac_value_r = 8'h1a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8c)\n    begin\n         cx_ac_value_r = 8'h26;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8d)\n    begin\n         cx_ac_value_r = 8'h27;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8e)\n    begin\n         cx_ac_value_r = 8'h28;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8f)\n    begin\n         cx_ac_value_r = 8'h29;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff90)\n    begin\n         cx_ac_value_r = 8'h2a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff91)\n    begin\n         cx_ac_value_r = 8'h35;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff92)\n    begin\n         cx_ac_value_r = 8'h36;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff93)\n    begin\n         cx_ac_value_r = 8'h37;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff94)\n    begin\n         cx_ac_value_r = 8'h38;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff95)\n    begin\n         cx_ac_value_r = 8'h39;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff96)\n    begin\n         cx_ac_value_r = 8'h3a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff97)\n    begin\n         cx_ac_value_r = 8'h43;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff98)\n    begin\n         cx_ac_value_r = 8'h44;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff99)\n    begin\n         cx_ac_value_r = 8'h45;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9a)\n    begin\n         cx_ac_value_r = 8'h46;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9b)\n    begin\n         cx_ac_value_r = 8'h47;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9c)\n    begin\n         cx_ac_value_r = 8'h48;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9d)\n    begin\n         cx_ac_value_r = 8'h49;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9e)\n    begin\n         cx_ac_value_r = 8'h4a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9f)\n    begin\n         cx_ac_value_r = 8'h53;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa0)\n    begin\n         cx_ac_value_r = 8'h54;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa1)\n    begin\n         cx_ac_value_r = 8'h55;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa2)\n    begin\n         cx_ac_value_r = 8'h56;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa3)\n    begin\n         cx_ac_value_r = 8'h57;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa4)\n    begin\n         cx_ac_value_r = 8'h58;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa5)\n    begin\n         cx_ac_value_r = 8'h59;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa6)\n    begin\n         cx_ac_value_r = 8'h5a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa7)\n    begin\n         cx_ac_value_r = 8'h63;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa8)\n    begin\n         cx_ac_value_r = 8'h64;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa9)\n    begin\n         cx_ac_value_r = 8'h65;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffaa)\n    begin\n         cx_ac_value_r = 8'h66;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffab)\n    begin\n         cx_ac_value_r = 8'h67;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffac)\n    begin\n         cx_ac_value_r = 8'h68;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffad)\n    begin\n         cx_ac_value_r = 8'h69;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffae)\n    begin\n         cx_ac_value_r = 8'h6a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffaf)\n    begin\n         cx_ac_value_r = 8'h73;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb0)\n    begin\n         cx_ac_value_r = 8'h74;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb1)\n    begin\n         cx_ac_value_r = 8'h75;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb2)\n    begin\n         cx_ac_value_r = 8'h76;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb3)\n    begin\n         cx_ac_value_r = 8'h77;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb4)\n    begin\n         cx_ac_value_r = 8'h78;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb5)\n    begin\n         cx_ac_value_r = 8'h79;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb6)\n    begin\n         cx_ac_value_r = 8'h7a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb7)\n    begin\n         cx_ac_value_r = 8'h82;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb8)\n    begin\n         cx_ac_value_r = 8'h83;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb9)\n    begin\n         cx_ac_value_r = 8'h84;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffba)\n    begin\n         cx_ac_value_r = 8'h85;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbb)\n    begin\n         cx_ac_value_r = 8'h86;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbc)\n    begin\n         cx_ac_value_r = 8'h87;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbd)\n    begin\n         cx_ac_value_r = 8'h88;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbe)\n    begin\n         cx_ac_value_r = 8'h89;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbf)\n    begin\n         cx_ac_value_r = 8'h8a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc0)\n    begin\n         cx_ac_value_r = 8'h92;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc1)\n    begin\n         cx_ac_value_r = 8'h93;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc2)\n    begin\n         cx_ac_value_r = 8'h94;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc3)\n    begin\n         cx_ac_value_r = 8'h95;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc4)\n    begin\n         cx_ac_value_r = 8'h96;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc5)\n    begin\n         cx_ac_value_r = 8'h97;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc6)\n    begin\n         cx_ac_value_r = 8'h98;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc7)\n    begin\n         cx_ac_value_r = 8'h99;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc8)\n    begin\n         cx_ac_value_r = 8'h9a;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc9)\n    begin\n         cx_ac_value_r = 8'ha2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffca)\n    begin\n         cx_ac_value_r = 8'ha3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcb)\n    begin\n         cx_ac_value_r = 8'ha4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcc)\n    begin\n         cx_ac_value_r = 8'ha5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcd)\n    begin\n         cx_ac_value_r = 8'ha6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffce)\n    begin\n         cx_ac_value_r = 8'ha7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcf)\n    begin\n         cx_ac_value_r = 8'ha8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd0)\n    begin\n         cx_ac_value_r = 8'ha9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd1)\n    begin\n         cx_ac_value_r = 8'haa;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd2)\n    begin\n         cx_ac_value_r = 8'hb2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd3)\n    begin\n         cx_ac_value_r = 8'hb3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd4)\n    begin\n         cx_ac_value_r = 8'hb4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd5)\n    begin\n         cx_ac_value_r = 8'hb5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd6)\n    begin\n         cx_ac_value_r = 8'hb6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd7)\n    begin\n         cx_ac_value_r = 8'hb7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd8)\n    begin\n         cx_ac_value_r = 8'hb8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd9)\n    begin\n         cx_ac_value_r = 8'hb9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffda)\n    begin\n         cx_ac_value_r = 8'hba;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdb)\n    begin\n         cx_ac_value_r = 8'hc2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdc)\n    begin\n         cx_ac_value_r = 8'hc3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdd)\n    begin\n         cx_ac_value_r = 8'hc4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffde)\n    begin\n         cx_ac_value_r = 8'hc5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdf)\n    begin\n         cx_ac_value_r = 8'hc6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe0)\n    begin\n         cx_ac_value_r = 8'hc7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe1)\n    begin\n         cx_ac_value_r = 8'hc8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe2)\n    begin\n         cx_ac_value_r = 8'hc9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe3)\n    begin\n         cx_ac_value_r = 8'hca;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe4)\n    begin\n         cx_ac_value_r = 8'hd2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe5)\n    begin\n         cx_ac_value_r = 8'hd3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe6)\n    begin\n         cx_ac_value_r = 8'hd4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe7)\n    begin\n         cx_ac_value_r = 8'hd5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe8)\n    begin\n         cx_ac_value_r = 8'hd6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe9)\n    begin\n         cx_ac_value_r = 8'hd7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffea)\n    begin\n         cx_ac_value_r = 8'hd8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffeb)\n    begin\n         cx_ac_value_r = 8'hd9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffec)\n    begin\n         cx_ac_value_r = 8'hda;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffed)\n    begin\n         cx_ac_value_r = 8'he2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffee)\n    begin\n         cx_ac_value_r = 8'he3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffef)\n    begin\n         cx_ac_value_r = 8'he4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff0)\n    begin\n         cx_ac_value_r = 8'he5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff1)\n    begin\n         cx_ac_value_r = 8'he6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff2)\n    begin\n         cx_ac_value_r = 8'he7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff3)\n    begin\n         cx_ac_value_r = 8'he8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff4)\n    begin\n         cx_ac_value_r = 8'he9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff5)\n    begin\n         cx_ac_value_r = 8'hea;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff6)\n    begin\n         cx_ac_value_r = 8'hf2;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff7)\n    begin\n         cx_ac_value_r = 8'hf3;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff8)\n    begin\n         cx_ac_value_r = 8'hf4;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff9)\n    begin\n         cx_ac_value_r = 8'hf5;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffa)\n    begin\n         cx_ac_value_r = 8'hf6;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffb)\n    begin\n         cx_ac_value_r = 8'hf7;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffc)\n    begin\n         cx_ac_value_r = 8'hf8;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffd)\n    begin\n         cx_ac_value_r = 8'hf9;\n         cx_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffe)\n    begin\n         cx_ac_value_r = 8'hfa;\n         cx_ac_width_r = 5'd16;\n    end\nend\n\nassign lookup_width_o = cx_ac_width_r;\nassign lookup_value_o = cx_ac_value_r;\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_dht_std_cx_dc.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\nmodule jpeg_dht_std_cx_dc\n(\n     input  [ 15:0]  lookup_input_i\n    ,output [  4:0]  lookup_width_o\n    ,output [  7:0]  lookup_value_o\n);\n\n//-----------------------------------------------------------------\n// Cx DC Table (standard)\n//-----------------------------------------------------------------\nreg [7:0] cx_dc_value_r;\nreg [4:0] cx_dc_width_r;\n\nalways @ *\nbegin\n    cx_dc_value_r = 8'b0;\n    cx_dc_width_r = 5'b0;\n\n    if (lookup_input_i[15:14] == 2'h0)\n    begin\n         cx_dc_value_r = 8'h00;\n         cx_dc_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:14] == 2'h1)\n    begin\n         cx_dc_value_r = 8'h01;\n         cx_dc_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:14] == 2'h2)\n    begin\n         cx_dc_value_r = 8'h02;\n         cx_dc_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:13] == 3'h6)\n    begin\n         cx_dc_value_r = 8'h03;\n         cx_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:12] == 4'he)\n    begin\n         cx_dc_value_r = 8'h04;\n         cx_dc_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:11] == 5'h1e)\n    begin\n         cx_dc_value_r = 8'h05;\n         cx_dc_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:10] == 6'h3e)\n    begin\n         cx_dc_value_r = 8'h06;\n         cx_dc_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:9] == 7'h7e)\n    begin\n         cx_dc_value_r = 8'h07;\n         cx_dc_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:8] == 8'hfe)\n    begin\n         cx_dc_value_r = 8'h08;\n         cx_dc_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:7] == 9'h1fe)\n    begin\n         cx_dc_value_r = 8'h09;\n         cx_dc_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:6] == 10'h3fe)\n    begin\n         cx_dc_value_r = 8'h0a;\n         cx_dc_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:5] == 11'h7fe)\n    begin\n         cx_dc_value_r = 8'h0b;\n         cx_dc_width_r = 5'd11;\n    end\nend\n\nassign lookup_width_o = cx_dc_width_r;\nassign lookup_value_o = cx_dc_value_r;\n\nendmodule\n\n"
  },
  {
    "path": "src_v/jpeg_dht_std_y_ac.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\nmodule jpeg_dht_std_y_ac\n(\n     input  [ 15:0]  lookup_input_i\n    ,output [  4:0]  lookup_width_o\n    ,output [  7:0]  lookup_value_o\n);\n\n//-----------------------------------------------------------------\n// Y AC Table (standard)\n//-----------------------------------------------------------------\nreg [7:0] y_ac_value_r;\nreg [4:0] y_ac_width_r;\n\nalways @ *\nbegin\n    y_ac_value_r = 8'b0;\n    y_ac_width_r = 5'b0;\n\n    if (lookup_input_i[15:14] == 2'h0)\n    begin\n         y_ac_value_r = 8'h01;\n         y_ac_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:14] == 2'h1)\n    begin\n         y_ac_value_r = 8'h02;\n         y_ac_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:13] == 3'h4)\n    begin\n         y_ac_value_r = 8'h03;\n         y_ac_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:12] == 4'ha)\n    begin\n         y_ac_value_r = 8'h00;\n         y_ac_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:12] == 4'hb)\n    begin\n         y_ac_value_r = 8'h04;\n         y_ac_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:12] == 4'hc)\n    begin\n         y_ac_value_r = 8'h11;\n         y_ac_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:11] == 5'h1a)\n    begin\n         y_ac_value_r = 8'h05;\n         y_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:11] == 5'h1b)\n    begin\n         y_ac_value_r = 8'h12;\n         y_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:11] == 5'h1c)\n    begin\n         y_ac_value_r = 8'h21;\n         y_ac_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:10] == 6'h3a)\n    begin\n         y_ac_value_r = 8'h31;\n         y_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:10] == 6'h3b)\n    begin\n         y_ac_value_r = 8'h41;\n         y_ac_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:9] == 7'h78)\n    begin\n         y_ac_value_r = 8'h06;\n         y_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:9] == 7'h79)\n    begin\n         y_ac_value_r = 8'h13;\n         y_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:9] == 7'h7a)\n    begin\n         y_ac_value_r = 8'h51;\n         y_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:9] == 7'h7b)\n    begin\n         y_ac_value_r = 8'h61;\n         y_ac_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:8] == 8'hf8)\n    begin\n         y_ac_value_r = 8'h07;\n         y_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:8] == 8'hf9)\n    begin\n         y_ac_value_r = 8'h22;\n         y_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:8] == 8'hfa)\n    begin\n         y_ac_value_r = 8'h71;\n         y_ac_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f6)\n    begin\n         y_ac_value_r = 8'h14;\n         y_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f7)\n    begin\n         y_ac_value_r = 8'h32;\n         y_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f8)\n    begin\n         y_ac_value_r = 8'h81;\n         y_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1f9)\n    begin\n         y_ac_value_r = 8'h91;\n         y_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:7] == 9'h1fa)\n    begin\n         y_ac_value_r = 8'ha1;\n         y_ac_width_r = 5'd9;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f6)\n    begin\n         y_ac_value_r = 8'h08;\n         y_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f7)\n    begin\n         y_ac_value_r = 8'h23;\n         y_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f8)\n    begin\n         y_ac_value_r = 8'h42;\n         y_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3f9)\n    begin\n         y_ac_value_r = 8'hb1;\n         y_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:6] == 10'h3fa)\n    begin\n         y_ac_value_r = 8'hc1;\n         y_ac_width_r = 5'd10;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f6)\n    begin\n         y_ac_value_r = 8'h15;\n         y_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f7)\n    begin\n         y_ac_value_r = 8'h52;\n         y_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f8)\n    begin\n         y_ac_value_r = 8'hd1;\n         y_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:5] == 11'h7f9)\n    begin\n         y_ac_value_r = 8'hf0;\n         y_ac_width_r = 5'd11;\n    end\n    else if (lookup_input_i[15:4] == 12'hff4)\n    begin\n         y_ac_value_r = 8'h24;\n         y_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff5)\n    begin\n         y_ac_value_r = 8'h33;\n         y_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff6)\n    begin\n         y_ac_value_r = 8'h62;\n         y_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:4] == 12'hff7)\n    begin\n         y_ac_value_r = 8'h72;\n         y_ac_width_r = 5'd12;\n    end\n    else if (lookup_input_i[15:1] == 15'h7fc0)\n    begin\n         y_ac_value_r = 8'h82;\n         y_ac_width_r = 5'd15;\n    end\n    else if (lookup_input_i[15:0] == 16'hff82)\n    begin\n         y_ac_value_r = 8'h09;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff83)\n    begin\n         y_ac_value_r = 8'h0a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff84)\n    begin\n         y_ac_value_r = 8'h16;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff85)\n    begin\n         y_ac_value_r = 8'h17;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff86)\n    begin\n         y_ac_value_r = 8'h18;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff87)\n    begin\n         y_ac_value_r = 8'h19;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff88)\n    begin\n         y_ac_value_r = 8'h1a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff89)\n    begin\n         y_ac_value_r = 8'h25;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8a)\n    begin\n         y_ac_value_r = 8'h26;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8b)\n    begin\n         y_ac_value_r = 8'h27;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8c)\n    begin\n         y_ac_value_r = 8'h28;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8d)\n    begin\n         y_ac_value_r = 8'h29;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8e)\n    begin\n         y_ac_value_r = 8'h2a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff8f)\n    begin\n         y_ac_value_r = 8'h34;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff90)\n    begin\n         y_ac_value_r = 8'h35;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff91)\n    begin\n         y_ac_value_r = 8'h36;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff92)\n    begin\n         y_ac_value_r = 8'h37;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff93)\n    begin\n         y_ac_value_r = 8'h38;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff94)\n    begin\n         y_ac_value_r = 8'h39;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff95)\n    begin\n         y_ac_value_r = 8'h3a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff96)\n    begin\n         y_ac_value_r = 8'h43;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff97)\n    begin\n         y_ac_value_r = 8'h44;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff98)\n    begin\n         y_ac_value_r = 8'h45;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff99)\n    begin\n         y_ac_value_r = 8'h46;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9a)\n    begin\n         y_ac_value_r = 8'h47;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9b)\n    begin\n         y_ac_value_r = 8'h48;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9c)\n    begin\n         y_ac_value_r = 8'h49;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9d)\n    begin\n         y_ac_value_r = 8'h4a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9e)\n    begin\n         y_ac_value_r = 8'h53;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hff9f)\n    begin\n         y_ac_value_r = 8'h54;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa0)\n    begin\n         y_ac_value_r = 8'h55;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa1)\n    begin\n         y_ac_value_r = 8'h56;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa2)\n    begin\n         y_ac_value_r = 8'h57;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa3)\n    begin\n         y_ac_value_r = 8'h58;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa4)\n    begin\n         y_ac_value_r = 8'h59;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa5)\n    begin\n         y_ac_value_r = 8'h5a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa6)\n    begin\n         y_ac_value_r = 8'h63;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa7)\n    begin\n         y_ac_value_r = 8'h64;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa8)\n    begin\n         y_ac_value_r = 8'h65;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffa9)\n    begin\n         y_ac_value_r = 8'h66;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffaa)\n    begin\n         y_ac_value_r = 8'h67;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffab)\n    begin\n         y_ac_value_r = 8'h68;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffac)\n    begin\n         y_ac_value_r = 8'h69;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffad)\n    begin\n         y_ac_value_r = 8'h6a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffae)\n    begin\n         y_ac_value_r = 8'h73;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffaf)\n    begin\n         y_ac_value_r = 8'h74;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb0)\n    begin\n         y_ac_value_r = 8'h75;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb1)\n    begin\n         y_ac_value_r = 8'h76;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb2)\n    begin\n         y_ac_value_r = 8'h77;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb3)\n    begin\n         y_ac_value_r = 8'h78;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb4)\n    begin\n         y_ac_value_r = 8'h79;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb5)\n    begin\n         y_ac_value_r = 8'h7a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb6)\n    begin\n         y_ac_value_r = 8'h83;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb7)\n    begin\n         y_ac_value_r = 8'h84;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb8)\n    begin\n         y_ac_value_r = 8'h85;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffb9)\n    begin\n         y_ac_value_r = 8'h86;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffba)\n    begin\n         y_ac_value_r = 8'h87;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbb)\n    begin\n         y_ac_value_r = 8'h88;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbc)\n    begin\n         y_ac_value_r = 8'h89;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbd)\n    begin\n         y_ac_value_r = 8'h8a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbe)\n    begin\n         y_ac_value_r = 8'h92;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffbf)\n    begin\n         y_ac_value_r = 8'h93;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc0)\n    begin\n         y_ac_value_r = 8'h94;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc1)\n    begin\n         y_ac_value_r = 8'h95;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc2)\n    begin\n         y_ac_value_r = 8'h96;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc3)\n    begin\n         y_ac_value_r = 8'h97;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc4)\n    begin\n         y_ac_value_r = 8'h98;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc5)\n    begin\n         y_ac_value_r = 8'h99;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc6)\n    begin\n         y_ac_value_r = 8'h9a;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc7)\n    begin\n         y_ac_value_r = 8'ha2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc8)\n    begin\n         y_ac_value_r = 8'ha3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffc9)\n    begin\n         y_ac_value_r = 8'ha4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffca)\n    begin\n         y_ac_value_r = 8'ha5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcb)\n    begin\n         y_ac_value_r = 8'ha6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcc)\n    begin\n         y_ac_value_r = 8'ha7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcd)\n    begin\n         y_ac_value_r = 8'ha8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffce)\n    begin\n         y_ac_value_r = 8'ha9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffcf)\n    begin\n         y_ac_value_r = 8'haa;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd0)\n    begin\n         y_ac_value_r = 8'hb2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd1)\n    begin\n         y_ac_value_r = 8'hb3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd2)\n    begin\n         y_ac_value_r = 8'hb4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd3)\n    begin\n         y_ac_value_r = 8'hb5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd4)\n    begin\n         y_ac_value_r = 8'hb6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd5)\n    begin\n         y_ac_value_r = 8'hb7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd6)\n    begin\n         y_ac_value_r = 8'hb8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd7)\n    begin\n         y_ac_value_r = 8'hb9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd8)\n    begin\n         y_ac_value_r = 8'hba;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffd9)\n    begin\n         y_ac_value_r = 8'hc2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffda)\n    begin\n         y_ac_value_r = 8'hc3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdb)\n    begin\n         y_ac_value_r = 8'hc4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdc)\n    begin\n         y_ac_value_r = 8'hc5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdd)\n    begin\n         y_ac_value_r = 8'hc6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffde)\n    begin\n         y_ac_value_r = 8'hc7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffdf)\n    begin\n         y_ac_value_r = 8'hc8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe0)\n    begin\n         y_ac_value_r = 8'hc9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe1)\n    begin\n         y_ac_value_r = 8'hca;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe2)\n    begin\n         y_ac_value_r = 8'hd2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe3)\n    begin\n         y_ac_value_r = 8'hd3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe4)\n    begin\n         y_ac_value_r = 8'hd4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe5)\n    begin\n         y_ac_value_r = 8'hd5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe6)\n    begin\n         y_ac_value_r = 8'hd6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe7)\n    begin\n         y_ac_value_r = 8'hd7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe8)\n    begin\n         y_ac_value_r = 8'hd8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffe9)\n    begin\n         y_ac_value_r = 8'hd9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffea)\n    begin\n         y_ac_value_r = 8'hda;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffeb)\n    begin\n         y_ac_value_r = 8'he1;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffec)\n    begin\n         y_ac_value_r = 8'he2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffed)\n    begin\n         y_ac_value_r = 8'he3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffee)\n    begin\n         y_ac_value_r = 8'he4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hffef)\n    begin\n         y_ac_value_r = 8'he5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff0)\n    begin\n         y_ac_value_r = 8'he6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff1)\n    begin\n         y_ac_value_r = 8'he7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff2)\n    begin\n         y_ac_value_r = 8'he8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff3)\n    begin\n         y_ac_value_r = 8'he9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff4)\n    begin\n         y_ac_value_r = 8'hea;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff5)\n    begin\n         y_ac_value_r = 8'hf1;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff6)\n    begin\n         y_ac_value_r = 8'hf2;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff7)\n    begin\n         y_ac_value_r = 8'hf3;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff8)\n    begin\n         y_ac_value_r = 8'hf4;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfff9)\n    begin\n         y_ac_value_r = 8'hf5;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffa)\n    begin\n         y_ac_value_r = 8'hf6;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffb)\n    begin\n         y_ac_value_r = 8'hf7;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffc)\n    begin\n         y_ac_value_r = 8'hf8;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffd)\n    begin\n         y_ac_value_r = 8'hf9;\n         y_ac_width_r = 5'd16;\n    end\n    else if (lookup_input_i[15:0] == 16'hfffe)\n    begin\n         y_ac_value_r = 8'hfa;\n         y_ac_width_r = 5'd16;\n    end\nend\n\nassign lookup_width_o = y_ac_width_r;\nassign lookup_value_o = y_ac_value_r;\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_dht_std_y_dc.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\nmodule jpeg_dht_std_y_dc\n(\n     input  [ 15:0]  lookup_input_i\n    ,output [  4:0]  lookup_width_o\n    ,output [  7:0]  lookup_value_o\n);\n\n//-----------------------------------------------------------------\n// Y DC Table (standard)\n//-----------------------------------------------------------------\nreg [7:0] y_dc_value_r;\nreg [4:0] y_dc_width_r;\n\nalways @ *\nbegin\n    y_dc_value_r = 8'b0;\n    y_dc_width_r = 5'b0;\n\n    if (lookup_input_i[15:14] == 2'h0)\n    begin\n         y_dc_value_r = 8'h00;\n         y_dc_width_r = 5'd2;\n    end\n    else if (lookup_input_i[15:13] == 3'h2)\n    begin\n         y_dc_value_r = 8'h01;\n         y_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:13] == 3'h3)\n    begin\n         y_dc_value_r = 8'h02;\n         y_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:13] == 3'h4)\n    begin\n         y_dc_value_r = 8'h03;\n         y_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:13] == 3'h5)\n    begin\n         y_dc_value_r = 8'h04;\n         y_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:13] == 3'h6)\n    begin\n         y_dc_value_r = 8'h05;\n         y_dc_width_r = 5'd3;\n    end\n    else if (lookup_input_i[15:12] == 4'he)\n    begin\n         y_dc_value_r = 8'h06;\n         y_dc_width_r = 5'd4;\n    end\n    else if (lookup_input_i[15:11] == 5'h1e)\n    begin\n         y_dc_value_r = 8'h07;\n         y_dc_width_r = 5'd5;\n    end\n    else if (lookup_input_i[15:10] == 6'h3e)\n    begin\n         y_dc_value_r = 8'h08;\n         y_dc_width_r = 5'd6;\n    end\n    else if (lookup_input_i[15:9] == 7'h7e)\n    begin\n         y_dc_value_r = 8'h09;\n         y_dc_width_r = 5'd7;\n    end\n    else if (lookup_input_i[15:8] == 8'hfe)\n    begin\n         y_dc_value_r = 8'h0a;\n         y_dc_width_r = 5'd8;\n    end\n    else if (lookup_input_i[15:7] == 9'h1fe)\n    begin\n         y_dc_value_r = 8'h0b;\n         y_dc_width_r = 5'd9;\n    end\nend\n\nassign lookup_width_o = y_dc_width_r;\nassign lookup_value_o = y_dc_value_r;\n\nendmodule"
  },
  {
    "path": "src_v/jpeg_dqt.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_dqt\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input  [  1:0]  img_dqt_table_y_i\n    ,input  [  1:0]  img_dqt_table_cb_i\n    ,input  [  1:0]  img_dqt_table_cr_i\n    ,input           cfg_valid_i\n    ,input  [  7:0]  cfg_data_i\n    ,input           cfg_last_i\n    ,input           inport_valid_i\n    ,input  [ 15:0]  inport_data_i\n    ,input  [  5:0]  inport_idx_i\n    ,input  [ 31:0]  inport_id_i\n    ,input           inport_eob_i\n    ,input           outport_accept_i\n\n    // Outputs\n    ,output          cfg_accept_o\n    ,output          inport_blk_space_o\n    ,output          outport_valid_o\n    ,output [ 15:0]  outport_data_o\n    ,output [  5:0]  outport_idx_o\n    ,output [ 31:0]  outport_id_o\n    ,output          outport_eob_o\n);\n\n\n\n//-----------------------------------------------------------------\n// DQT tables\n//-----------------------------------------------------------------\n// 4 * 256\nreg [7:0] table_dqt_q[0:255];\n\n//-----------------------------------------------------------------\n// Capture Index\n//-----------------------------------------------------------------\nreg [7:0] idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    idx_q <= 8'hFF;\nelse if (cfg_valid_i && cfg_last_i && cfg_accept_o)\n    idx_q <= 8'hFF;\nelse if (cfg_valid_i && cfg_accept_o)\n    idx_q <= idx_q + 8'd1;\n\nassign cfg_accept_o = 1'b1;\n\n//-----------------------------------------------------------------\n// Write DQT table\n//-----------------------------------------------------------------\nreg [1:0] cfg_table_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    cfg_table_q <= 2'b0;\nelse if (cfg_valid_i && cfg_accept_o && idx_q == 8'hFF)\n    cfg_table_q <= cfg_data_i[1:0];\n\nwire [7:0] cfg_table_addr_w = {cfg_table_q, idx_q[5:0]};\n\nwire [1:0] table_src_w[3:0];\n\nassign table_src_w[0] = img_dqt_table_y_i;\nassign table_src_w[1] = img_dqt_table_cb_i;\nassign table_src_w[2] = img_dqt_table_cr_i;\nassign table_src_w[3] = 2'b0;\n\nwire [7:0] table_rd_idx_w   = {table_src_w[inport_id_i[31:30]], inport_idx_i};\n\nwire       dqt_write_w      = cfg_valid_i && cfg_accept_o && idx_q != 8'hFF;\nwire [7:0] dqt_table_addr_w = dqt_write_w ? cfg_table_addr_w : table_rd_idx_w;\n\nreg [7:0] dqt_entry_q;\n\nalways @ (posedge clk_i )\nbegin\n    if (dqt_write_w)\n        table_dqt_q[dqt_table_addr_w] <= cfg_data_i;\n\n    dqt_entry_q <= table_dqt_q[dqt_table_addr_w];\nend\n\n//-----------------------------------------------------------------\n// dezigzag: Reverse zigzag process\n//-----------------------------------------------------------------\nfunction [5:0] dezigzag;\n    input [5:0] idx;\n    reg [5:0] out_idx;\nbegin\n    case (idx)\n    6'd0: out_idx = 6'd0;\n    6'd1: out_idx = 6'd1;\n    6'd2: out_idx = 6'd8;\n    6'd3: out_idx = 6'd16;\n    6'd4: out_idx = 6'd9;\n    6'd5: out_idx = 6'd2;\n    6'd6: out_idx = 6'd3;\n    6'd7: out_idx = 6'd10;\n    6'd8: out_idx = 6'd17;\n    6'd9: out_idx = 6'd24;\n    6'd10: out_idx = 6'd32;\n    6'd11: out_idx = 6'd25;\n    6'd12: out_idx = 6'd18;\n    6'd13: out_idx = 6'd11;\n    6'd14: out_idx = 6'd4;\n    6'd15: out_idx = 6'd5;\n    6'd16: out_idx = 6'd12;\n    6'd17: out_idx = 6'd19;\n    6'd18: out_idx = 6'd26;\n    6'd19: out_idx = 6'd33;\n    6'd20: out_idx = 6'd40;\n    6'd21: out_idx = 6'd48;\n    6'd22: out_idx = 6'd41;\n    6'd23: out_idx = 6'd34;\n    6'd24: out_idx = 6'd27;\n    6'd25: out_idx = 6'd20;\n    6'd26: out_idx = 6'd13;\n    6'd27: out_idx = 6'd6;\n    6'd28: out_idx = 6'd7;\n    6'd29: out_idx = 6'd14;\n    6'd30: out_idx = 6'd21;\n    6'd31: out_idx = 6'd28;\n    6'd32: out_idx = 6'd35;\n    6'd33: out_idx = 6'd42;\n    6'd34: out_idx = 6'd49;\n    6'd35: out_idx = 6'd56;\n    6'd36: out_idx = 6'd57;\n    6'd37: out_idx = 6'd50;\n    6'd38: out_idx = 6'd43;\n    6'd39: out_idx = 6'd36;\n    6'd40: out_idx = 6'd29;\n    6'd41: out_idx = 6'd22;\n    6'd42: out_idx = 6'd15;\n    6'd43: out_idx = 6'd23;\n    6'd44: out_idx = 6'd30;\n    6'd45: out_idx = 6'd37;\n    6'd46: out_idx = 6'd44;\n    6'd47: out_idx = 6'd51;\n    6'd48: out_idx = 6'd58;\n    6'd49: out_idx = 6'd59;\n    6'd50: out_idx = 6'd52;\n    6'd51: out_idx = 6'd45;\n    6'd52: out_idx = 6'd38;\n    6'd53: out_idx = 6'd31;\n    6'd54: out_idx = 6'd39;\n    6'd55: out_idx = 6'd46;\n    6'd56: out_idx = 6'd53;\n    6'd57: out_idx = 6'd60;\n    6'd58: out_idx = 6'd61;\n    6'd59: out_idx = 6'd54;\n    6'd60: out_idx = 6'd47;\n    6'd61: out_idx = 6'd55;\n    6'd62: out_idx = 6'd62;\n    default: out_idx = 6'd63; \n    endcase\n\n    dezigzag = out_idx;\nend\nendfunction\n\n//-----------------------------------------------------------------\n// Process dequantisation and dezigzag\n//-----------------------------------------------------------------\nreg        inport_valid_q;\nreg [15:0] inport_data_q;\nreg [5:0]  inport_idx_q;\nreg [31:0] inport_id_q;\nreg        inport_eob_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    inport_valid_q <= 1'b0;\nelse\n    inport_valid_q <= inport_valid_i && ~img_start_i;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    inport_idx_q <= 6'b0;\nelse\n    inport_idx_q <= inport_idx_i;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    inport_data_q <= 16'b0;\nelse\n    inport_data_q <= inport_data_i;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    inport_id_q <= 32'b0;\nelse if (inport_valid_i)\n    inport_id_q <= inport_id_i;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    inport_eob_q <= 1'b0;\nelse\n    inport_eob_q <= inport_eob_i;\n\n//-----------------------------------------------------------------\n// Output\n//-----------------------------------------------------------------\nreg               outport_valid_q;\nreg signed [15:0] outport_data_q;\nreg [5:0]         outport_idx_q;\nreg [31:0]        outport_id_q;\nreg               outport_eob_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    outport_valid_q <= 1'b0;\nelse\n    outport_valid_q <= inport_valid_q && ~img_start_i;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    outport_data_q <= 16'b0;\nelse\n    outport_data_q <= inport_data_q * dqt_entry_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    outport_idx_q <= 6'b0;\nelse\n    outport_idx_q <= dezigzag(inport_idx_q);\n\nalways @ (posedge clk_i )\nif (rst_i)\n    outport_id_q <= 32'b0;\nelse\n    outport_id_q <= inport_id_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    outport_eob_q <= 1'b0;\nelse\n    outport_eob_q <= inport_eob_q;\n\nassign outport_valid_o = outport_valid_q;\nassign outport_data_o  = outport_data_q;\nassign outport_idx_o   = outport_idx_q;\nassign outport_id_o    = outport_id_q;    \nassign outport_eob_o   = outport_eob_q;\n\n// TODO: Perf\nassign inport_blk_space_o = outport_accept_i && !(outport_eob_q || inport_eob_q);\n\n`ifdef verilator\nfunction get_valid; /*verilator public*/\nbegin\n    get_valid = outport_valid_o;\nend\nendfunction\nfunction [15:0] get_sample; /*verilator public*/\nbegin\n    get_sample = outport_data_o;\nend\nendfunction\nfunction [5:0] get_sample_idx; /*verilator public*/\nbegin\n    get_sample_idx = outport_idx_o;\nend\nendfunction\n`endif\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [ 15:0]  inport_data_i\n    ,input  [  5:0]  inport_idx_i\n    ,input           inport_eob_i\n    ,input  [ 31:0]  inport_id_i\n    ,input           outport_accept_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 31:0]  outport_data_o\n    ,output [  5:0]  outport_idx_o\n    ,output [ 31:0]  outport_id_o\n);\n\n\n\n\nwire          input_valid_w;\nwire [ 15:0]  input_data0_w;\nwire [ 15:0]  input_data1_w;\nwire [ 15:0]  input_data2_w;\nwire [ 15:0]  input_data3_w;\nwire [  2:0]  input_idx_w;\nwire          input_ready_w;\n\n\njpeg_idct_ram\nu_input\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.img_start_i(img_start_i)\n    ,.img_end_i(img_end_i)\n\n    ,.inport_valid_i(inport_valid_i)\n    ,.inport_data_i(inport_data_i)\n    ,.inport_idx_i(inport_idx_i)\n    ,.inport_eob_i(inport_eob_i)\n    ,.inport_accept_o(inport_accept_o)\n\n    ,.outport_valid_o(input_valid_w)\n    ,.outport_data0_o(input_data0_w)\n    ,.outport_data1_o(input_data1_w)\n    ,.outport_data2_o(input_data2_w)\n    ,.outport_data3_o(input_data3_w)\n    ,.outport_idx_o(input_idx_w)\n    ,.outport_ready_i(outport_accept_i)\n);\n\nwire          idct_x_valid_w;\nwire [ 31:0]  idct_x_data_w;\nwire [  5:0]  idct_x_idx_w;\nwire          idct_x_accept_w;\n\njpeg_idct_x\nu_idct_x\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.img_start_i(img_start_i)\n    ,.img_end_i(img_end_i)\n\n    ,.inport_valid_i(input_valid_w)\n    ,.inport_data0_i(input_data0_w)\n    ,.inport_data1_i(input_data1_w)\n    ,.inport_data2_i(input_data2_w)\n    ,.inport_data3_i(input_data3_w)\n    ,.inport_idx_i(input_idx_w)\n\n    ,.outport_valid_o(idct_x_valid_w)\n    ,.outport_data_o(idct_x_data_w)\n    ,.outport_idx_o(idct_x_idx_w)\n);\n\nwire          transpose_valid_w;\nwire [ 31:0]  transpose_data0_w;\nwire [ 31:0]  transpose_data1_w;\nwire [ 31:0]  transpose_data2_w;\nwire [ 31:0]  transpose_data3_w;\nwire [  2:0]  transpose_idx_w;\nwire          transpose_ready_w = 1'b1;\n\njpeg_idct_transpose\nu_transpose\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.img_start_i(img_start_i)\n    ,.img_end_i(img_end_i)\n\n    ,.inport_valid_i(idct_x_valid_w)\n    ,.inport_data_i(idct_x_data_w)\n    ,.inport_idx_i(idct_x_idx_w)\n    ,.inport_accept_o(idct_x_accept_w)\n\n    ,.outport_valid_o(transpose_valid_w)\n    ,.outport_data0_o(transpose_data0_w)\n    ,.outport_data1_o(transpose_data1_w)\n    ,.outport_data2_o(transpose_data2_w)\n    ,.outport_data3_o(transpose_data3_w)\n    ,.outport_idx_o(transpose_idx_w)\n    ,.outport_ready_i(transpose_ready_w)\n);\n\njpeg_idct_y\nu_idct_y\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.img_start_i(img_start_i)\n    ,.img_end_i(img_end_i)\n\n    ,.inport_valid_i(transpose_valid_w)\n    ,.inport_data0_i(transpose_data0_w)\n    ,.inport_data1_i(transpose_data1_w)\n    ,.inport_data2_i(transpose_data2_w)\n    ,.inport_data3_i(transpose_data3_w)\n    ,.inport_idx_i(transpose_idx_w)\n\n    ,.outport_valid_o(outport_valid_o)\n    ,.outport_data_o(outport_data_o)\n    ,.outport_idx_o(outport_idx_o)\n);\n\n\njpeg_idct_fifo\n#(\n     .WIDTH(32)\n    ,.DEPTH(8)\n    ,.ADDR_W(3)\n)\nu_id_fifo\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.flush_i(img_start_i)\n\n    ,.push_i(inport_eob_i)\n    ,.data_in_i(inport_id_i)\n    ,.accept_o()\n\n    ,.valid_o()\n    ,.data_out_o(outport_id_o)\n    ,.pop_i(outport_valid_o && outport_idx_o == 6'd63)\n);\n\n`ifdef verilator\nfunction get_valid; /*verilator public*/\nbegin\n    get_valid = outport_valid_o;\nend\nendfunction\nfunction [5:0] get_sample_idx; /*verilator public*/\nbegin\n    get_sample_idx = outport_idx_o;\nend\nendfunction\nfunction [31:0] get_sample; /*verilator public*/\nbegin\n    get_sample = outport_data_o;\nend\nendfunction\n`endif\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_fifo.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_fifo\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter WIDTH            = 8\n    ,parameter DEPTH            = 4\n    ,parameter ADDR_W           = 2\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input  [WIDTH-1:0]  data_in_i\n    ,input           push_i\n    ,input           pop_i\n    ,input           flush_i\n\n    // Outputs\n    ,output [WIDTH-1:0]  data_out_o\n    ,output          accept_o\n    ,output          valid_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Local Params\n//-----------------------------------------------------------------\nlocalparam COUNT_W = ADDR_W + 1;\n\n//-----------------------------------------------------------------\n// Registers\n//-----------------------------------------------------------------\nreg [WIDTH-1:0]   ram_q[DEPTH-1:0];\nreg [ADDR_W-1:0]  rd_ptr_q;\nreg [ADDR_W-1:0]  wr_ptr_q;\nreg [COUNT_W-1:0] count_q;\n\n//-----------------------------------------------------------------\n// Sequential\n//-----------------------------------------------------------------\nalways @ (posedge clk_i or posedge rst_i)\nif (rst_i)\nbegin\n    count_q   <= {(COUNT_W) {1'b0}};\n    rd_ptr_q  <= {(ADDR_W) {1'b0}};\n    wr_ptr_q  <= {(ADDR_W) {1'b0}};\nend\nelse if (flush_i)\nbegin\n    count_q   <= {(COUNT_W) {1'b0}};\n    rd_ptr_q  <= {(ADDR_W) {1'b0}};\n    wr_ptr_q  <= {(ADDR_W) {1'b0}};\nend\nelse\nbegin\n    // Push\n    if (push_i & accept_o)\n    begin\n        ram_q[wr_ptr_q] <= data_in_i;\n        wr_ptr_q        <= wr_ptr_q + 1;\n    end\n\n    // Pop\n    if (pop_i & valid_o)\n        rd_ptr_q      <= rd_ptr_q + 1;\n\n    // Count up\n    if ((push_i & accept_o) & ~(pop_i & valid_o))\n        count_q <= count_q + 1;\n    // Count down\n    else if (~(push_i & accept_o) & (pop_i & valid_o))\n        count_q <= count_q - 1;\nend\n\n//-------------------------------------------------------------------\n// Combinatorial\n//-------------------------------------------------------------------\n/* verilator lint_off WIDTH */\nassign valid_o       = (count_q != 0);\nassign accept_o      = (count_q != DEPTH);\n/* verilator lint_on WIDTH */\n\nassign data_out_o    = ram_q[rd_ptr_q];\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_ram.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_ram\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [ 15:0]  inport_data_i\n    ,input  [  5:0]  inport_idx_i\n    ,input           inport_eob_i\n    ,input           outport_ready_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 15:0]  outport_data0_o\n    ,output [ 15:0]  outport_data1_o\n    ,output [ 15:0]  outport_data2_o\n    ,output [ 15:0]  outport_data3_o\n    ,output [  2:0]  outport_idx_o\n);\n\n\n\nreg [1:0]   block_wr_q;\nreg [1:0]   block_rd_q;\nreg [5:0]   rd_idx_q;\nreg [3:0]   rd_addr_q;\n\nwire [5:0]  wr_ptr_w = {block_wr_q, inport_idx_i[5:3], inport_idx_i[0]};\n\nwire [15:0] outport_data0_w;\nwire [15:0] outport_data1_w;\nwire [15:0] outport_data2_w;\nwire [15:0] outport_data3_w;\n\nwire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd0 || inport_idx_i[2:0] == 3'd1);\nwire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd2 || inport_idx_i[2:0] == 3'd3);\nwire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd4 || inport_idx_i[2:0] == 3'd5);\nwire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd6 || inport_idx_i[2:0] == 3'd7);\n\njpeg_idct_ram_dp\nu_ram0\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr0_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(16'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data0_w)\n);\n\njpeg_idct_ram_dp\nu_ram1\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr1_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(16'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data1_w)\n);\n\njpeg_idct_ram_dp\nu_ram2\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr2_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(16'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data2_w)\n);\n\njpeg_idct_ram_dp\nu_ram3\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr3_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(16'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data3_w)\n);\n\n//-----------------------------------------------------------------\n// Data Qualifiers\n//-----------------------------------------------------------------\nreg [63:0]        data_valid0_r;\nreg [63:0]        data_valid0_q;\n\nalways @ *\nbegin\n    data_valid0_r = data_valid0_q;\n\n    // End of block read out - reset data valid state\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        case (block_rd_q)\n        2'd0:    data_valid0_r[15:0]  = 16'b0;\n        2'd1:    data_valid0_r[31:16] = 16'b0;\n        2'd2:    data_valid0_r[47:32] = 16'b0;\n        default: data_valid0_r[63:48] = 16'b0;\n        endcase\n    end\n\n    if (wr0_w)\n        data_valid0_r[wr_ptr_w] = 1'b1;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_valid0_q <= 64'b0;\nelse if (img_start_i)\n    data_valid0_q <= 64'b0;\nelse\n    data_valid0_q <= data_valid0_r;\n\nreg [63:0]        data_valid1_r;\nreg [63:0]        data_valid1_q;\n\nalways @ *\nbegin\n    data_valid1_r = data_valid1_q;\n\n    // End of block read out - reset data valid state\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        case (block_rd_q)\n        2'd0:    data_valid1_r[15:0]  = 16'b0;\n        2'd1:    data_valid1_r[31:16] = 16'b0;\n        2'd2:    data_valid1_r[47:32] = 16'b0;\n        default: data_valid1_r[63:48] = 16'b0;\n        endcase\n    end\n\n    if (wr1_w)\n        data_valid1_r[wr_ptr_w] = 1'b1;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_valid1_q <= 64'b0;\nelse if (img_start_i)\n    data_valid1_q <= 64'b0;\nelse\n    data_valid1_q <= data_valid1_r;\n\nreg [63:0]        data_valid2_r;\nreg [63:0]        data_valid2_q;\n\nalways @ *\nbegin\n    data_valid2_r = data_valid2_q;\n\n    // End of block read out - reset data valid state\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        case (block_rd_q)\n        2'd0:    data_valid2_r[15:0]  = 16'b0;\n        2'd1:    data_valid2_r[31:16] = 16'b0;\n        2'd2:    data_valid2_r[47:32] = 16'b0;\n        default: data_valid2_r[63:48] = 16'b0;\n        endcase\n    end\n\n    if (wr2_w)\n        data_valid2_r[wr_ptr_w] = 1'b1;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_valid2_q <= 64'b0;\nelse if (img_start_i)\n    data_valid2_q <= 64'b0;\nelse\n    data_valid2_q <= data_valid2_r;\n\nreg [63:0]        data_valid3_r;\nreg [63:0]        data_valid3_q;\n\nalways @ *\nbegin\n    data_valid3_r = data_valid3_q;\n\n    // End of block read out - reset data valid state\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        case (block_rd_q)\n        2'd0:    data_valid3_r[15:0]  = 16'b0;\n        2'd1:    data_valid3_r[31:16] = 16'b0;\n        2'd2:    data_valid3_r[47:32] = 16'b0;\n        default: data_valid3_r[63:48] = 16'b0;\n        endcase\n    end\n\n    if (wr3_w)\n        data_valid3_r[wr_ptr_w] = 1'b1;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_valid3_q <= 64'b0;\nelse if (img_start_i)\n    data_valid3_q <= 64'b0;\nelse\n    data_valid3_q <= data_valid3_r;\n\n\n//-----------------------------------------------------------------\n// Input Buffer\n//-----------------------------------------------------------------\nreg [3:0] block_ready_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_ready_q     <= 4'b0;\n    block_wr_q        <= 2'b0;\n    block_rd_q        <= 2'b0;\nend\nelse if (img_start_i)\nbegin\n    block_ready_q     <= 4'b0;\n    block_wr_q        <= 2'b0;\n    block_rd_q        <= 2'b0;\nend\nelse\nbegin\n    if (inport_eob_i && inport_accept_o)\n    begin\n        block_ready_q[block_wr_q] <= 1'b1;\n        block_wr_q                <= block_wr_q + 2'd1;\n    end\n\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        block_ready_q[block_rd_q] <= 1'b0;\n        block_rd_q                <= block_rd_q + 2'd1;\n    end\nend\n\nassign inport_accept_o = ~block_ready_q[block_wr_q];\n\n//-----------------------------------------------------------------\n// FSM\n//-----------------------------------------------------------------\nlocalparam STATE_W           = 2;\nlocalparam STATE_IDLE        = 2'd0;\nlocalparam STATE_SETUP       = 2'd1;\nlocalparam STATE_ACTIVE      = 2'd2;\n\nreg [STATE_W-1:0] state_q;\nreg [STATE_W-1:0] next_state_r;\n\nalways @ *\nbegin\n    next_state_r = state_q;\n\n    case (state_q)\n    STATE_IDLE:\n    begin\n        if (block_ready_q[block_rd_q] && outport_ready_i)\n            next_state_r = STATE_SETUP;\n    end\n    STATE_SETUP:\n    begin\n        next_state_r = STATE_ACTIVE;\n    end\n    STATE_ACTIVE:\n    begin\n        if (outport_valid_o && rd_idx_q == 6'd63)\n            next_state_r = STATE_IDLE;\n    end\n    default: ;\n    endcase\n\n    if (img_start_i)\n        next_state_r = STATE_IDLE;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    state_q <= STATE_IDLE;\nelse\n    state_q <= next_state_r;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_idx_q <= 6'b0;\nelse if (img_start_i)\n    rd_idx_q <= 6'b0;\nelse if (state_q == STATE_ACTIVE)\n    rd_idx_q <= rd_idx_q + 6'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_addr_q <= 4'b0;\nelse if (state_q == STATE_IDLE)\n    rd_addr_q <= 4'b0;\nelse if (state_q == STATE_SETUP)\n    rd_addr_q <= 4'd1;\nelse if (state_q == STATE_ACTIVE)\nbegin\n    case (rd_idx_q[2:0])\n    3'd0: rd_addr_q <= rd_addr_q - 1;\n    3'd1: rd_addr_q <= rd_addr_q + 1;\n    3'd2: ;\n    3'd3: rd_addr_q <= rd_addr_q - 1;\n    3'd4: rd_addr_q <= rd_addr_q + 1;\n    3'd5: rd_addr_q <= rd_addr_q - 1;\n    3'd6: rd_addr_q <= rd_addr_q + 2;\n    3'd7: rd_addr_q <= rd_addr_q + 1;\n    endcase\nend\n\nreg data_val0_q;\nreg data_val1_q;\nreg data_val2_q;\nreg data_val3_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    data_val0_q <= 1'b0;\n    data_val1_q <= 1'b0;\n    data_val2_q <= 1'b0;\n    data_val3_q <= 1'b0;\nend\nelse\nbegin\n    data_val0_q <= data_valid0_q[{block_rd_q, rd_addr_q}];\n    data_val1_q <= data_valid1_q[{block_rd_q, rd_addr_q}];\n    data_val2_q <= data_valid2_q[{block_rd_q, rd_addr_q}];\n    data_val3_q <= data_valid3_q[{block_rd_q, rd_addr_q}];\nend\n\nassign outport_valid_o = (state_q == STATE_ACTIVE);\nassign outport_idx_o   = rd_idx_q[2:0];\nassign outport_data0_o = {16{data_val0_q}} & outport_data0_w;\nassign outport_data1_o = {16{data_val1_q}} & outport_data1_w;\nassign outport_data2_o = {16{data_val2_q}} & outport_data2_w;\nassign outport_data3_o = {16{data_val3_q}} & outport_data3_w;\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_ram_dp.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_ram_dp\n(\n    // Inputs\n     input           clk0_i\n    ,input           rst0_i\n    ,input  [  5:0]  addr0_i\n    ,input  [ 15:0]  data0_i\n    ,input           wr0_i\n    ,input           clk1_i\n    ,input           rst1_i\n    ,input  [  5:0]  addr1_i\n    ,input  [ 15:0]  data1_i\n    ,input           wr1_i\n\n    // Outputs\n    ,output [ 15:0]  data0_o\n    ,output [ 15:0]  data1_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Dual Port RAM\n// Mode: Read First\n//-----------------------------------------------------------------\n/* verilator lint_off MULTIDRIVEN */\nreg [15:0]   ram [63:0] /*verilator public*/;\n/* verilator lint_on MULTIDRIVEN */\n\nreg [15:0] ram_read0_q;\nreg [15:0] ram_read1_q;\n\n\n// Synchronous write\nalways @ (posedge clk0_i)\nbegin\n    if (wr0_i)\n        ram[addr0_i][15:0] <= data0_i[15:0];\n\n    ram_read0_q <= ram[addr0_i];\nend\n\nalways @ (posedge clk1_i)\nbegin\n    if (wr1_i)\n        ram[addr1_i][15:0] <= data1_i[15:0];\n\n    ram_read1_q <= ram[addr1_i];\nend\n\n\nassign data0_o = ram_read0_q;\nassign data1_o = ram_read1_q;\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_transpose.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_transpose\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data_i\n    ,input  [  5:0]  inport_idx_i\n    ,input           outport_ready_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 31:0]  outport_data0_o\n    ,output [ 31:0]  outport_data1_o\n    ,output [ 31:0]  outport_data2_o\n    ,output [ 31:0]  outport_data3_o\n    ,output [  2:0]  outport_idx_o\n);\n\n\n\nreg         block_wr_q;\nreg         block_rd_q;\nreg [5:0]   rd_idx_q;\nreg [3:0]   rd_addr_q;\n\nwire [4:0]  wr_ptr_w = {block_wr_q, inport_idx_i[3:0]};\n\nwire [31:0] outport_data0_w;\nwire [31:0] outport_data1_w;\nwire [31:0] outport_data2_w;\nwire [31:0] outport_data3_w;\n\nwire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd0);\nwire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd1);\nwire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd2);\nwire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd3);\n\njpeg_idct_transpose_ram\nu_ram0\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr0_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(32'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data0_w)\n);\n\njpeg_idct_transpose_ram\nu_ram1\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr1_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(32'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data1_w)\n);\n\njpeg_idct_transpose_ram\nu_ram2\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr2_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(32'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data2_w)\n);\n\njpeg_idct_transpose_ram\nu_ram3\n(\n     .clk0_i(clk_i)\n    ,.rst0_i(rst_i)\n    ,.clk1_i(clk_i)\n    ,.rst1_i(rst_i)\n\n    ,.addr0_i(wr_ptr_w)\n    ,.data0_i(inport_data_i)\n    ,.wr0_i(wr3_w)\n    ,.data0_o()\n\n    ,.addr1_i({block_rd_q, rd_addr_q})\n    ,.data1_i(32'b0)\n    ,.wr1_i(1'b0)\n    ,.data1_o(outport_data3_w)\n);\n\n//-----------------------------------------------------------------\n// Input Buffer\n//-----------------------------------------------------------------\nreg [1:0] block_ready_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_ready_q     <= 2'b0;\n    block_wr_q        <= 1'b0;\n    block_rd_q        <= 1'b0;\nend\nelse if (img_start_i)\nbegin\n    block_ready_q     <= 2'b0;\n    block_wr_q        <= 1'b0;\n    block_rd_q        <= 1'b0;\nend\nelse\nbegin\n    if (inport_valid_i && inport_idx_i == 6'd63 && inport_accept_o)\n    begin\n        block_ready_q[block_wr_q] <= 1'b1;\n        block_wr_q                <= ~block_wr_q;\n    end\n\n    if (outport_valid_o && rd_idx_q[5:0] == 6'd63)\n    begin\n        block_ready_q[block_rd_q] <= 1'b0;\n        block_rd_q <= ~block_rd_q;\n    end\nend\n\nassign inport_accept_o = ~block_ready_q[block_wr_q];\n\n//-----------------------------------------------------------------\n// FSM\n//-----------------------------------------------------------------\nlocalparam STATE_W           = 2;\nlocalparam STATE_IDLE        = 2'd0;\nlocalparam STATE_SETUP       = 2'd1;\nlocalparam STATE_ACTIVE      = 2'd2;\n\nreg [STATE_W-1:0] state_q;\nreg [STATE_W-1:0] next_state_r;\n\nalways @ *\nbegin\n    next_state_r = state_q;\n\n    case (state_q)\n    STATE_IDLE:\n    begin\n        if (block_ready_q[block_rd_q] && outport_ready_i)\n            next_state_r = STATE_SETUP;\n    end\n    STATE_SETUP:\n    begin\n        next_state_r = STATE_ACTIVE;\n    end\n    STATE_ACTIVE:\n    begin\n        if (outport_valid_o && rd_idx_q == 6'd63)\n            next_state_r = STATE_IDLE;\n    end\n    default: ;\n    endcase\n\n    if (img_start_i)\n        next_state_r = STATE_IDLE;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    state_q <= STATE_IDLE;\nelse\n    state_q <= next_state_r;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_idx_q <= 6'b0;\nelse if (img_start_i)\n    rd_idx_q <= 6'b0;\nelse if (state_q == STATE_ACTIVE)\n    rd_idx_q <= rd_idx_q + 6'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_addr_q <= 4'b0;\nelse if (state_q == STATE_IDLE)\n    rd_addr_q <= 4'b0;\nelse if (state_q == STATE_SETUP)\n    rd_addr_q <= 4'd8;\nelse if (state_q == STATE_ACTIVE)\nbegin\n    case (rd_idx_q[2:0])\n    3'd0: rd_addr_q <= rd_addr_q - 4'd8;\n    3'd1: rd_addr_q <= rd_addr_q + 4'd8;\n    3'd2: ;\n    3'd3: rd_addr_q <= rd_addr_q - 4'd8;\n    3'd4: rd_addr_q <= rd_addr_q + 4'd8;\n    3'd5: rd_addr_q <= rd_addr_q - 4'd8;\n    3'd6: rd_addr_q <= rd_addr_q + 4'd1;\n    3'd7: rd_addr_q <= rd_addr_q + 4'd8;\n    endcase\nend\n\nassign outport_valid_o = (state_q == STATE_ACTIVE);\nassign outport_idx_o   = rd_idx_q[2:0];\nassign outport_data0_o = outport_data0_w;\nassign outport_data1_o = outport_data1_w;\nassign outport_data2_o = outport_data2_w;\nassign outport_data3_o = outport_data3_w;\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_transpose_ram.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_transpose_ram\n(\n    // Inputs\n     input           clk0_i\n    ,input           rst0_i\n    ,input  [  4:0]  addr0_i\n    ,input  [ 31:0]  data0_i\n    ,input           wr0_i\n    ,input           clk1_i\n    ,input           rst1_i\n    ,input  [  4:0]  addr1_i\n    ,input  [ 31:0]  data1_i\n    ,input           wr1_i\n\n    // Outputs\n    ,output [ 31:0]  data0_o\n    ,output [ 31:0]  data1_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Dual Port RAM\n// Mode: Read First\n//-----------------------------------------------------------------\n/* verilator lint_off MULTIDRIVEN */\nreg [31:0]   ram [31:0] /*verilator public*/;\n/* verilator lint_on MULTIDRIVEN */\n\nreg [31:0] ram_read0_q;\nreg [31:0] ram_read1_q;\n\n\n// Synchronous write\nalways @ (posedge clk0_i)\nbegin\n    if (wr0_i)\n        ram[addr0_i][31:0] <= data0_i[31:0];\n\n    ram_read0_q <= ram[addr0_i];\nend\n\nalways @ (posedge clk1_i)\nbegin\n    if (wr1_i)\n        ram[addr1_i][31:0] <= data1_i[31:0];\n\n    ram_read1_q <= ram[addr1_i];\nend\n\n\nassign data0_o = ram_read0_q;\nassign data1_o = ram_read1_q;\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_x.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_x\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter OUT_SHIFT        = 11\n    ,parameter INPUT_WIDTH      = 16\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [ 15:0]  inport_data0_i\n    ,input  [ 15:0]  inport_data1_i\n    ,input  [ 15:0]  inport_data2_i\n    ,input  [ 15:0]  inport_data3_i\n    ,input  [  2:0]  inport_idx_i\n\n    // Outputs\n    ,output          outport_valid_o\n    ,output [ 31:0]  outport_data_o\n    ,output [  5:0]  outport_idx_o\n);\n\n\n\n\nlocalparam [15:0] C1_16 = 4017; // cos( pi/16) x4096\nlocalparam [15:0] C2_16 = 3784; // cos(2pi/16) x4096\nlocalparam [15:0] C3_16 = 3406; // cos(3pi/16) x4096\nlocalparam [15:0] C4_16 = 2896; // cos(4pi/16) x4096\nlocalparam [15:0] C5_16 = 2276; // cos(5pi/16) x4096\nlocalparam [15:0] C6_16 = 1567; // cos(6pi/16) x4096\nlocalparam [15:0] C7_16 = 799;  // cos(7pi/16) x4096\n\nwire signed [31:0] block_in_0_1 = {{16{inport_data0_i[15]}}, inport_data0_i};\nwire signed [31:0] block_in_2_3 = {{16{inport_data1_i[15]}}, inport_data1_i};\nwire signed [31:0] block_in_4_5 = {{16{inport_data2_i[15]}}, inport_data2_i};\nwire signed [31:0] block_in_6_7 = {{16{inport_data3_i[15]}}, inport_data3_i};\n\n//-----------------------------------------------------------------\n// IDCT\n//-----------------------------------------------------------------\nreg signed [31:0] i0;\nreg signed [31:0] mul0_a;\nreg signed [31:0] mul0_b;\nreg signed [31:0] mul1_a;\nreg signed [31:0] mul1_b;\nreg signed [31:0] mul2_a;\nreg signed [31:0] mul2_b;\nreg signed [31:0] mul3_a;\nreg signed [31:0] mul3_b;\nreg signed [31:0] mul4_a;\nreg signed [31:0] mul4_b;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    i0     <= 32'b0;\n    mul0_a <= 32'b0;\n    mul0_b <= 32'b0;\n    mul1_a <= 32'b0;\n    mul1_b <= 32'b0;\n    mul2_a <= 32'b0;\n    mul2_b <= 32'b0;\n    mul3_a <= 32'b0;\n    mul3_b <= 32'b0;\n    mul4_a <= 32'b0;\n    mul4_b <= 32'b0;\nend\nelse\nbegin\n    /* verilator lint_off WIDTH */\n    case (inport_idx_i)\n    3'd0:\n    begin\n        i0     <= block_in_0_1 + block_in_4_5;\n        mul0_a <= block_in_2_3;\n        mul0_b <= C2_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C6_16;\n    end\n    3'd1:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C1_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C7_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C5_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C3_16;\n        mul4_a <= i0;\n        mul4_b <= C4_16;\n    end\n    3'd2:\n    begin\n        i0     <= block_in_0_1 - block_in_4_5;\n    end\n    3'd3:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C7_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C1_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C3_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C5_16;\n    end\n    3'd4:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C7_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C1_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C3_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C5_16;\n    end\n    3'd5:\n    begin\n        mul0_a <= block_in_2_3;\n        mul0_b <= C6_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C2_16;\n        mul4_a <= i0;\n        mul4_b <= C4_16;\n    end\n    default:\n        ;\n    endcase\n    /* verilator lint_on WIDTH */\nend\n\nreg signed [31:0] mul0_q;\nreg signed [31:0] mul1_q;\nreg signed [31:0] mul2_q;\nreg signed [31:0] mul3_q;\nreg signed [31:0] mul4_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    mul0_q <= 32'b0;\n    mul1_q <= 32'b0;\n    mul2_q <= 32'b0;\n    mul3_q <= 32'b0;\n    mul4_q <= 32'b0;\nend\nelse\nbegin\n    mul0_q <= mul0_a * mul0_b;\n    mul1_q <= mul1_a * mul1_b;\n    mul2_q <= mul2_a * mul2_b;\n    mul3_q <= mul3_a * mul3_b;\n    mul4_q <= mul4_a * mul4_b;\nend\n\nreg signed [31:0] mul0;\nreg signed [31:0] mul1;\nreg signed [31:0] mul2;\nreg signed [31:0] mul3;\nreg signed [31:0] mul4;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    mul0 <= 32'b0;\n    mul1 <= 32'b0;\n    mul2 <= 32'b0;\n    mul3 <= 32'b0;\n    mul4 <= 32'b0;\nend\nelse\nbegin\n    mul0 <= mul0_q;\n    mul1 <= mul1_q;\n    mul2 <= mul2_q;\n    mul3 <= mul3_q;\n    mul4 <= mul4_q;\nend\n\nreg        out_stg0_valid_q;\nreg [2:0]  out_stg0_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg0_valid_q <= 1'b0;\n    out_stg0_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg0_valid_q <= inport_valid_i;\n    out_stg0_idx_q   <= inport_idx_i;\nend\n\nreg        out_stg1_valid_q;\nreg [2:0]  out_stg1_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg1_valid_q <= 1'b0;\n    out_stg1_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg1_valid_q <= out_stg0_valid_q;\n    out_stg1_idx_q   <= out_stg0_idx_q;\nend\n\nreg        out_stg2_valid_q;\nreg [2:0]  out_stg2_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg2_valid_q <= 1'b0;\n    out_stg2_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg2_valid_q <= out_stg1_valid_q;\n    out_stg2_idx_q   <= out_stg1_idx_q;\nend\n\nreg signed [31:0] o_s5;\nreg signed [31:0] o_s6;\nreg signed [31:0] o_s7;\nreg signed [31:0] o_t0;\nreg signed [31:0] o_t1;\nreg signed [31:0] o_t2;\nreg signed [31:0] o_t3;\nreg signed [31:0] o_t4;\nreg signed [31:0] o_t5;\nreg signed [31:0] o_t6;\nreg signed [31:0] o_t7;\nreg signed [31:0] o_t6_5;\nreg signed [31:0] o_t5_6;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    o_s5   <= 32'b0;\n    o_s6   <= 32'b0;\n    o_s7   <= 32'b0;\n    o_t0   <= 32'b0;\n    o_t1   <= 32'b0;\n    o_t2   <= 32'b0;\n    o_t3   <= 32'b0;\n    o_t4   <= 32'b0;\n    o_t5   <= 32'b0;\n    o_t6   <= 32'b0;\n    o_t7   <= 32'b0;\n    o_t6_5 <= 32'b0;\n    o_t5_6 <= 32'b0;\nend\nelse\nbegin\n    case (out_stg2_idx_q)\n    3'd0:\n    begin\n        o_t3 <= mul0 + mul1; // s3\n    end\n    3'd1:\n    begin\n        o_s7 <= mul0 + mul1;\n        o_s6 <= mul2 + mul3;\n        o_t0 <= mul4;        // s0\n    end\n    3'd2:\n    begin\n        o_t0 <= o_t0 + o_t3; // t0\n        o_t3 <= o_t0 - o_t3; // t3\n        o_t7 <= o_s6 + o_s7;\n    end\n    3'd3:\n    begin\n        o_t4 <= (mul0 - mul1) + (mul2 - mul3);\n    end\n    3'd4:\n    begin\n        o_t0 <= mul0 - mul1; // s4\n        o_s5 <= mul2 - mul3;    \n    end\n    3'd5:\n    begin\n        o_t3 <= mul0 - mul1; // s2\n        o_t4 <= mul4; // s1\n        o_t5 <= o_t0 - o_s5;\n        o_t6 <= o_s7 - o_s6;\n    end\n    3'd6:\n    begin\n        o_t1 <= o_t4 + o_t3;\n        o_t2 <= o_t4 - o_t3;\n        o_t6_5 <= o_t6 - o_t5;\n        o_t5_6 <= o_t5 + o_t6;\n    end\n    default:\n    begin\n        o_s5 <= (o_t6_5 * 181) / 256; // 1/sqrt(2)\n        o_s6 <= (o_t5_6 * 181) / 256; // 1/sqrt(2)\n    end\n    endcase\nend\n\nreg        out_stg3_valid_q;\nreg [2:0]  out_stg3_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg3_valid_q <= 1'b0;\n    out_stg3_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg3_valid_q <= out_stg2_valid_q;\n    out_stg3_idx_q   <= out_stg2_idx_q;\nend\n\nreg signed [31:0] block_out[0:7];\nreg signed [31:0] block_out_tmp;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_out[0] <= 32'b0;\n    block_out[1] <= 32'b0;\n    block_out[2] <= 32'b0;\n    block_out[3] <= 32'b0;\n    block_out[4] <= 32'b0;\n    block_out[5] <= 32'b0;\n    block_out[6] <= 32'b0;\n    block_out[7] <= 32'b0;\n    block_out_tmp <= 32'b0;\nend\nelse if (out_stg3_valid_q)\nbegin\n    if (out_stg3_idx_q == 3'd3)\n    begin\n        block_out[0] <= ((o_t0 + o_t7) >>> OUT_SHIFT);\n        block_out_tmp <= ((o_t0 - o_t7) >>> OUT_SHIFT); // block_out[7]\n        block_out[3] <= ((o_t3 + o_t4) >>> OUT_SHIFT);\n        block_out[4] <= ((o_t3 - o_t4) >>> OUT_SHIFT);\n    end\n\n    if (out_stg3_idx_q == 3'd6)\n        block_out[7] <= block_out_tmp;\n\n    if (out_stg3_idx_q == 3'd7)\n    begin\n        block_out[2] <= ((o_t2 + o_s5) >>> OUT_SHIFT);\n        block_out[5] <= ((o_t2 - o_s5) >>> OUT_SHIFT);\n        block_out[1] <= ((o_t1 + o_s6) >>> OUT_SHIFT);\n        block_out[6] <= ((o_t1 - o_s6) >>> OUT_SHIFT);\n    end\nend\n\nreg [7:0] valid_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    valid_q  <= 8'b0;\nelse if (img_start_i)\n    valid_q  <= 8'b0;\nelse\n    valid_q <= {valid_q[6:0], out_stg3_valid_q};\n\nreg [5:0] ptr_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    ptr_q <= 6'd0;\nelse if (img_start_i)\n    ptr_q <= 6'd0;\nelse if (outport_valid_o)\n    ptr_q <= ptr_q + 6'd1;\n\nassign outport_valid_o = valid_q[6];\nassign outport_data_o  = block_out[ptr_q[2:0]];\n\nassign outport_idx_o   = ptr_q;\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_idct_y.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_idct_y\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter OUT_SHIFT        = 15\n    ,parameter INPUT_WIDTH      = 32\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data0_i\n    ,input  [ 31:0]  inport_data1_i\n    ,input  [ 31:0]  inport_data2_i\n    ,input  [ 31:0]  inport_data3_i\n    ,input  [  2:0]  inport_idx_i\n\n    // Outputs\n    ,output          outport_valid_o\n    ,output [ 31:0]  outport_data_o\n    ,output [  5:0]  outport_idx_o\n);\n\n\n\n\nlocalparam [15:0] C1_16 = 4017; // cos( pi/16) x4096\nlocalparam [15:0] C2_16 = 3784; // cos(2pi/16) x4096\nlocalparam [15:0] C3_16 = 3406; // cos(3pi/16) x4096\nlocalparam [15:0] C4_16 = 2896; // cos(4pi/16) x4096\nlocalparam [15:0] C5_16 = 2276; // cos(5pi/16) x4096\nlocalparam [15:0] C6_16 = 1567; // cos(6pi/16) x4096\nlocalparam [15:0] C7_16 = 799;  // cos(7pi/16) x4096\n\nwire signed [31:0] block_in_0_1 = inport_data0_i;\nwire signed [31:0] block_in_2_3 = inport_data1_i;\nwire signed [31:0] block_in_4_5 = inport_data2_i;\nwire signed [31:0] block_in_6_7 = inport_data3_i;\n\n//-----------------------------------------------------------------\n// IDCT\n//-----------------------------------------------------------------\nreg signed [31:0] i0;\nreg signed [31:0] mul0_a;\nreg signed [31:0] mul0_b;\nreg signed [31:0] mul1_a;\nreg signed [31:0] mul1_b;\nreg signed [31:0] mul2_a;\nreg signed [31:0] mul2_b;\nreg signed [31:0] mul3_a;\nreg signed [31:0] mul3_b;\nreg signed [31:0] mul4_a;\nreg signed [31:0] mul4_b;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    i0     <= 32'b0;\n    mul0_a <= 32'b0;\n    mul0_b <= 32'b0;\n    mul1_a <= 32'b0;\n    mul1_b <= 32'b0;\n    mul2_a <= 32'b0;\n    mul2_b <= 32'b0;\n    mul3_a <= 32'b0;\n    mul3_b <= 32'b0;\n    mul4_a <= 32'b0;\n    mul4_b <= 32'b0;\nend\nelse\nbegin\n    /* verilator lint_off WIDTH */\n    case (inport_idx_i)\n    3'd0:\n    begin\n        i0     <= block_in_0_1 + block_in_4_5;\n        mul0_a <= block_in_2_3;\n        mul0_b <= C2_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C6_16;\n    end\n    3'd1:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C1_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C7_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C5_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C3_16;\n        mul4_a <= i0;\n        mul4_b <= C4_16;\n    end\n    3'd2:\n    begin\n        i0     <= block_in_0_1 - block_in_4_5;\n    end\n    3'd3:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C7_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C1_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C3_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C5_16;\n    end\n    3'd4:\n    begin\n        mul0_a <= block_in_0_1;\n        mul0_b <= C7_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C1_16;\n        mul2_a <= block_in_4_5;\n        mul2_b <= C3_16;\n        mul3_a <= block_in_2_3;\n        mul3_b <= C5_16;\n    end\n    3'd5:\n    begin\n        mul0_a <= block_in_2_3;\n        mul0_b <= C6_16;\n        mul1_a <= block_in_6_7;\n        mul1_b <= C2_16;\n        mul4_a <= i0;\n        mul4_b <= C4_16;\n    end\n    default:\n        ;\n    endcase\n    /* verilator lint_on WIDTH */\nend\n\nreg signed [31:0] mul0_q;\nreg signed [31:0] mul1_q;\nreg signed [31:0] mul2_q;\nreg signed [31:0] mul3_q;\nreg signed [31:0] mul4_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    mul0_q <= 32'b0;\n    mul1_q <= 32'b0;\n    mul2_q <= 32'b0;\n    mul3_q <= 32'b0;\n    mul4_q <= 32'b0;\nend\nelse\nbegin\n    mul0_q <= mul0_a * mul0_b;\n    mul1_q <= mul1_a * mul1_b;\n    mul2_q <= mul2_a * mul2_b;\n    mul3_q <= mul3_a * mul3_b;\n    mul4_q <= mul4_a * mul4_b;\nend\n\nreg signed [31:0] mul0;\nreg signed [31:0] mul1;\nreg signed [31:0] mul2;\nreg signed [31:0] mul3;\nreg signed [31:0] mul4;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    mul0 <= 32'b0;\n    mul1 <= 32'b0;\n    mul2 <= 32'b0;\n    mul3 <= 32'b0;\n    mul4 <= 32'b0;\nend\nelse\nbegin\n    mul0 <= mul0_q;\n    mul1 <= mul1_q;\n    mul2 <= mul2_q;\n    mul3 <= mul3_q;\n    mul4 <= mul4_q;\nend\n\nreg        out_stg0_valid_q;\nreg [2:0]  out_stg0_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg0_valid_q <= 1'b0;\n    out_stg0_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg0_valid_q <= inport_valid_i;\n    out_stg0_idx_q   <= inport_idx_i;\nend\n\nreg        out_stg1_valid_q;\nreg [2:0]  out_stg1_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg1_valid_q <= 1'b0;\n    out_stg1_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg1_valid_q <= out_stg0_valid_q;\n    out_stg1_idx_q   <= out_stg0_idx_q;\nend\n\nreg        out_stg2_valid_q;\nreg [2:0]  out_stg2_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg2_valid_q <= 1'b0;\n    out_stg2_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg2_valid_q <= out_stg1_valid_q;\n    out_stg2_idx_q   <= out_stg1_idx_q;\nend\n\nreg signed [31:0] o_s5;\nreg signed [31:0] o_s6;\nreg signed [31:0] o_s7;\nreg signed [31:0] o_t0;\nreg signed [31:0] o_t1;\nreg signed [31:0] o_t2;\nreg signed [31:0] o_t3;\nreg signed [31:0] o_t4;\nreg signed [31:0] o_t5;\nreg signed [31:0] o_t6;\nreg signed [31:0] o_t7;\nreg signed [31:0] o_t6_5;\nreg signed [31:0] o_t5_6;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    o_s5   <= 32'b0;\n    o_s6   <= 32'b0;\n    o_s7   <= 32'b0;\n    o_t0   <= 32'b0;\n    o_t1   <= 32'b0;\n    o_t2   <= 32'b0;\n    o_t3   <= 32'b0;\n    o_t4   <= 32'b0;\n    o_t5   <= 32'b0;\n    o_t6   <= 32'b0;\n    o_t7   <= 32'b0;\n    o_t6_5 <= 32'b0;\n    o_t5_6 <= 32'b0;\nend\nelse\nbegin\n    case (out_stg2_idx_q)\n    3'd0:\n    begin\n        o_t3 <= mul0 + mul1; // s3\n    end\n    3'd1:\n    begin\n        o_s7 <= mul0 + mul1;\n        o_s6 <= mul2 + mul3;\n        o_t0 <= mul4;        // s0\n    end\n    3'd2:\n    begin\n        o_t0 <= o_t0 + o_t3; // t0\n        o_t3 <= o_t0 - o_t3; // t3\n        o_t7 <= o_s6 + o_s7;\n    end\n    3'd3:\n    begin\n        o_t4 <= (mul0 - mul1) + (mul2 - mul3);\n    end\n    3'd4:\n    begin\n        o_t0 <= mul0 - mul1; // s4\n        o_s5 <= mul2 - mul3;    \n    end\n    3'd5:\n    begin\n        o_t3 <= mul0 - mul1; // s2\n        o_t4 <= mul4; // s1\n        o_t5 <= o_t0 - o_s5;\n        o_t6 <= o_s7 - o_s6;\n    end\n    3'd6:\n    begin\n        o_t1 <= o_t4 + o_t3;\n        o_t2 <= o_t4 - o_t3;\n        o_t6_5 <= o_t6 - o_t5;\n        o_t5_6 <= o_t5 + o_t6;\n    end\n    default:\n    begin\n        o_s5 <= (o_t6_5 * 181) / 256; // 1/sqrt(2)\n        o_s6 <= (o_t5_6 * 181) / 256; // 1/sqrt(2)\n    end\n    endcase\nend\n\nreg        out_stg3_valid_q;\nreg [2:0]  out_stg3_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    out_stg3_valid_q <= 1'b0;\n    out_stg3_idx_q   <= 3'b0;\nend\nelse\nbegin\n    out_stg3_valid_q <= out_stg2_valid_q;\n    out_stg3_idx_q   <= out_stg2_idx_q;\nend\n\nreg signed [31:0] block_out[0:7];\nreg signed [31:0] block_out_tmp;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_out[0] <= 32'b0;\n    block_out[1] <= 32'b0;\n    block_out[2] <= 32'b0;\n    block_out[3] <= 32'b0;\n    block_out[4] <= 32'b0;\n    block_out[5] <= 32'b0;\n    block_out[6] <= 32'b0;\n    block_out[7] <= 32'b0;\n    block_out_tmp <= 32'b0;\nend\nelse if (out_stg3_valid_q)\nbegin\n    if (out_stg3_idx_q == 3'd3)\n    begin\n        block_out[0] <= ((o_t0 + o_t7) >>> OUT_SHIFT);\n        block_out_tmp <= ((o_t0 - o_t7) >>> OUT_SHIFT); // block_out[7]\n        block_out[3] <= ((o_t3 + o_t4) >>> OUT_SHIFT);\n        block_out[4] <= ((o_t3 - o_t4) >>> OUT_SHIFT);\n    end\n\n    if (out_stg3_idx_q == 3'd6)\n        block_out[7] <= block_out_tmp;\n\n    if (out_stg3_idx_q == 3'd7)\n    begin\n        block_out[2] <= ((o_t2 + o_s5) >>> OUT_SHIFT);\n        block_out[5] <= ((o_t2 - o_s5) >>> OUT_SHIFT);\n        block_out[1] <= ((o_t1 + o_s6) >>> OUT_SHIFT);\n        block_out[6] <= ((o_t1 - o_s6) >>> OUT_SHIFT);\n    end\nend\n\nreg [7:0] valid_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    valid_q  <= 8'b0;\nelse if (img_start_i)\n    valid_q  <= 8'b0;\nelse\n    valid_q <= {valid_q[6:0], out_stg3_valid_q};\n\nreg [5:0] ptr_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    ptr_q <= 6'd0;\nelse if (img_start_i)\n    ptr_q <= 6'd0;\nelse if (outport_valid_o)\n    ptr_q <= ptr_q + 6'd1;\n\nassign outport_valid_o = valid_q[6];\nassign outport_data_o  = block_out[ptr_q[2:0]];\n\n\n\nfunction [5:0] ptr_conv;\n    input [5:0] idx;\n    reg [5:0] out_idx;\nbegin\n    case (idx)\n    6'd0:  out_idx = 6'd0;\n    6'd1:  out_idx = 6'd8;\n    6'd2:  out_idx = 6'd16;\n    6'd3:  out_idx = 6'd24;\n    6'd4:  out_idx = 6'd32;\n    6'd5:  out_idx = 6'd40;\n    6'd6:  out_idx = 6'd48;\n    6'd7:  out_idx = 6'd56;\n    6'd8:  out_idx = 6'd1;\n    6'd9:  out_idx = 6'd9;\n    6'd10:  out_idx = 6'd17;\n    6'd11:  out_idx = 6'd25;\n    6'd12:  out_idx = 6'd33;\n    6'd13:  out_idx = 6'd41;\n    6'd14:  out_idx = 6'd49;\n    6'd15:  out_idx = 6'd57;\n    6'd16:  out_idx = 6'd2;\n    6'd17:  out_idx = 6'd10;\n    6'd18:  out_idx = 6'd18;\n    6'd19:  out_idx = 6'd26;\n    6'd20:  out_idx = 6'd34;\n    6'd21:  out_idx = 6'd42;\n    6'd22:  out_idx = 6'd50;\n    6'd23:  out_idx = 6'd58;\n    6'd24:  out_idx = 6'd3;\n    6'd25:  out_idx = 6'd11;\n    6'd26:  out_idx = 6'd19;\n    6'd27:  out_idx = 6'd27;\n    6'd28:  out_idx = 6'd35;\n    6'd29:  out_idx = 6'd43;\n    6'd30:  out_idx = 6'd51;\n    6'd31:  out_idx = 6'd59;\n    6'd32:  out_idx = 6'd4;\n    6'd33:  out_idx = 6'd12;\n    6'd34:  out_idx = 6'd20;\n    6'd35:  out_idx = 6'd28;\n    6'd36:  out_idx = 6'd36;\n    6'd37:  out_idx = 6'd44;\n    6'd38:  out_idx = 6'd52;\n    6'd39:  out_idx = 6'd60;\n    6'd40:  out_idx = 6'd5;\n    6'd41:  out_idx = 6'd13;\n    6'd42:  out_idx = 6'd21;\n    6'd43:  out_idx = 6'd29;\n    6'd44:  out_idx = 6'd37;\n    6'd45:  out_idx = 6'd45;\n    6'd46:  out_idx = 6'd53;\n    6'd47:  out_idx = 6'd61;\n    6'd48:  out_idx = 6'd6;\n    6'd49:  out_idx = 6'd14;\n    6'd50:  out_idx = 6'd22;\n    6'd51:  out_idx = 6'd30;\n    6'd52:  out_idx = 6'd38;\n    6'd53:  out_idx = 6'd46;\n    6'd54:  out_idx = 6'd54;\n    6'd55:  out_idx = 6'd62;\n    6'd56:  out_idx = 6'd7;\n    6'd57:  out_idx = 6'd15;\n    6'd58:  out_idx = 6'd23;\n    6'd59:  out_idx = 6'd31;\n    6'd60:  out_idx = 6'd39;\n    6'd61:  out_idx = 6'd47;\n    6'd62:  out_idx = 6'd55;\n    default:  out_idx = 6'd63;\n    endcase\n\n    ptr_conv = out_idx;\nend\nendfunction\n\n\nassign outport_idx_o   = ptr_conv(ptr_q);\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_input.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_input\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data_i\n    ,input  [  3:0]  inport_strb_i\n    ,input           inport_last_i\n    ,input           dqt_cfg_accept_i\n    ,input           dht_cfg_accept_i\n    ,input           data_accept_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          img_start_o\n    ,output          img_end_o\n    ,output [ 15:0]  img_width_o\n    ,output [ 15:0]  img_height_o\n    ,output [  1:0]  img_mode_o\n    ,output [  1:0]  img_dqt_table_y_o\n    ,output [  1:0]  img_dqt_table_cb_o\n    ,output [  1:0]  img_dqt_table_cr_o\n    ,output          dqt_cfg_valid_o\n    ,output [  7:0]  dqt_cfg_data_o\n    ,output          dqt_cfg_last_o\n    ,output          dht_cfg_valid_o\n    ,output [  7:0]  dht_cfg_data_o\n    ,output          dht_cfg_last_o\n    ,output          data_valid_o\n    ,output [  7:0]  data_data_o\n    ,output          data_last_o\n);\n\n\n\nwire inport_accept_w;\n\n//-----------------------------------------------------------------\n// Input data read index\n//-----------------------------------------------------------------\nreg [1:0] byte_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    byte_idx_q <= 2'b0;\nelse if (inport_valid_i && inport_accept_w && inport_last_i)\n    byte_idx_q <= 2'b0;\nelse if (inport_valid_i && inport_accept_w)\n    byte_idx_q <= byte_idx_q + 2'd1;\n\n//-----------------------------------------------------------------\n// Data mux\n//-----------------------------------------------------------------\nreg [7:0] data_r;\n\nalways @ *\nbegin\n    data_r = 8'b0;\n\n    case (byte_idx_q)\n    default: data_r = {8{inport_strb_i[0]}} & inport_data_i[7:0];\n    2'd1:    data_r = {8{inport_strb_i[1]}} & inport_data_i[15:8];\n    2'd2:    data_r = {8{inport_strb_i[2]}} & inport_data_i[23:16];\n    2'd3:    data_r = {8{inport_strb_i[3]}} & inport_data_i[31:24];\n    endcase\nend\n\n//-----------------------------------------------------------------\n// Last data\n//-----------------------------------------------------------------\nreg [7:0] last_b_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    last_b_q <= 8'b0;\nelse if (inport_valid_i && inport_accept_w)\n    last_b_q <= inport_last_i ? 8'b0 : data_r;\n\n//-----------------------------------------------------------------\n// Token decoder\n//-----------------------------------------------------------------\nwire token_soi_w  = (last_b_q == 8'hFF && data_r == 8'hd8);\nwire token_sof0_w = (last_b_q == 8'hFF && data_r == 8'hc0);\nwire token_dqt_w  = (last_b_q == 8'hFF && data_r == 8'hdb);\nwire token_dht_w  = (last_b_q == 8'hFF && data_r == 8'hc4);\nwire token_eoi_w  = (last_b_q == 8'hFF && data_r == 8'hd9);\nwire token_sos_w  = (last_b_q == 8'hFF && data_r == 8'hda);\nwire token_pad_w  = (last_b_q == 8'hFF && data_r == 8'h00);\n\n// Unsupported\nwire token_sof2_w = (last_b_q == 8'hFF && data_r == 8'hc2);\nwire token_dri_w  = (last_b_q == 8'hFF && data_r == 8'hdd);\nwire token_rst_w  = (last_b_q == 8'hFF && data_r >= 8'hd0 && data_r <= 8'hd7);\nwire token_app_w  = (last_b_q == 8'hFF && data_r >= 8'he0 && data_r <= 8'hef);\nwire token_com_w  = (last_b_q == 8'hFF && data_r == 8'hfe);\n\n//-----------------------------------------------------------------\n// FSM\n//-----------------------------------------------------------------\nlocalparam STATE_W           = 5;\nlocalparam STATE_IDLE        = 5'd0;\nlocalparam STATE_ACTIVE      = 5'd1;\nlocalparam STATE_UXP_LENH    = 5'd2;\nlocalparam STATE_UXP_LENL    = 5'd3;\nlocalparam STATE_UXP_DATA    = 5'd4;\nlocalparam STATE_DQT_LENH    = 5'd5;\nlocalparam STATE_DQT_LENL    = 5'd6;\nlocalparam STATE_DQT_DATA    = 5'd7;\nlocalparam STATE_DHT_LENH    = 5'd8;\nlocalparam STATE_DHT_LENL    = 5'd9;\nlocalparam STATE_DHT_DATA    = 5'd10;\nlocalparam STATE_IMG_LENH    = 5'd11;\nlocalparam STATE_IMG_LENL    = 5'd12;\nlocalparam STATE_IMG_SOS     = 5'd13;\nlocalparam STATE_IMG_DATA    = 5'd14;\nlocalparam STATE_SOF_LENH    = 5'd15;\nlocalparam STATE_SOF_LENL    = 5'd16;\nlocalparam STATE_SOF_DATA    = 5'd17;\n\nreg [STATE_W-1:0] state_q;\nreg [15:0]        length_q;\n\nreg [STATE_W-1:0] next_state_r;\nalways @ *\nbegin\n    next_state_r = state_q;\n\n    case (state_q)\n    //-------------------------------------------------------------\n    // IDLE - waiting for SOI\n    //-------------------------------------------------------------\n    STATE_IDLE :\n    begin\n        if (token_soi_w)\n            next_state_r = STATE_ACTIVE;\n    end\n    //-------------------------------------------------------------\n    // ACTIVE - waiting for various image markers\n    //-------------------------------------------------------------\n    STATE_ACTIVE :\n    begin\n        if (token_eoi_w)\n            next_state_r = STATE_IDLE;\n        else if (token_dqt_w)\n            next_state_r = STATE_DQT_LENH;\n        else if (token_dht_w)\n            next_state_r = STATE_DHT_LENH;\n        else if (token_sos_w)\n            next_state_r = STATE_IMG_LENH;\n        else if (token_sof0_w)\n            next_state_r = STATE_SOF_LENH;\n        // Unsupported\n        else if (token_sof2_w ||\n                 token_dri_w ||\n                 token_rst_w ||\n                 token_app_w ||\n                 token_com_w)\n            next_state_r = STATE_UXP_LENH;\n\n    end\n    //-------------------------------------------------------------\n    // IMG\n    //-------------------------------------------------------------\n    STATE_IMG_LENH :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_IMG_LENL;\n    end\n    STATE_IMG_LENL :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_IMG_SOS;\n    end\n    STATE_IMG_SOS :\n    begin\n        if (inport_valid_i && length_q <= 16'd1)\n            next_state_r = STATE_IMG_DATA;\n    end\n    STATE_IMG_DATA :\n    begin\n        if (token_eoi_w)\n            next_state_r = STATE_IDLE;\n    end\n    //-------------------------------------------------------------\n    // DQT\n    //-------------------------------------------------------------\n    STATE_DQT_LENH :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_DQT_LENL;\n    end\n    STATE_DQT_LENL :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_DQT_DATA;\n    end\n    STATE_DQT_DATA :\n    begin\n        if (inport_valid_i && inport_accept_w && length_q <= 16'd1)\n            next_state_r = STATE_ACTIVE;\n    end\n    //-------------------------------------------------------------\n    // SOF\n    //-------------------------------------------------------------\n    STATE_SOF_LENH :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_SOF_LENL;\n    end\n    STATE_SOF_LENL :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_SOF_DATA;\n    end\n    STATE_SOF_DATA :\n    begin\n        if (inport_valid_i && inport_accept_w && length_q <= 16'd1)\n            next_state_r = STATE_ACTIVE;\n    end\n    //-------------------------------------------------------------\n    // DHT\n    //-------------------------------------------------------------\n    STATE_DHT_LENH :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_DHT_LENL;\n    end\n    STATE_DHT_LENL :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_DHT_DATA;\n    end\n    STATE_DHT_DATA :\n    begin\n        if (inport_valid_i && inport_accept_w && length_q <= 16'd1)\n            next_state_r = STATE_ACTIVE;\n    end\n    //-------------------------------------------------------------\n    // Unsupported sections - skip\n    //-------------------------------------------------------------\n    STATE_UXP_LENH :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_UXP_LENL;\n    end\n    STATE_UXP_LENL :\n    begin\n        if (inport_valid_i)\n            next_state_r = STATE_UXP_DATA;\n    end\n    STATE_UXP_DATA :\n    begin\n        if (inport_valid_i && inport_accept_w && length_q <= 16'd1)\n            next_state_r = STATE_ACTIVE;\n    end\n    default:\n        ;\n    endcase\n\n    // End of data stream\n    if (inport_valid_i && inport_last_i && inport_accept_w)\n        next_state_r = STATE_IDLE;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    state_q <= STATE_IDLE;\nelse\n    state_q <= next_state_r;\n\n//-----------------------------------------------------------------\n// Length\n//-----------------------------------------------------------------\nalways @ (posedge clk_i )\nif (rst_i)\n    length_q <= 16'b0;\nelse if (state_q == STATE_UXP_LENH || state_q == STATE_DQT_LENH || \n         state_q == STATE_DHT_LENH || state_q == STATE_IMG_LENH ||\n         state_q == STATE_SOF_LENH)\n    length_q <= {data_r, 8'b0};\nelse if (state_q == STATE_UXP_LENL || state_q == STATE_DQT_LENL ||\n         state_q == STATE_DHT_LENL || state_q == STATE_IMG_LENL ||\n         state_q == STATE_SOF_LENL)\n    length_q <= {8'b0, data_r} - 16'd2;\nelse if ((state_q == STATE_UXP_DATA || \n          state_q == STATE_DQT_DATA ||\n          state_q == STATE_DHT_DATA ||\n          state_q == STATE_SOF_DATA ||\n          state_q == STATE_IMG_SOS) && inport_valid_i && inport_accept_w)\n    length_q <= length_q - 16'd1;\n\n//-----------------------------------------------------------------\n// DQT\n//-----------------------------------------------------------------\nassign dqt_cfg_valid_o = (state_q == STATE_DQT_DATA) && inport_valid_i;\nassign dqt_cfg_data_o  = data_r;\nassign dqt_cfg_last_o  = inport_last_i || (length_q == 16'd1);\n\n//-----------------------------------------------------------------\n// DQT\n//-----------------------------------------------------------------\nassign dht_cfg_valid_o = (state_q == STATE_DHT_DATA) && inport_valid_i;\nassign dht_cfg_data_o  = data_r;\nassign dht_cfg_last_o  = inport_last_i || (length_q == 16'd1);\n\n//-----------------------------------------------------------------\n// Image data\n//-----------------------------------------------------------------\nreg       data_valid_q;\nreg [7:0] data_data_q;\nreg       data_last_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_valid_q <= 1'b0;\nelse if (inport_valid_i && data_accept_i)\n    data_valid_q <= (state_q == STATE_IMG_DATA) && (inport_valid_i && ~token_pad_w && ~token_eoi_w);\nelse if (state_q != STATE_IMG_DATA)\n    data_valid_q <= 1'b0;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    data_data_q <= 8'b0;\nelse if (inport_valid_i && data_accept_i)\n    data_data_q <= data_r;\n\nassign data_valid_o = data_valid_q && inport_valid_i && !token_eoi_w;\nassign data_data_o  = data_data_q;\n\n// NOTE: Last is delayed by one cycles (not qualified by data_valid_o)\nassign data_last_o  = data_valid_q && inport_valid_i && token_eoi_w;\n\n//-----------------------------------------------------------------\n// Handshaking\n//-----------------------------------------------------------------\nwire last_byte_w = (byte_idx_q == 2'd3) || inport_last_i;\n\nassign inport_accept_w =  (state_q == STATE_DQT_DATA && dqt_cfg_accept_i) ||\n                          (state_q == STATE_DHT_DATA && dht_cfg_accept_i) ||\n                          (state_q == STATE_IMG_DATA && (data_accept_i || token_pad_w)) ||\n                          (state_q != STATE_DQT_DATA && \n                           state_q != STATE_DHT_DATA && \n                           state_q != STATE_IMG_DATA);\n\nassign inport_accept_o = last_byte_w && inport_accept_w;\n\n//-----------------------------------------------------------------\n// Capture Index\n//-----------------------------------------------------------------\nreg [5:0] idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    idx_q <= 6'b0;\nelse if (inport_valid_i && inport_accept_w && state_q == STATE_SOF_DATA)\n    idx_q <= idx_q + 6'd1;\nelse if (state_q == STATE_SOF_LENH)\n    idx_q <= 6'b0;\n\n//-----------------------------------------------------------------\n// SOF capture\n//-----------------------------------------------------------------\nreg [7:0] img_precision_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_precision_q <= 8'b0;\nelse if (token_sof0_w)\n    img_precision_q <= 8'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd0)\n    img_precision_q <= data_r;\n\nreg [15:0] img_height_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_height_q <= 16'b0;\nelse if (token_sof0_w)\n    img_height_q <= 16'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd1)\n    img_height_q <= {data_r, 8'b0};\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd2)\n    img_height_q <= {img_height_q[15:8], data_r};\n\nassign img_height_o = img_height_q;\n\nreg [15:0] img_width_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_width_q <= 16'b0;\nelse if (token_sof0_w)\n    img_width_q <= 16'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd3)\n    img_width_q <= {data_r, 8'b0};\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd4)\n    img_width_q <= {img_width_q[15:8], data_r};\n\nassign img_width_o  = img_width_q;\n\nreg [7:0] img_num_comp_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_num_comp_q <= 8'b0;\nelse if (token_sof0_w)\n    img_num_comp_q <= 8'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd5)\n    img_num_comp_q <= data_r;\n\nreg [7:0] img_y_factor_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_y_factor_q <= 8'b0;\nelse if (token_sof0_w)\n    img_y_factor_q <= 8'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd7)\n    img_y_factor_q <= data_r;\n\nreg [1:0] img_y_dqt_table_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_y_dqt_table_q <= 2'b0;\nelse if (token_sof0_w)\n    img_y_dqt_table_q <= 2'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd8)\n    img_y_dqt_table_q <= data_r[1:0];\n\nreg [7:0] img_cb_factor_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_cb_factor_q <= 8'b0;\nelse if (token_sof0_w)\n    img_cb_factor_q <= 8'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd10)\n    img_cb_factor_q <= data_r;\n\nreg [1:0] img_cb_dqt_table_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_cb_dqt_table_q <= 2'b0;\nelse if (token_sof0_w)\n    img_cb_dqt_table_q <= 2'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd11)\n    img_cb_dqt_table_q <= data_r[1:0];\n\nreg [7:0] img_cr_factor_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_cr_factor_q <= 8'b0;\nelse if (token_sof0_w)\n    img_cr_factor_q <= 8'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd13)\n    img_cr_factor_q <= data_r;\n\nreg [1:0] img_cr_dqt_table_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_cr_dqt_table_q <= 2'b0;\nelse if (token_sof0_w)\n    img_cr_dqt_table_q <= 2'b0;\nelse if (state_q == STATE_SOF_DATA && idx_q == 6'd14)\n    img_cr_dqt_table_q <= data_r[1:0];\n\nassign img_dqt_table_y_o  = img_y_dqt_table_q;\nassign img_dqt_table_cb_o = img_cb_dqt_table_q;\nassign img_dqt_table_cr_o = img_cr_dqt_table_q;\n\nwire [3:0] y_horiz_factor_w  = img_y_factor_q[7:4];\nwire [3:0] y_vert_factor_w   = img_y_factor_q[3:0];\nwire [3:0] cb_horiz_factor_w = img_cb_factor_q[7:4];\nwire [3:0] cb_vert_factor_w  = img_cb_factor_q[3:0];\nwire [3:0] cr_horiz_factor_w = img_cr_factor_q[7:4];\nwire [3:0] cr_vert_factor_w  = img_cr_factor_q[3:0];\n\nlocalparam JPEG_MONOCHROME  = 2'd0;\nlocalparam JPEG_YCBCR_444   = 2'd1;\nlocalparam JPEG_YCBCR_420   = 2'd2;\nlocalparam JPEG_UNSUPPORTED = 2'd3;\n\nreg [1:0] img_mode_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    img_mode_q <= JPEG_UNSUPPORTED;\nelse if (token_sof0_w)\n    img_mode_q <= JPEG_UNSUPPORTED;\nelse if (state_q == STATE_SOF_DATA && next_state_r == STATE_ACTIVE)\nbegin\n    // Single component (Y)\n    if (img_num_comp_q == 8'd1)\n        img_mode_q <= JPEG_MONOCHROME;\n    // Colour image (YCbCr)\n    else if (img_num_comp_q == 8'd3)\n    begin\n        if (y_horiz_factor_w  == 4'd1 && y_vert_factor_w  == 4'd1 &&\n            cb_horiz_factor_w == 4'd1 && cb_vert_factor_w == 4'd1 &&\n            cr_horiz_factor_w == 4'd1 && cr_vert_factor_w == 4'd1)\n            img_mode_q <= JPEG_YCBCR_444;\n        else if (y_horiz_factor_w  == 4'd2 && y_vert_factor_w  == 4'd2 &&\n                 cb_horiz_factor_w == 4'd1 && cb_vert_factor_w == 4'd1 &&\n                 cr_horiz_factor_w == 4'd1 && cr_vert_factor_w == 4'd1)\n            img_mode_q <= JPEG_YCBCR_420;\n    end\nend\n\nreg eof_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    eof_q <= 1'b1;\nelse if (state_q == STATE_IDLE && token_soi_w)\n    eof_q <= 1'b0;\nelse if (img_end_o)\n    eof_q <= 1'b1;\n\nreg start_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    start_q <= 1'b0;\nelse if (inport_valid_i & token_sos_w)\n    start_q <= 1'b0;\nelse if (state_q == STATE_IDLE && token_soi_w)\n    start_q <= 1'b1;    \n\nassign img_start_o = start_q;\nassign img_end_o   = eof_q | (inport_valid_i & token_eoi_w);\nassign img_mode_o  = img_mode_q;\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_mcu_id.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_mcu_id\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input  [ 15:0]  img_width_i\n    ,input  [ 15:0]  img_height_i\n    ,input  [  1:0]  img_mode_i\n    ,input           start_of_block_i\n    ,input           end_of_block_i\n\n    // Outputs\n    ,output [ 31:0]  block_id_o\n    ,output [  1:0]  block_type_o\n    ,output          end_of_image_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Block Type (Y, Cb, Cr)\n//-----------------------------------------------------------------\nlocalparam JPEG_MONOCHROME  = 2'd0;\nlocalparam JPEG_YCBCR_444   = 2'd1;\nlocalparam JPEG_YCBCR_420   = 2'd2;\nlocalparam JPEG_UNSUPPORTED = 2'd3;\n\nlocalparam BLOCK_Y          = 2'd0;\nlocalparam BLOCK_CB         = 2'd1;\nlocalparam BLOCK_CR         = 2'd2;\nlocalparam BLOCK_EOF        = 2'd3;\n\nreg [1:0] block_type_q;\nreg [2:0] type_idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_type_q <= BLOCK_Y;\n    type_idx_q   <= 3'd0;\nend\nelse if (img_start_i)\nbegin\n    block_type_q <= BLOCK_Y;\n    type_idx_q   <= 3'd0;\nend\nelse if (start_of_block_i && end_of_image_o)\nbegin\n    block_type_q <= BLOCK_EOF;\n    type_idx_q   <= 3'd0;\nend\nelse if (img_mode_i == JPEG_MONOCHROME)\n    block_type_q <= BLOCK_Y;\nelse if (img_mode_i == JPEG_YCBCR_444 && end_of_block_i)\nbegin\n    if (block_type_q == BLOCK_CR)\n        block_type_q <= BLOCK_Y;\n    else\n        block_type_q <= block_type_q + 2'd1;\nend\nelse if (img_mode_i == JPEG_YCBCR_420 && end_of_block_i)\nbegin\n    type_idx_q <= type_idx_q + 3'd1;\n\n    case (type_idx_q)\n    default:\n        block_type_q <= BLOCK_Y;\n    3'd3:\n        block_type_q <= BLOCK_CB;\n    3'd4:\n        block_type_q <= BLOCK_CR;\n    3'd5:\n    begin\n        block_type_q <= BLOCK_Y;\n        type_idx_q   <= 3'd0;\n    end\n    endcase\nend\n\n//-----------------------------------------------------------------\n// Block index\n//-----------------------------------------------------------------\nwire [15:0] width_rnd_w   = ((img_width_i+7) / 8) * 8;\nwire [15:0] block_x_max_w = width_rnd_w / 8;\nwire [15:0] img_w_div4_w  = width_rnd_w / 4;\n\nreg  [15:0] block_x_q;\nreg  [15:0] block_y_q;\n\nreg  [15:0] x_idx_q;\nreg  [15:0] y_idx_q;\n\nwire [15:0] block_x_next_w = block_x_q + 16'd1;\n\nreg         end_of_image_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    block_x_q      <= 16'b0;\n    block_y_q      <= 16'b0;\n    x_idx_q        <= 16'b0;\n    y_idx_q        <= 16'b0;\n    end_of_image_q <= 1'b0;\nend\nelse if (img_start_i)\nbegin\n    block_x_q      <= 16'b0;\n    block_y_q      <= 16'b0;\n    x_idx_q        <= 16'b0;\n    y_idx_q        <= 16'b0;\n    end_of_image_q <= 1'b0;\nend\nelse if (end_of_block_i && ((img_mode_i == JPEG_MONOCHROME) || (img_mode_i == JPEG_YCBCR_444 && block_type_q == BLOCK_CR)))\nbegin\n    if (block_x_next_w == block_x_max_w)\n    begin\n        block_x_q <= 16'b0;\n        block_y_q <= block_y_q + 16'd1;\n    end\n    else\n        block_x_q <= block_x_next_w;\n\n    if (img_end_i && block_x_next_w == block_x_max_w)\n        end_of_image_q <= 1'b1;\nend\nelse if (start_of_block_i && img_mode_i == JPEG_YCBCR_420 && block_type_q == BLOCK_Y)\nbegin\n    block_x_q <= ({x_idx_q[15:2], 2'b0} / 2) + (type_idx_q[0] ? 16'd1 : 16'd0);\n    block_y_q <= y_idx_q + (type_idx_q[1] ? 16'd1 : 16'd0);\n\n    // Y component\n    if (type_idx_q < 3'd4)\n    begin\n        if ((x_idx_q + 16'd1) == img_w_div4_w)\n        begin\n            x_idx_q <= 16'd0;\n            y_idx_q <= y_idx_q + 16'd2;\n        end\n        else\n            x_idx_q <= x_idx_q + 16'd1;\n    end\nend\nelse if (start_of_block_i && img_mode_i == JPEG_YCBCR_420 && block_type_q == BLOCK_CR)\nbegin\n    if (img_end_i && block_x_next_w == block_x_max_w)\n        end_of_image_q <= 1'b1;\nend\n\n//-----------------------------------------------------------------\n// Outputs\n//-----------------------------------------------------------------\n// Block ID (type=y|cb|cr, y pos, x pos)\nassign block_id_o     = {block_type_q, block_y_q[13:0], block_x_q};\nassign block_type_o   = block_type_q;\n\n// End of image detection\nassign end_of_image_o = end_of_image_q;\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_mcu_proc.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_mcu_proc\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input  [ 15:0]  img_width_i\n    ,input  [ 15:0]  img_height_i\n    ,input  [  1:0]  img_mode_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data_i\n    ,input           inport_last_i\n    ,input           lookup_valid_i\n    ,input  [  4:0]  lookup_width_i\n    ,input  [  7:0]  lookup_value_i\n    ,input           outport_blk_space_i\n\n    // Outputs\n    ,output [  5:0]  inport_pop_o\n    ,output          lookup_req_o\n    ,output [  1:0]  lookup_table_o\n    ,output [ 15:0]  lookup_input_o\n    ,output          outport_valid_o\n    ,output [ 15:0]  outport_data_o\n    ,output [  5:0]  outport_idx_o\n    ,output [ 31:0]  outport_id_o\n    ,output          outport_eob_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Block Type (Y, Cb, Cr)\n//-----------------------------------------------------------------\nwire start_block_w;\nwire next_block_w;\nwire end_of_image_w;\n\nlocalparam JPEG_MONOCHROME  = 2'd0;\nlocalparam JPEG_YCBCR_444   = 2'd1;\nlocalparam JPEG_YCBCR_420   = 2'd2;\nlocalparam JPEG_UNSUPPORTED = 2'd3;\n\nlocalparam BLOCK_Y          = 2'd0;\nlocalparam BLOCK_CB         = 2'd1;\nlocalparam BLOCK_CR         = 2'd2;\nlocalparam BLOCK_EOF        = 2'd3;\n\nwire [1:0] block_type_w;\n\nlocalparam DHT_TABLE_Y_DC_IDX  = 2'd0;\nlocalparam DHT_TABLE_Y_AC_IDX  = 2'd1;\nlocalparam DHT_TABLE_CX_DC_IDX = 2'd2;\nlocalparam DHT_TABLE_CX_AC_IDX = 2'd3;\n\njpeg_mcu_id\nu_id\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.img_start_i(img_start_i)\n    ,.img_end_i(img_end_i)\n    ,.img_width_i(img_width_i)\n    ,.img_height_i(img_height_i)\n    ,.img_mode_i(img_mode_i)\n\n    ,.start_of_block_i(start_block_w)\n    ,.end_of_block_i(next_block_w)\n\n    ,.block_id_o(outport_id_o)\n    ,.block_type_o(block_type_w)\n    ,.end_of_image_o(end_of_image_w)\n);\n\n//-----------------------------------------------------------------\n// FSM\n//-----------------------------------------------------------------\nlocalparam STATE_W           = 5;\nlocalparam STATE_IDLE        = 5'd0;\nlocalparam STATE_FETCH_WORD  = 5'd1;\nlocalparam STATE_HUFF_LOOKUP = 5'd2;\nlocalparam STATE_OUTPUT      = 5'd3;\nlocalparam STATE_EOB         = 5'd4;\nlocalparam STATE_EOF         = 5'd5;\n\nreg [STATE_W-1:0] state_q;\nreg [STATE_W-1:0] next_state_r;\n\nreg [7:0]         code_bits_q;\nreg [7:0]         coeff_idx_q;\n\nalways @ *\nbegin\n    next_state_r = state_q;\n\n    case (state_q)\n    STATE_IDLE:\n    begin\n        if (end_of_image_w && outport_blk_space_i)\n            next_state_r = STATE_EOF;\n        else if (inport_valid_i && outport_blk_space_i)\n            next_state_r = STATE_FETCH_WORD;\n    end\n    STATE_FETCH_WORD:\n    begin\n        if (coeff_idx_q >= 8'd63)\n            next_state_r = STATE_EOB;\n        else if (inport_valid_i)\n            next_state_r = STATE_HUFF_LOOKUP;\n    end\n    STATE_HUFF_LOOKUP:\n    begin\n        if (lookup_valid_i)\n            next_state_r = STATE_OUTPUT;\n    end\n    STATE_OUTPUT:\n    begin\n        next_state_r = STATE_FETCH_WORD;\n    end\n    STATE_EOB:\n    begin\n        next_state_r = STATE_IDLE;\n    end\n    STATE_EOF:\n    begin\n        if (!img_end_i)\n            next_state_r = STATE_IDLE;\n    end\n    default : ;\n    endcase\n\n    if (img_start_i)\n        next_state_r = STATE_IDLE;\nend\n\nassign start_block_w = (state_q == STATE_IDLE && next_state_r != STATE_IDLE);\nassign next_block_w  = (state_q == STATE_EOB);\n\nalways @ (posedge clk_i )\nif (rst_i)\n    state_q <= STATE_IDLE;\nelse\n    state_q <= next_state_r;\n\nreg first_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    first_q <= 1'b1;\nelse if (state_q == STATE_IDLE)\n    first_q <= 1'b1;\nelse if (state_q == STATE_OUTPUT)\n    first_q <= 1'b0;\n\n//-----------------------------------------------------------------\n// Huffman code lookup stash\n//-----------------------------------------------------------------\nreg [7:0] code_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    code_q <= 8'b0;\nelse if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i)\n    code_q <= lookup_value_i;\n\n//-----------------------------------------------------------------\n// code[3:0] = width of symbol\n//-----------------------------------------------------------------\nalways @ (posedge clk_i )\nif (rst_i)\n    code_bits_q <= 8'b0;\nelse if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i)\n    code_bits_q <= {4'b0, lookup_value_i[3:0]};\n\n//-----------------------------------------------------------------\n// Lookup width flops\n//-----------------------------------------------------------------\nreg [4:0] lookup_width_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    lookup_width_q <= 5'b0;\nelse if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i)\n    lookup_width_q <= lookup_width_i;\n\n//-----------------------------------------------------------------\n// Data for coefficient (remainder from Huffman lookup)\n//-----------------------------------------------------------------\nreg [15:0] input_data_q;\n\nwire [31:0] input_shift_w = inport_data_i >> (5'd16 - lookup_width_i);\n\nalways @ (posedge clk_i )\nif (rst_i)\n    input_data_q <= 16'b0;\n// Use remaining data for actual coeffecient\nelse if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i)\n    input_data_q <= input_shift_w[15:0];\n\n//-----------------------------------------------------------------\n// Bit buffer pop\n//-----------------------------------------------------------------\nreg [5:0]  pop_bits_r;\n\nwire [4:0] coef_bits_w = {1'b0, code_q[3:0]};\n\nalways @ *\nbegin\n    pop_bits_r = 6'b0;\n\n    case (state_q)\n    STATE_OUTPUT:\n    begin\n        // DC coefficient\n        if (coeff_idx_q == 8'd0)\n            pop_bits_r = {1'b0, lookup_width_q} + coef_bits_w;\n        // End of block or ZRL (no coefficient)\n        else if (code_q == 8'b0 || code_q == 8'hF0)\n            pop_bits_r = {1'b0, lookup_width_q};\n        else\n            pop_bits_r = {1'b0, lookup_width_q} + coef_bits_w;\n    end\n    default : ;\n    endcase\nend\n\nassign lookup_req_o   = (state_q == STATE_FETCH_WORD) & inport_valid_i;\nassign lookup_input_o = inport_data_i[31:16];\nassign inport_pop_o   = pop_bits_r;\n\nreg [1:0] lookup_table_r;\nalways @ *\nbegin\n    lookup_table_r = DHT_TABLE_Y_DC_IDX;\n\n    if (first_q) // (coeff_idx_q == 8'd0)\n    begin\n        if (block_type_w == BLOCK_Y)\n            lookup_table_r = DHT_TABLE_Y_DC_IDX;\n        else\n            lookup_table_r = DHT_TABLE_CX_DC_IDX;\n    end\n    else\n    begin\n        if (block_type_w == BLOCK_Y)\n            lookup_table_r = DHT_TABLE_Y_AC_IDX;\n        else\n            lookup_table_r = DHT_TABLE_CX_AC_IDX;\n    end\nend\nassign lookup_table_o = lookup_table_r;\n\n//-----------------------------------------------------------------------------\n// decode_number: Extract number from code / width\n//-----------------------------------------------------------------------------\nfunction [15:0] decode_number;\n    input [15:0] w;\n    input [4:0]  bits;\n    reg signed [15:0] code;\nbegin\n    code = w;\n\n    if ((code & (1<<(bits - 5'd1))) == 16'b0 && bits != 5'd0)\n    begin\n        code = (code | ((~0) << bits)) + 1;\n    end\n    decode_number = code;\nend\nendfunction\n\n//-----------------------------------------------------------------\n// Previous DC coeffecient\n//-----------------------------------------------------------------\nwire [1:0] comp_idx_w = block_type_w;\n\nreg [15:0] prev_dc_coeff_q[3:0];\nreg [15:0] dc_coeff_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    prev_dc_coeff_q[0] <= 16'b0;\n    prev_dc_coeff_q[1] <= 16'b0;\n    prev_dc_coeff_q[2] <= 16'b0;\n    prev_dc_coeff_q[3] <= 16'b0; // X\nend\nelse if (img_start_i)\nbegin\n    prev_dc_coeff_q[0] <= 16'b0;\n    prev_dc_coeff_q[1] <= 16'b0;\n    prev_dc_coeff_q[2] <= 16'b0;\n    prev_dc_coeff_q[3] <= 16'b0; // X\nend\nelse if (state_q == STATE_EOB)\n    prev_dc_coeff_q[comp_idx_w] <= dc_coeff_q;\n\n//-----------------------------------------------------------------\n// coeff\n//-----------------------------------------------------------------\nreg [15:0] coeff_r;\n\nalways @ *\nbegin\n    if (coeff_idx_q == 8'b0)\n        coeff_r = decode_number(input_data_q >> (16 - coef_bits_w), coef_bits_w) + prev_dc_coeff_q[comp_idx_w];\n    else\n        coeff_r = decode_number(input_data_q >> (16 - coef_bits_w), coef_bits_w);\nend\n\n//-----------------------------------------------------------------\n// dc_coeff\n//-----------------------------------------------------------------\nalways @ (posedge clk_i )\nif (rst_i)\n    dc_coeff_q <= 16'b0;\nelse if (state_q == STATE_OUTPUT && coeff_idx_q == 8'b0)\n    dc_coeff_q <= coeff_r;\n\n//-----------------------------------------------------------------\n// DC / AC coeff\n//-----------------------------------------------------------------\nreg [15:0] coeff_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    coeff_q <= 16'b0;\nelse if (state_q == STATE_OUTPUT)\n    coeff_q <= coeff_r;\n\n//-----------------------------------------------------------------\n// Coeffecient index\n//-----------------------------------------------------------------\nalways @ (posedge clk_i )\nif (rst_i)\n    coeff_idx_q <= 8'b0;\nelse if (state_q == STATE_EOB || img_start_i)\n    coeff_idx_q <= 8'b0;\nelse if (state_q == STATE_FETCH_WORD && !first_q && inport_valid_i)\n    coeff_idx_q <= coeff_idx_q + 8'd1;\nelse if (state_q == STATE_OUTPUT)\nbegin\n    // DC\n    if (coeff_idx_q == 8'b0)\n        ;\n    // AC\n    else\n    begin\n        // End of block\n        if (code_q == 8'b0)\n            coeff_idx_q <= 8'd64;\n        // ZRL - 16 zeros\n        else if (code_q == 8'hF0)\n            coeff_idx_q <= coeff_idx_q + 8'd15;\n        // RLE number zeros (0 - 15)\n        else\n            coeff_idx_q <= coeff_idx_q + {4'b0, code_q[7:4]};\n    end\nend\n\n//-----------------------------------------------------------------\n// Output push\n//-----------------------------------------------------------------\nreg push_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    push_q <= 1'b0;\nelse if (state_q == STATE_OUTPUT || state_q == STATE_EOF)\n    push_q <= 1'b1;\nelse\n    push_q <= 1'b0;\n\nassign outport_valid_o = push_q && (coeff_idx_q < 8'd64);\nassign outport_data_o  = coeff_q;\nassign outport_idx_o   = coeff_idx_q[5:0];\nassign outport_eob_o   = (state_q == STATE_EOB) || \n                         (state_q == STATE_EOF && push_q);\n\n`ifdef verilator\nfunction get_valid; /*verilator public*/\nbegin\n    get_valid = outport_valid_o && block_type_w != BLOCK_EOF;\nend\nendfunction\nfunction [5:0] get_sample_idx; /*verilator public*/\nbegin\n    get_sample_idx = outport_idx_o;\nend\nendfunction\nfunction [15:0] get_sample; /*verilator public*/\nbegin\n    get_sample = outport_data_o;\nend\nendfunction\n\nfunction [5:0] get_bitbuffer_pop; /*verilator public*/\nbegin\n    get_bitbuffer_pop = inport_pop_o;\nend\nendfunction\n\nfunction get_dht_valid; /*verilator public*/\nbegin\n    get_dht_valid = lookup_valid_i && (state_q == STATE_HUFF_LOOKUP);\nend\nendfunction\nfunction [4:0] get_dht_width; /*verilator public*/\nbegin\n    get_dht_width = lookup_width_i;\nend\nendfunction\nfunction [7:0] get_dht_value; /*verilator public*/\nbegin\n    get_dht_value = lookup_value_i;\nend\nendfunction\n`endif\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_output.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_output\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input           img_start_i\n    ,input           img_end_i\n    ,input  [ 15:0]  img_width_i\n    ,input  [ 15:0]  img_height_i\n    ,input  [  1:0]  img_mode_i\n    ,input           inport_valid_i\n    ,input  [ 31:0]  inport_data_i\n    ,input  [  5:0]  inport_idx_i\n    ,input  [ 31:0]  inport_id_i\n    ,input           outport_accept_i\n\n    // Outputs\n    ,output          inport_accept_o\n    ,output          outport_valid_o\n    ,output [ 15:0]  outport_width_o\n    ,output [ 15:0]  outport_height_o\n    ,output [ 15:0]  outport_pixel_x_o\n    ,output [ 15:0]  outport_pixel_y_o\n    ,output [  7:0]  outport_pixel_r_o\n    ,output [  7:0]  outport_pixel_g_o\n    ,output [  7:0]  outport_pixel_b_o\n    ,output          idle_o\n);\n\n\n\nlocalparam BLOCK_Y          = 2'd0;\nlocalparam BLOCK_CB         = 2'd1;\nlocalparam BLOCK_CR         = 2'd2;\nlocalparam BLOCK_EOF        = 2'd3;\n\nlocalparam JPEG_MONOCHROME  = 2'd0;\nlocalparam JPEG_YCBCR_444   = 2'd1;\nlocalparam JPEG_YCBCR_420   = 2'd2;\nlocalparam JPEG_UNSUPPORTED = 2'd3;\n\nreg valid_r;\nwire output_space_w = (!outport_valid_o || outport_accept_i);\n\n//-----------------------------------------------------------------\n// FIFO: Y\n//-----------------------------------------------------------------\nwire               y_valid_w;\nwire signed [31:0] y_value_w;\nwire               y_pop_w;\nwire [31:0]        y_level_w;\n\njpeg_output_y_ram\nu_ram_y\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.flush_i(img_start_i)\n    ,.level_o(y_level_w)\n\n    ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_Y || inport_id_i[31:30] == BLOCK_EOF))\n    ,.wr_idx_i(inport_idx_i)\n    ,.data_in_i(inport_data_i)\n\n    ,.valid_o(y_valid_w)\n    ,.data_out_o(y_value_w)\n    ,.pop_i(y_pop_w)\n);\n\n//-----------------------------------------------------------------\n// FIFO: Cb\n//-----------------------------------------------------------------\nwire               cb_valid_w;\nwire signed [31:0] cb_value_w;\nwire               cb_pop_w;\nwire [31:0]        cb_level_w;\n\njpeg_output_cx_ram\nu_ram_cb\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.flush_i(img_start_i)\n    ,.level_o(cb_level_w)\n    ,.mode420_i(img_mode_i == JPEG_YCBCR_420)\n\n    ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_CB || inport_id_i[31:30] == BLOCK_EOF))\n    ,.wr_idx_i(inport_idx_i)\n    ,.data_in_i(inport_data_i)\n\n    ,.valid_o(cb_valid_w)\n    ,.data_out_o(cb_value_w)\n    ,.pop_i(cb_pop_w)\n);\n\n//-----------------------------------------------------------------\n// FIFO: Cr\n//-----------------------------------------------------------------\nwire               cr_valid_w;\nwire signed [31:0] cr_value_w;\nwire               cr_pop_w;\nwire [31:0]        cr_level_w;\n\njpeg_output_cx_ram\nu_ram_cr\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n\n    ,.flush_i(img_start_i)\n    ,.level_o(cr_level_w)\n    ,.mode420_i(img_mode_i == JPEG_YCBCR_420)\n\n    ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_CR || inport_id_i[31:30] == BLOCK_EOF))\n    ,.wr_idx_i(inport_idx_i)\n    ,.data_in_i(inport_data_i)\n\n    ,.valid_o(cr_valid_w)\n    ,.data_out_o(cr_value_w)\n    ,.pop_i(cr_pop_w)\n);\n\n//-----------------------------------------------------------------\n// FIFO: Info\n//-----------------------------------------------------------------\nwire        id_valid_w;\nwire [31:0] id_value_w;\nwire        id_pop_w;\n\njpeg_output_fifo\n#(\n     .WIDTH(32)\n    ,.DEPTH(8)\n    ,.ADDR_W(3)\n)\nu_info\n(\n     .clk_i(clk_i)\n    ,.rst_i(rst_i)\n    ,.flush_i(img_start_i)\n \n    ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_Y || inport_id_i[31:30] == BLOCK_EOF) && inport_idx_i == 6'd0)\n    ,.data_in_i(inport_id_i)\n    ,.accept_o()\n\n    ,.valid_o(id_valid_w)\n    ,.data_out_o(id_value_w)\n    ,.pop_i(id_pop_w)\n);\n\nassign inport_accept_o   = (y_level_w <= 32'd384 && cr_level_w <= 32'd128) | idle_o;\n\n//-----------------------------------------------------------------\n// Block counter (0 - 63)\n//-----------------------------------------------------------------\nreg [5:0] idx_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    idx_q <= 6'b0;\nelse if (img_start_i)\n    idx_q <= 6'b0;\nelse if (valid_r && output_space_w)\n    idx_q <= idx_q + 6'd1;\n\n//-----------------------------------------------------------------\n// Subsampling counter (420 chroma subsampling)\n//-----------------------------------------------------------------\nreg [1:0] subsmpl_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    subsmpl_q <= 2'b0;\nelse if (img_start_i)\n    subsmpl_q <= 2'b0;\nelse if (valid_r && output_space_w && img_mode_i == JPEG_YCBCR_420 && idx_q == 6'd63)\n    subsmpl_q <= subsmpl_q + 2'd1;\n\n//-----------------------------------------------------------------\n// YUV -> RGB\n//-----------------------------------------------------------------\nreg active_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    active_q <= 1'b0;\nelse if (img_start_i)\n    active_q <= 1'b0;\nelse if (!active_q)\nbegin\n    if (img_mode_i == JPEG_MONOCHROME)\n        active_q <= (y_level_w >= 32'd64);\n    else if (img_mode_i == JPEG_YCBCR_444)\n        active_q <= (y_level_w >= 32'd64) && (cb_level_w >= 32'd64) && (cr_level_w >= 32'd64);\n    else if (subsmpl_q != 2'b0) // 420\n        active_q <= 1'b1;\n    else // 420\n        active_q <= (y_level_w >= 32'd256) && (cb_level_w >= 32'd256) && (cr_level_w >= 32'd256);\nend\nelse if (valid_r && output_space_w && idx_q == 6'd63)\n    active_q <= 1'b0;\n\nreg signed [31:0] r_conv_r;\nreg signed [31:0] g_conv_r;\nreg signed [31:0] b_conv_r;\n\nwire signed [31:0] cr_1_402_w = (cr_value_w * 5743) >>> 12; // cr_value_w * 1.402\nwire signed [31:0] cr_0_714_w = (cr_value_w * 2925) >>> 12; // cr_value_w * 0.71414\nwire signed [31:0] cb_0_344_w = (cb_value_w * 1410) >>> 12; // cb_value_w * 0.34414\nwire signed [31:0] cb_1_772_w = (cb_value_w * 7258) >>> 12; // cb_value_w * 1.772\n\nalways @ *\nbegin\n    valid_r  = active_q;\n    r_conv_r = 32'b0;\n    g_conv_r = 32'b0;\n    b_conv_r = 32'b0;\n\n    if (img_mode_i == JPEG_MONOCHROME)\n    begin\n        r_conv_r = 128 + y_value_w;\n        g_conv_r = 128 + y_value_w;\n        b_conv_r = 128 + y_value_w;\n    end\n    else// if (img_mode_i == JPEG_YCBCR_444)\n    begin\n        r_conv_r = 128 + y_value_w + cr_1_402_w;\n        g_conv_r = 128 + y_value_w - cb_0_344_w - cr_0_714_w;\n        b_conv_r = 128 + y_value_w + cb_1_772_w;\n    end\nend\n\nassign y_pop_w  = output_space_w && active_q;\nassign cb_pop_w = output_space_w && active_q;\nassign cr_pop_w = output_space_w && active_q;\nassign id_pop_w = output_space_w && (idx_q == 6'd63);\n\n//-----------------------------------------------------------------\n// Outputs\n//-----------------------------------------------------------------\nreg        valid_q;\nreg [15:0] pixel_x_q;\nreg [15:0] pixel_y_q;\nreg [7:0]  pixel_r_q;\nreg [7:0]  pixel_g_q;\nreg [7:0]  pixel_b_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    valid_q <= 1'b0;\nelse if (output_space_w)\n    valid_q <= valid_r && (id_value_w[31:30] != BLOCK_EOF);\n\nwire [31:0] x_start_w = {13'b0, id_value_w[15:0],3'b0};\nwire [31:0] y_start_w = {15'b0, id_value_w[29:16],3'b0};\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    pixel_x_q <= 16'b0;\n    pixel_y_q <= 16'b0;\nend\nelse if (output_space_w)\nbegin\n    /* verilator lint_off WIDTH */\n    pixel_x_q <= x_start_w + (idx_q % 8);\n    pixel_y_q <= y_start_w + (idx_q / 8);\n    /* verilator lint_on WIDTH */\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    pixel_r_q <= 8'b0;\n    pixel_g_q <= 8'b0;\n    pixel_b_q <= 8'b0;\nend\nelse if (output_space_w)\nbegin\n    pixel_r_q <= (|r_conv_r[31:8]) ? (r_conv_r[31:24] ^ 8'hff) : r_conv_r[7:0];\n    pixel_g_q <= (|g_conv_r[31:8]) ? (g_conv_r[31:24] ^ 8'hff) : g_conv_r[7:0];\n    pixel_b_q <= (|b_conv_r[31:8]) ? (b_conv_r[31:24] ^ 8'hff) : b_conv_r[7:0];\nend\n\nassign outport_valid_o   = valid_q;\nassign outport_pixel_x_o = pixel_x_q;\nassign outport_pixel_y_o = pixel_y_q;\nassign outport_width_o   = img_width_i;\nassign outport_height_o  = img_height_i;\nassign outport_pixel_r_o = pixel_r_q;\nassign outport_pixel_g_o = pixel_g_q;\nassign outport_pixel_b_o = pixel_b_q;\n\n//-----------------------------------------------------------------\n// Idle\n//-----------------------------------------------------------------\nreg idle_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    idle_q <= 1'b1;\nelse if (img_start_i)\n    idle_q <= 1'b0;\nelse if (id_valid_w && id_value_w[31:30] == BLOCK_EOF)\n    idle_q <= 1'b1;\n\nassign idle_o = idle_q;\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_output_cx_ram.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_output_cx_ram\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input  [  5:0]  wr_idx_i\n    ,input  [ 31:0]  data_in_i\n    ,input           push_i\n    ,input           mode420_i\n    ,input           pop_i\n    ,input           flush_i\n\n    // Outputs\n    ,output [ 31:0]  data_out_o\n    ,output          valid_o\n    ,output [ 31:0]  level_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Registers\n//-----------------------------------------------------------------\nreg [7:0]   rd_ptr_q;\nreg [7:0]   wr_ptr_q;\n\n//-----------------------------------------------------------------\n// Write Side\n//-----------------------------------------------------------------\nwire [7:0] write_next_w = wr_ptr_q + 8'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    wr_ptr_q <= 8'b0;\nelse if (flush_i)\n    wr_ptr_q <= 8'b0;\n// Push\nelse if (push_i)\n    wr_ptr_q <= write_next_w;\n\n//-----------------------------------------------------------------\n// Read Side\n//-----------------------------------------------------------------\nwire read_ok_w = (level_o > 32'd1);\nreg  rd_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_q <= 1'b0;\nelse if (flush_i)\n    rd_q <= 1'b0;\nelse\n    rd_q <= read_ok_w;\n\nwire [7:0] rd_ptr_next_w = rd_ptr_q + 8'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_ptr_q <= 8'b0;\nelse if (flush_i)\n    rd_ptr_q <= 8'b0;\nelse if (read_ok_w && ((!valid_o) || (valid_o && pop_i)))\n    rd_ptr_q <= rd_ptr_next_w;\n\n//-------------------------------------------------------------------\n// Chroma subsampling (420) sample addressing\n//-------------------------------------------------------------------\nreg [7:0] cx_idx_q;\n\nreg [5:0] cx_rd_ptr_r;\n\nalways @ *\nbegin\n    case (cx_idx_q)\n    8'd0: cx_rd_ptr_r = 6'd0;\n    8'd1: cx_rd_ptr_r = 6'd1;\n    8'd2: cx_rd_ptr_r = 6'd1;\n    8'd3: cx_rd_ptr_r = 6'd2;\n    8'd4: cx_rd_ptr_r = 6'd2;\n    8'd5: cx_rd_ptr_r = 6'd3;\n    8'd6: cx_rd_ptr_r = 6'd3;\n    8'd7: cx_rd_ptr_r = 6'd0;\n    8'd8: cx_rd_ptr_r = 6'd0;\n    8'd9: cx_rd_ptr_r = 6'd1;\n    8'd10: cx_rd_ptr_r = 6'd1;\n    8'd11: cx_rd_ptr_r = 6'd2;\n    8'd12: cx_rd_ptr_r = 6'd2;\n    8'd13: cx_rd_ptr_r = 6'd3;\n    8'd14: cx_rd_ptr_r = 6'd3;\n    8'd15: cx_rd_ptr_r = 6'd8;\n    8'd16: cx_rd_ptr_r = 6'd8;\n    8'd17: cx_rd_ptr_r = 6'd9;\n    8'd18: cx_rd_ptr_r = 6'd9;\n    8'd19: cx_rd_ptr_r = 6'd10;\n    8'd20: cx_rd_ptr_r = 6'd10;\n    8'd21: cx_rd_ptr_r = 6'd11;\n    8'd22: cx_rd_ptr_r = 6'd11;\n    8'd23: cx_rd_ptr_r = 6'd8;\n    8'd24: cx_rd_ptr_r = 6'd8;\n    8'd25: cx_rd_ptr_r = 6'd9;\n    8'd26: cx_rd_ptr_r = 6'd9;\n    8'd27: cx_rd_ptr_r = 6'd10;\n    8'd28: cx_rd_ptr_r = 6'd10;\n    8'd29: cx_rd_ptr_r = 6'd11;\n    8'd30: cx_rd_ptr_r = 6'd11;\n    8'd31: cx_rd_ptr_r = 6'd16;\n    8'd32: cx_rd_ptr_r = 6'd16;\n    8'd33: cx_rd_ptr_r = 6'd17;\n    8'd34: cx_rd_ptr_r = 6'd17;\n    8'd35: cx_rd_ptr_r = 6'd18;\n    8'd36: cx_rd_ptr_r = 6'd18;\n    8'd37: cx_rd_ptr_r = 6'd19;\n    8'd38: cx_rd_ptr_r = 6'd19;\n    8'd39: cx_rd_ptr_r = 6'd16;\n    8'd40: cx_rd_ptr_r = 6'd16;\n    8'd41: cx_rd_ptr_r = 6'd17;\n    8'd42: cx_rd_ptr_r = 6'd17;\n    8'd43: cx_rd_ptr_r = 6'd18;\n    8'd44: cx_rd_ptr_r = 6'd18;\n    8'd45: cx_rd_ptr_r = 6'd19;\n    8'd46: cx_rd_ptr_r = 6'd19;\n    8'd47: cx_rd_ptr_r = 6'd24;\n    8'd48: cx_rd_ptr_r = 6'd24;\n    8'd49: cx_rd_ptr_r = 6'd25;\n    8'd50: cx_rd_ptr_r = 6'd25;\n    8'd51: cx_rd_ptr_r = 6'd26;\n    8'd52: cx_rd_ptr_r = 6'd26;\n    8'd53: cx_rd_ptr_r = 6'd27;\n    8'd54: cx_rd_ptr_r = 6'd27;\n    8'd55: cx_rd_ptr_r = 6'd24;\n    8'd56: cx_rd_ptr_r = 6'd24;\n    8'd57: cx_rd_ptr_r = 6'd25;\n    8'd58: cx_rd_ptr_r = 6'd25;\n    8'd59: cx_rd_ptr_r = 6'd26;\n    8'd60: cx_rd_ptr_r = 6'd26;\n    8'd61: cx_rd_ptr_r = 6'd27;\n    8'd62: cx_rd_ptr_r = 6'd27;\n    8'd63: cx_rd_ptr_r = 6'd4;\n    8'd64: cx_rd_ptr_r = 6'd4;\n    8'd65: cx_rd_ptr_r = 6'd5;\n    8'd66: cx_rd_ptr_r = 6'd5;\n    8'd67: cx_rd_ptr_r = 6'd6;\n    8'd68: cx_rd_ptr_r = 6'd6;\n    8'd69: cx_rd_ptr_r = 6'd7;\n    8'd70: cx_rd_ptr_r = 6'd7;\n    8'd71: cx_rd_ptr_r = 6'd4;\n    8'd72: cx_rd_ptr_r = 6'd4;\n    8'd73: cx_rd_ptr_r = 6'd5;\n    8'd74: cx_rd_ptr_r = 6'd5;\n    8'd75: cx_rd_ptr_r = 6'd6;\n    8'd76: cx_rd_ptr_r = 6'd6;\n    8'd77: cx_rd_ptr_r = 6'd7;\n    8'd78: cx_rd_ptr_r = 6'd7;\n    8'd79: cx_rd_ptr_r = 6'd12;\n    8'd80: cx_rd_ptr_r = 6'd12;\n    8'd81: cx_rd_ptr_r = 6'd13;\n    8'd82: cx_rd_ptr_r = 6'd13;\n    8'd83: cx_rd_ptr_r = 6'd14;\n    8'd84: cx_rd_ptr_r = 6'd14;\n    8'd85: cx_rd_ptr_r = 6'd15;\n    8'd86: cx_rd_ptr_r = 6'd15;\n    8'd87: cx_rd_ptr_r = 6'd12;\n    8'd88: cx_rd_ptr_r = 6'd12;\n    8'd89: cx_rd_ptr_r = 6'd13;\n    8'd90: cx_rd_ptr_r = 6'd13;\n    8'd91: cx_rd_ptr_r = 6'd14;\n    8'd92: cx_rd_ptr_r = 6'd14;\n    8'd93: cx_rd_ptr_r = 6'd15;\n    8'd94: cx_rd_ptr_r = 6'd15;\n    8'd95: cx_rd_ptr_r = 6'd20;\n    8'd96: cx_rd_ptr_r = 6'd20;\n    8'd97: cx_rd_ptr_r = 6'd21;\n    8'd98: cx_rd_ptr_r = 6'd21;\n    8'd99: cx_rd_ptr_r = 6'd22;\n    8'd100: cx_rd_ptr_r = 6'd22;\n    8'd101: cx_rd_ptr_r = 6'd23;\n    8'd102: cx_rd_ptr_r = 6'd23;\n    8'd103: cx_rd_ptr_r = 6'd20;\n    8'd104: cx_rd_ptr_r = 6'd20;\n    8'd105: cx_rd_ptr_r = 6'd21;\n    8'd106: cx_rd_ptr_r = 6'd21;\n    8'd107: cx_rd_ptr_r = 6'd22;\n    8'd108: cx_rd_ptr_r = 6'd22;\n    8'd109: cx_rd_ptr_r = 6'd23;\n    8'd110: cx_rd_ptr_r = 6'd23;\n    8'd111: cx_rd_ptr_r = 6'd28;\n    8'd112: cx_rd_ptr_r = 6'd28;\n    8'd113: cx_rd_ptr_r = 6'd29;\n    8'd114: cx_rd_ptr_r = 6'd29;\n    8'd115: cx_rd_ptr_r = 6'd30;\n    8'd116: cx_rd_ptr_r = 6'd30;\n    8'd117: cx_rd_ptr_r = 6'd31;\n    8'd118: cx_rd_ptr_r = 6'd31;\n    8'd119: cx_rd_ptr_r = 6'd28;\n    8'd120: cx_rd_ptr_r = 6'd28;\n    8'd121: cx_rd_ptr_r = 6'd29;\n    8'd122: cx_rd_ptr_r = 6'd29;\n    8'd123: cx_rd_ptr_r = 6'd30;\n    8'd124: cx_rd_ptr_r = 6'd30;\n    8'd125: cx_rd_ptr_r = 6'd31;\n    8'd126: cx_rd_ptr_r = 6'd31;\n    8'd127: cx_rd_ptr_r = 6'd32;\n    8'd128: cx_rd_ptr_r = 6'd32;\n    8'd129: cx_rd_ptr_r = 6'd33;\n    8'd130: cx_rd_ptr_r = 6'd33;\n    8'd131: cx_rd_ptr_r = 6'd34;\n    8'd132: cx_rd_ptr_r = 6'd34;\n    8'd133: cx_rd_ptr_r = 6'd35;\n    8'd134: cx_rd_ptr_r = 6'd35;\n    8'd135: cx_rd_ptr_r = 6'd32;\n    8'd136: cx_rd_ptr_r = 6'd32;\n    8'd137: cx_rd_ptr_r = 6'd33;\n    8'd138: cx_rd_ptr_r = 6'd33;\n    8'd139: cx_rd_ptr_r = 6'd34;\n    8'd140: cx_rd_ptr_r = 6'd34;\n    8'd141: cx_rd_ptr_r = 6'd35;\n    8'd142: cx_rd_ptr_r = 6'd35;\n    8'd143: cx_rd_ptr_r = 6'd40;\n    8'd144: cx_rd_ptr_r = 6'd40;\n    8'd145: cx_rd_ptr_r = 6'd41;\n    8'd146: cx_rd_ptr_r = 6'd41;\n    8'd147: cx_rd_ptr_r = 6'd42;\n    8'd148: cx_rd_ptr_r = 6'd42;\n    8'd149: cx_rd_ptr_r = 6'd43;\n    8'd150: cx_rd_ptr_r = 6'd43;\n    8'd151: cx_rd_ptr_r = 6'd40;\n    8'd152: cx_rd_ptr_r = 6'd40;\n    8'd153: cx_rd_ptr_r = 6'd41;\n    8'd154: cx_rd_ptr_r = 6'd41;\n    8'd155: cx_rd_ptr_r = 6'd42;\n    8'd156: cx_rd_ptr_r = 6'd42;\n    8'd157: cx_rd_ptr_r = 6'd43;\n    8'd158: cx_rd_ptr_r = 6'd43;\n    8'd159: cx_rd_ptr_r = 6'd48;\n    8'd160: cx_rd_ptr_r = 6'd48;\n    8'd161: cx_rd_ptr_r = 6'd49;\n    8'd162: cx_rd_ptr_r = 6'd49;\n    8'd163: cx_rd_ptr_r = 6'd50;\n    8'd164: cx_rd_ptr_r = 6'd50;\n    8'd165: cx_rd_ptr_r = 6'd51;\n    8'd166: cx_rd_ptr_r = 6'd51;\n    8'd167: cx_rd_ptr_r = 6'd48;\n    8'd168: cx_rd_ptr_r = 6'd48;\n    8'd169: cx_rd_ptr_r = 6'd49;\n    8'd170: cx_rd_ptr_r = 6'd49;\n    8'd171: cx_rd_ptr_r = 6'd50;\n    8'd172: cx_rd_ptr_r = 6'd50;\n    8'd173: cx_rd_ptr_r = 6'd51;\n    8'd174: cx_rd_ptr_r = 6'd51;\n    8'd175: cx_rd_ptr_r = 6'd56;\n    8'd176: cx_rd_ptr_r = 6'd56;\n    8'd177: cx_rd_ptr_r = 6'd57;\n    8'd178: cx_rd_ptr_r = 6'd57;\n    8'd179: cx_rd_ptr_r = 6'd58;\n    8'd180: cx_rd_ptr_r = 6'd58;\n    8'd181: cx_rd_ptr_r = 6'd59;\n    8'd182: cx_rd_ptr_r = 6'd59;\n    8'd183: cx_rd_ptr_r = 6'd56;\n    8'd184: cx_rd_ptr_r = 6'd56;\n    8'd185: cx_rd_ptr_r = 6'd57;\n    8'd186: cx_rd_ptr_r = 6'd57;\n    8'd187: cx_rd_ptr_r = 6'd58;\n    8'd188: cx_rd_ptr_r = 6'd58;\n    8'd189: cx_rd_ptr_r = 6'd59;\n    8'd190: cx_rd_ptr_r = 6'd59;\n    8'd191: cx_rd_ptr_r = 6'd36;\n    8'd192: cx_rd_ptr_r = 6'd36;\n    8'd193: cx_rd_ptr_r = 6'd37;\n    8'd194: cx_rd_ptr_r = 6'd37;\n    8'd195: cx_rd_ptr_r = 6'd38;\n    8'd196: cx_rd_ptr_r = 6'd38;\n    8'd197: cx_rd_ptr_r = 6'd39;\n    8'd198: cx_rd_ptr_r = 6'd39;\n    8'd199: cx_rd_ptr_r = 6'd36;\n    8'd200: cx_rd_ptr_r = 6'd36;\n    8'd201: cx_rd_ptr_r = 6'd37;\n    8'd202: cx_rd_ptr_r = 6'd37;\n    8'd203: cx_rd_ptr_r = 6'd38;\n    8'd204: cx_rd_ptr_r = 6'd38;\n    8'd205: cx_rd_ptr_r = 6'd39;\n    8'd206: cx_rd_ptr_r = 6'd39;\n    8'd207: cx_rd_ptr_r = 6'd44;\n    8'd208: cx_rd_ptr_r = 6'd44;\n    8'd209: cx_rd_ptr_r = 6'd45;\n    8'd210: cx_rd_ptr_r = 6'd45;\n    8'd211: cx_rd_ptr_r = 6'd46;\n    8'd212: cx_rd_ptr_r = 6'd46;\n    8'd213: cx_rd_ptr_r = 6'd47;\n    8'd214: cx_rd_ptr_r = 6'd47;\n    8'd215: cx_rd_ptr_r = 6'd44;\n    8'd216: cx_rd_ptr_r = 6'd44;\n    8'd217: cx_rd_ptr_r = 6'd45;\n    8'd218: cx_rd_ptr_r = 6'd45;\n    8'd219: cx_rd_ptr_r = 6'd46;\n    8'd220: cx_rd_ptr_r = 6'd46;\n    8'd221: cx_rd_ptr_r = 6'd47;\n    8'd222: cx_rd_ptr_r = 6'd47;\n    8'd223: cx_rd_ptr_r = 6'd52;\n    8'd224: cx_rd_ptr_r = 6'd52;\n    8'd225: cx_rd_ptr_r = 6'd53;\n    8'd226: cx_rd_ptr_r = 6'd53;\n    8'd227: cx_rd_ptr_r = 6'd54;\n    8'd228: cx_rd_ptr_r = 6'd54;\n    8'd229: cx_rd_ptr_r = 6'd55;\n    8'd230: cx_rd_ptr_r = 6'd55;\n    8'd231: cx_rd_ptr_r = 6'd52;\n    8'd232: cx_rd_ptr_r = 6'd52;\n    8'd233: cx_rd_ptr_r = 6'd53;\n    8'd234: cx_rd_ptr_r = 6'd53;\n    8'd235: cx_rd_ptr_r = 6'd54;\n    8'd236: cx_rd_ptr_r = 6'd54;\n    8'd237: cx_rd_ptr_r = 6'd55;\n    8'd238: cx_rd_ptr_r = 6'd55;\n    8'd239: cx_rd_ptr_r = 6'd60;\n    8'd240: cx_rd_ptr_r = 6'd60;\n    8'd241: cx_rd_ptr_r = 6'd61;\n    8'd242: cx_rd_ptr_r = 6'd61;\n    8'd243: cx_rd_ptr_r = 6'd62;\n    8'd244: cx_rd_ptr_r = 6'd62;\n    8'd245: cx_rd_ptr_r = 6'd63;\n    8'd246: cx_rd_ptr_r = 6'd63;\n    8'd247: cx_rd_ptr_r = 6'd60;\n    8'd248: cx_rd_ptr_r = 6'd60;\n    8'd249: cx_rd_ptr_r = 6'd61;\n    8'd250: cx_rd_ptr_r = 6'd61;\n    8'd251: cx_rd_ptr_r = 6'd62;\n    8'd252: cx_rd_ptr_r = 6'd62;\n    8'd253: cx_rd_ptr_r = 6'd63;\n    8'd254: cx_rd_ptr_r = 6'd63;\n    default: cx_rd_ptr_r = 6'd0;\n    endcase\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    cx_idx_q    <= 8'b0;\nelse if (flush_i)\n    cx_idx_q    <= 8'b0;\nelse if (read_ok_w && ((!valid_o) || (valid_o && pop_i)))\n    cx_idx_q    <= cx_idx_q + 8'd1;\n\nreg [1:0] cx_half_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    cx_half_q    <= 2'b0;\nelse if (flush_i)\n    cx_half_q    <= 2'b0;\nelse if (read_ok_w && ((!valid_o) || (valid_o && pop_i)) && cx_idx_q == 8'd255)\n    cx_half_q    <= cx_half_q + 2'd1;\n\nreg [5:0] cx_rd_ptr_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    cx_rd_ptr_q <= 6'b0;\nelse if (read_ok_w && ((!valid_o) || (valid_o && pop_i)))\n    cx_rd_ptr_q <= cx_rd_ptr_r;\n\nwire [7:0] rd_addr_w = mode420_i ? {cx_half_q, cx_rd_ptr_q} : rd_ptr_q;\n\n//-------------------------------------------------------------------\n// Read Skid Buffer\n//-------------------------------------------------------------------\nreg                rd_skid_q;\nreg [31:0] rd_skid_data_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    rd_skid_q <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\nelse if (flush_i)\nbegin\n    rd_skid_q <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\nelse if (valid_o && !pop_i)\nbegin\n    rd_skid_q      <= 1'b1;\n    rd_skid_data_q <= data_out_o;\nend\nelse\nbegin\n    rd_skid_q      <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\n\n//-------------------------------------------------------------------\n// Combinatorial\n//-------------------------------------------------------------------\nassign valid_o       = rd_skid_q | rd_q;\n\n//-------------------------------------------------------------------\n// Dual port RAM\n//-------------------------------------------------------------------\nwire [31:0] data_out_w;\n\njpeg_output_cx_ram_ram_dp_256_8\nu_ram\n(\n    // Inputs\n    .clk0_i(clk_i),\n    .rst0_i(rst_i),\n    .clk1_i(clk_i),\n    .rst1_i(rst_i),\n\n    // Write side\n    .addr0_i({wr_ptr_q[7:6], wr_idx_i}),\n    .wr0_i(push_i),\n    .data0_i(data_in_i),\n    .data0_o(),\n\n    // Read side\n    .addr1_i(rd_addr_w),\n    .data1_i(32'b0),\n    .wr1_i(1'b0),\n    .data1_o(data_out_w)\n);\n\nassign data_out_o = rd_skid_q ? rd_skid_data_q : data_out_w;\n\n\n//-------------------------------------------------------------------\n// Level\n//-------------------------------------------------------------------\nreg [31:0]  count_q;\nreg [31:0]  count_r;\n\nalways @ *\nbegin\n    count_r = count_q;\n\n    if (pop_i && valid_o)\n        count_r = count_r - 32'd1;\n\n    if (push_i)\n        count_r = count_r + (mode420_i ? 32'd4 : 32'd1);\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    count_q   <= 32'b0;\nelse if (flush_i)\n    count_q   <= 32'b0;\nelse\n    count_q <= count_r;\n\nassign level_o = count_q;\n\nendmodule\n\n//-------------------------------------------------------------------\n// Dual port RAM\n//-------------------------------------------------------------------\nmodule jpeg_output_cx_ram_ram_dp_256_8\n(\n    // Inputs\n     input           clk0_i\n    ,input           rst0_i\n    ,input  [ 7:0]  addr0_i\n    ,input  [ 31:0]  data0_i\n    ,input           wr0_i\n    ,input           clk1_i\n    ,input           rst1_i\n    ,input  [ 7:0]  addr1_i\n    ,input  [ 31:0]  data1_i\n    ,input           wr1_i\n\n    // Outputs\n    ,output [ 31:0]  data0_o\n    ,output [ 31:0]  data1_o\n);\n\n/* verilator lint_off MULTIDRIVEN */\nreg [31:0]   ram [255:0] /*verilator public*/;\n/* verilator lint_on MULTIDRIVEN */\n\nreg [31:0] ram_read0_q;\nreg [31:0] ram_read1_q;\n\n// Synchronous write\nalways @ (posedge clk0_i)\nbegin\n    if (wr0_i)\n        ram[addr0_i] <= data0_i;\n\n    ram_read0_q <= ram[addr0_i];\nend\n\nalways @ (posedge clk1_i)\nbegin\n    if (wr1_i)\n        ram[addr1_i] <= data1_i;\n\n    ram_read1_q <= ram[addr1_i];\nend\n\nassign data0_o = ram_read0_q;\nassign data1_o = ram_read1_q;\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_output_fifo.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_output_fifo\n//-----------------------------------------------------------------\n// Params\n//-----------------------------------------------------------------\n#(\n     parameter WIDTH            = 8\n    ,parameter DEPTH            = 4\n    ,parameter ADDR_W           = 2\n)\n//-----------------------------------------------------------------\n// Ports\n//-----------------------------------------------------------------\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input  [WIDTH-1:0]  data_in_i\n    ,input           push_i\n    ,input           pop_i\n    ,input           flush_i\n\n    // Outputs\n    ,output [WIDTH-1:0]  data_out_o\n    ,output          accept_o\n    ,output          valid_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Local Params\n//-----------------------------------------------------------------\nlocalparam COUNT_W = ADDR_W + 1;\n\n//-----------------------------------------------------------------\n// Registers\n//-----------------------------------------------------------------\nreg [WIDTH-1:0]   ram_q[DEPTH-1:0];\nreg [ADDR_W-1:0]  rd_ptr_q;\nreg [ADDR_W-1:0]  wr_ptr_q;\nreg [COUNT_W-1:0] count_q;\n\n//-----------------------------------------------------------------\n// Sequential\n//-----------------------------------------------------------------\nalways @ (posedge clk_i or posedge rst_i)\nif (rst_i)\nbegin\n    count_q   <= {(COUNT_W) {1'b0}};\n    rd_ptr_q  <= {(ADDR_W) {1'b0}};\n    wr_ptr_q  <= {(ADDR_W) {1'b0}};\nend\nelse if (flush_i)\nbegin\n    count_q   <= {(COUNT_W) {1'b0}};\n    rd_ptr_q  <= {(ADDR_W) {1'b0}};\n    wr_ptr_q  <= {(ADDR_W) {1'b0}};\nend\nelse\nbegin\n    // Push\n    if (push_i & accept_o)\n    begin\n        ram_q[wr_ptr_q] <= data_in_i;\n        wr_ptr_q        <= wr_ptr_q + 1;\n    end\n\n    // Pop\n    if (pop_i & valid_o)\n        rd_ptr_q      <= rd_ptr_q + 1;\n\n    // Count up\n    if ((push_i & accept_o) & ~(pop_i & valid_o))\n        count_q <= count_q + 1;\n    // Count down\n    else if (~(push_i & accept_o) & (pop_i & valid_o))\n        count_q <= count_q - 1;\nend\n\n//-------------------------------------------------------------------\n// Combinatorial\n//-------------------------------------------------------------------\n/* verilator lint_off WIDTH */\nassign valid_o       = (count_q != 0);\nassign accept_o      = (count_q != DEPTH);\n/* verilator lint_on WIDTH */\n\nassign data_out_o    = ram_q[rd_ptr_q];\n\n\n\nendmodule\n"
  },
  {
    "path": "src_v/jpeg_output_y_ram.v",
    "content": "//-----------------------------------------------------------------\n//                      Baseline JPEG Decoder\n//                             V0.1\n//                       Ultra-Embedded.com\n//                        Copyright 2020\n//\n//                   admin@ultra-embedded.com\n//-----------------------------------------------------------------\n//                      License: Apache 2.0\n// This IP can be freely used in commercial projects, however you may\n// want access to unreleased materials such as verification environments,\n// or test vectors, as well as changes to the IP for integration purposes.\n// If this is the case, contact the above address.\n// I am interested to hear how and where this IP is used, so please get\n// in touch!\n//-----------------------------------------------------------------\n// Copyright 2020 Ultra-Embedded.com\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n//     http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//-----------------------------------------------------------------\n\nmodule jpeg_output_y_ram\n(\n    // Inputs\n     input           clk_i\n    ,input           rst_i\n    ,input  [  5:0]  wr_idx_i\n    ,input  [ 31:0]  data_in_i\n    ,input           push_i\n    ,input           pop_i\n    ,input           flush_i\n\n    // Outputs\n    ,output [ 31:0]  data_out_o\n    ,output          valid_o\n    ,output [ 31:0]  level_o\n);\n\n\n\n//-----------------------------------------------------------------\n// Registers\n//-----------------------------------------------------------------\nreg [8:0]   rd_ptr_q;\nreg [8:0]   wr_ptr_q;\n\n//-----------------------------------------------------------------\n// Write Side\n//-----------------------------------------------------------------\nwire [8:0] write_next_w = wr_ptr_q + 9'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    wr_ptr_q <= 9'b0;\nelse if (flush_i)\n    wr_ptr_q <= 9'b0;\n// Push\nelse if (push_i)\n    wr_ptr_q <= write_next_w;\n\n//-----------------------------------------------------------------\n// Read Side\n//-----------------------------------------------------------------\nwire read_ok_w = (wr_ptr_q != rd_ptr_q);\nreg  rd_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_q <= 1'b0;\nelse if (flush_i)\n    rd_q <= 1'b0;\nelse\n    rd_q <= read_ok_w;\n\nwire [8:0] rd_ptr_next_w = rd_ptr_q + 9'd1;\n\nalways @ (posedge clk_i )\nif (rst_i)\n    rd_ptr_q <= 9'b0;\nelse if (flush_i)\n    rd_ptr_q <= 9'b0;\nelse if (read_ok_w && ((!valid_o) || (valid_o && pop_i)))\n    rd_ptr_q <= rd_ptr_next_w;\n\nwire [8:0] rd_addr_w = rd_ptr_q;\n\n//-------------------------------------------------------------------\n// Read Skid Buffer\n//-------------------------------------------------------------------\nreg                rd_skid_q;\nreg [31:0] rd_skid_data_q;\n\nalways @ (posedge clk_i )\nif (rst_i)\nbegin\n    rd_skid_q <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\nelse if (flush_i)\nbegin\n    rd_skid_q <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\nelse if (valid_o && !pop_i)\nbegin\n    rd_skid_q      <= 1'b1;\n    rd_skid_data_q <= data_out_o;\nend\nelse\nbegin\n    rd_skid_q      <= 1'b0;\n    rd_skid_data_q <= 32'b0;\nend\n\n//-------------------------------------------------------------------\n// Combinatorial\n//-------------------------------------------------------------------\nassign valid_o       = rd_skid_q | rd_q;\n\n//-------------------------------------------------------------------\n// Dual port RAM\n//-------------------------------------------------------------------\nwire [31:0] data_out_w;\n\njpeg_output_y_ram_ram_dp_512_9\nu_ram\n(\n    // Inputs\n    .clk0_i(clk_i),\n    .rst0_i(rst_i),\n    .clk1_i(clk_i),\n    .rst1_i(rst_i),\n\n    // Write side\n    .addr0_i({wr_ptr_q[8:6], wr_idx_i}),\n    .wr0_i(push_i),\n    .data0_i(data_in_i),\n    .data0_o(),\n\n    // Read side\n    .addr1_i(rd_addr_w),\n    .data1_i(32'b0),\n    .wr1_i(1'b0),\n    .data1_o(data_out_w)\n);\n\nassign data_out_o = rd_skid_q ? rd_skid_data_q : data_out_w;\n\n\n//-------------------------------------------------------------------\n// Level\n//-------------------------------------------------------------------\nreg [31:0]  count_q;\nreg [31:0]  count_r;\n\nalways @ *\nbegin\n    count_r = count_q;\n\n    if (pop_i && valid_o)\n        count_r = count_r - 32'd1;\n\n    if (push_i)\n        count_r = count_r + 32'd1;\nend\n\nalways @ (posedge clk_i )\nif (rst_i)\n    count_q   <= 32'b0;\nelse if (flush_i)\n    count_q   <= 32'b0;\nelse\n    count_q <= count_r;\n\nassign level_o = count_q;\n\nendmodule\n\n//-------------------------------------------------------------------\n// Dual port RAM\n//-------------------------------------------------------------------\nmodule jpeg_output_y_ram_ram_dp_512_9\n(\n    // Inputs\n     input           clk0_i\n    ,input           rst0_i\n    ,input  [ 8:0]  addr0_i\n    ,input  [ 31:0]  data0_i\n    ,input           wr0_i\n    ,input           clk1_i\n    ,input           rst1_i\n    ,input  [ 8:0]  addr1_i\n    ,input  [ 31:0]  data1_i\n    ,input           wr1_i\n\n    // Outputs\n    ,output [ 31:0]  data0_o\n    ,output [ 31:0]  data1_o\n);\n\n/* verilator lint_off MULTIDRIVEN */\nreg [31:0]   ram [511:0] /*verilator public*/;\n/* verilator lint_on MULTIDRIVEN */\n\nreg [31:0] ram_read0_q;\nreg [31:0] ram_read1_q;\n\n// Synchronous write\nalways @ (posedge clk0_i)\nbegin\n    if (wr0_i)\n        ram[addr0_i] <= data0_i;\n\n    ram_read0_q <= ram[addr0_i];\nend\n\nalways @ (posedge clk1_i)\nbegin\n    if (wr1_i)\n        ram[addr1_i] <= data1_i;\n\n    ram_read1_q <= ram[addr1_i];\nend\n\nassign data0_o = ram_read0_q;\nassign data1_o = ram_read1_q;\n\n\n\nendmodule\n"
  }
]