├── LICENSE ├── README.md ├── c_model ├── README.md ├── jpeg_bit_buffer.h ├── jpeg_dht.h ├── jpeg_dqt.h ├── jpeg_idct.h ├── jpeg_mcu_block.h ├── main.cpp └── makefile ├── docs ├── block_diagram.png ├── resources.png └── supported_opts.png └── src_v ├── jpeg_bitbuffer.v ├── jpeg_core.v ├── jpeg_dht.v ├── jpeg_dht_std_cx_ac.v ├── jpeg_dht_std_cx_dc.v ├── jpeg_dht_std_y_ac.v ├── jpeg_dht_std_y_dc.v ├── jpeg_dqt.v ├── jpeg_idct.v ├── jpeg_idct_fifo.v ├── jpeg_idct_ram.v ├── jpeg_idct_ram_dp.v ├── jpeg_idct_transpose.v ├── jpeg_idct_transpose_ram.v ├── jpeg_idct_x.v ├── jpeg_idct_y.v ├── jpeg_input.v ├── jpeg_mcu_id.v ├── jpeg_mcu_proc.v ├── jpeg_output.v ├── jpeg_output_cx_ram.v ├── jpeg_output_fifo.v └── jpeg_output_y_ram.v /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # High throughput JPEG decoder 2 | 3 | Github: [https://github.com/ultraembedded/core_jpeg](https://github.com/ultraembedded/core_jpeg) 4 | 5 | This project is a JPEG decoder core for FPGA written in Verilog. 6 | 7 | ![JPEG Core](docs/block_diagram.png) 8 | 9 | ## Features 10 | * Baseline JPEG Decoder IP (sequential encoded images). 11 | * 32-bit AXI Stream input. 12 | * Input format: JPEG (JPEG File Interchange Format) 13 | * Output format: 24-bit RGB output in 8x8 blocks (row-major ordering). 14 | * Support for Monochrome, 4:4:4, 4:2:0 chroma subsampling support. 15 | * Support for fixed standard Huffman tables (reduced logic usage, fast). 16 | * Support for dynamic Huffman tables (from JPEG input stream -> slower decode, more logic). 17 | * Dynamic DQT tables from JPEG input stream. 18 | * Synthesizable Verilog 2001, Verilator and FPGA friendly. 19 | * Multipliers and tables / FIFO's map efficiently to FPGA resources (DSP48, blockRAM, etc). 20 | * Verified using co-simulation against a C-model and tested on FPGA with thousands of images. 21 | 22 | ## Design Aims 23 | 1. Fast decode performance suitable for video playback 24 | 2. Support a minimal JPEG baseline feature set. 25 | 3. Be well tested (with verification against a reference C-model). 26 | 4. Map to FPGA resources such as BlockRAM, DSP macros wherever possible. 27 | 28 | ## FPGA Mapping 29 | The current version of the JPEG decoder uses the following resources on a Xilinx 7 series FPGA (post-implementation); 30 | ![Resource Usage](docs/resources.png) 31 | 32 | The design is also able to meet timing >= 75MHz. 33 | 34 | ## Performance 35 | Peak JPEG decode performance is as follows; 36 | * Monochrome = 66 cycles per 8x8 pixels (1.0 cycles per pixel) 37 | * YCbCr 4:2:0 = 137 cycles per 8x8 pixels (2.1 cycles per pixel) 38 | * YCbCr 4:4:4 = 198 cycles per 8x8 pixels (3.1 cycles per pixel) 39 | 40 | ## Use Case 41 | The purpose of this design was to replace a 3rd party JPEG decoder core used in my [Motion JPEG](https://en.wikipedia.org/wiki/Motion_JPEG) based [FPGA video player](https://github.com/ultraembedded/FPGAmp). 42 | Motion JPEG has worse compression performance than MPEG based video, but the complexity of the HW required is low enough that it can be used on low(-ish)-end FPGAs. 43 | 44 | Video playback usually requires at least 25 frames per second, hence there is a budget of less than 40ms per JPEG frame. 45 | This fact drives the design choices taken for this implementation. 46 | 47 | Clearly, the higher the resolution, the more pixels that must be produced from the JPEG decoder within that 40ms budget, so this core is designed to have high throughput in the output stages - with additional resources dedicated to the IDCT transform, and output re-ordering stages to facilitate this. 48 | 49 | ## Limitations 50 | The current release does not support; 51 | * Restart markers 52 | * 4:2:2 H/V chroma subsampling (only 4:4:4 and 4:2:0 are supported). 53 | 54 | Under the GNU Image Manipulation Program, the following 'X' options are **not** supported currently; 55 | ![Unsupported Opts](docs/supported_opts.png) 56 | 57 | Note: Support for 'optimised' Huffman tables is possible when design parameter SUPPORT_WRITABLE_DHT=1. 58 | This functionality increases the core size substantially and reduces performance. 59 | 60 | ## Future Work / TODO 61 | * Add support for the first layer of progressive JPEG images. 62 | * Add option to reduce arithmetic precision to reduce design size. 63 | * Add lightweight variant of the core with reduced performance (for smaller FPGAs). -------------------------------------------------------------------------------- /c_model/README.md: -------------------------------------------------------------------------------- 1 | ## JPEG Decoder C Model 2 | 3 | This a simple C model of a JPEG decoder that can decode baseline JPEG images. 4 | The purpose of this is to provide a reference to test the digital HW design against. 5 | 6 | It supports; 7 | * YCbCr 4:4:4 (no chroma subsampling), 4:2:0 and monochrome images. 8 | * Conversion to a bitmap file (PPM / P6 format). 9 | * Optimised (Huffman tables) images. 10 | 11 | It does not support (currently); 12 | * Progressive 13 | * YCbCr 4:2:2 chroma subsampling 14 | * Restart markers 15 | * App data, COM sections, will be ignored. 16 | 17 | 18 | ### Building / Usage 19 | ``` 20 | # Build 21 | make 22 | 23 | # Run 24 | ./jpeg my_image.jpg bitmap.ppm 25 | ``` 26 | -------------------------------------------------------------------------------- /c_model/jpeg_bit_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_BIT_BUFFER_H 2 | #define JPEG_BIT_BUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define dprintf 11 | 12 | #ifndef TEST_HOOKS_BITBUFFER 13 | #define TEST_HOOKS_BITBUFFER(x) 14 | #endif 15 | 16 | #ifndef TEST_HOOKS_BITBUFFER_DECL 17 | #define TEST_HOOKS_BITBUFFER_DECL 18 | #endif 19 | 20 | //----------------------------------------------------------------------------- 21 | // jpeg_bit_buffer: 22 | //----------------------------------------------------------------------------- 23 | class jpeg_bit_buffer 24 | { 25 | public: 26 | jpeg_bit_buffer() 27 | { 28 | m_buffer = NULL; 29 | reset(-1); 30 | } 31 | 32 | void reset(int max_size = -1) 33 | { 34 | if (m_buffer) 35 | { 36 | delete [] m_buffer; 37 | m_buffer = NULL; 38 | } 39 | 40 | if (max_size <= 0) 41 | m_max_size = 1 << 20; 42 | else 43 | m_max_size = max_size; 44 | 45 | m_buffer = new uint8_t[m_max_size]; 46 | memset(m_buffer, 0, m_max_size); 47 | m_wr_offset = 0; 48 | m_last = 0; 49 | m_rd_offset = 0; 50 | } 51 | 52 | // Push byte into stream (return false if marker found) 53 | bool push(uint8_t b) 54 | { 55 | uint8_t last = m_last; 56 | 57 | // Skip padding 58 | if (last == 0xFF && b == 0x00) 59 | ; 60 | // Marker found 61 | else if (last == 0xFF && b != 0x00) 62 | { 63 | m_wr_offset--; 64 | return false; 65 | } 66 | // Push byte into buffer 67 | else 68 | { 69 | assert(m_wr_offset < m_max_size); 70 | m_buffer[m_wr_offset++] = b; 71 | } 72 | 73 | m_last = b; 74 | 75 | return true; 76 | } 77 | 78 | // Read upto 32-bit (aligned to MSB) 79 | uint32_t read_word(void) 80 | { 81 | if (eof()) 82 | return 0; 83 | 84 | int byte = m_rd_offset / 8; 85 | int bit = m_rd_offset % 8; // 0 - 7 86 | uint64_t w = 0; 87 | for (int x=0;x<5;x++) 88 | { 89 | w |= m_buffer[byte+x]; 90 | w <<= 8; 91 | } 92 | w <<= bit; 93 | return w >> 16; 94 | } 95 | 96 | void advance(int bits) 97 | { 98 | TEST_HOOKS_BITBUFFER(bits); 99 | m_rd_offset += bits; 100 | } 101 | 102 | bool eof(void) 103 | { 104 | return (((m_rd_offset+7) / 8) >= m_wr_offset); 105 | } 106 | 107 | TEST_HOOKS_BITBUFFER_DECL; 108 | 109 | private: 110 | uint8_t *m_buffer; 111 | uint8_t m_last; 112 | int m_max_size; 113 | int m_wr_offset; 114 | int m_rd_offset; // in bits 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /c_model/jpeg_dht.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_DHT_H 2 | #define JPEG_DHT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define DHT_TABLE_Y_DC 0x00 11 | #define DHT_TABLE_Y_DC_IDX 0 12 | #define DHT_TABLE_Y_AC 0x10 13 | #define DHT_TABLE_Y_AC_IDX 1 14 | #define DHT_TABLE_CX_DC 0x01 15 | #define DHT_TABLE_CX_DC_IDX 2 16 | #define DHT_TABLE_CX_AC 0x11 17 | #define DHT_TABLE_CX_AC_IDX 3 18 | 19 | #define dprintf 20 | 21 | //----------------------------------------------------------------------------- 22 | // jpeg_dqt: 23 | //----------------------------------------------------------------------------- 24 | class jpeg_dht 25 | { 26 | public: 27 | jpeg_dht() { reset(); } 28 | 29 | void reset(void) 30 | { 31 | for (int i=0;i<4;i++) 32 | memset(&m_dht_table[i], 0, sizeof(t_huffman_table)); 33 | } 34 | 35 | int process(uint8_t *data, int len) 36 | { 37 | uint8_t *buf = data; 38 | int consumed = 0; 39 | 40 | // DHT tables can be combined into one section (it seems) 41 | while (consumed <= (len-17)) 42 | { 43 | // Huffman table info, first four MSBs represent table type (0 for DC, 1 for AC), last four LSBs represent table # 44 | uint8_t table_info = *buf++; 45 | 46 | int table_idx = 0; 47 | switch (table_info) 48 | { 49 | case DHT_TABLE_Y_DC: 50 | table_idx = DHT_TABLE_Y_DC_IDX; 51 | break; 52 | case DHT_TABLE_Y_AC: 53 | table_idx = DHT_TABLE_Y_AC_IDX; 54 | break; 55 | case DHT_TABLE_CX_DC: 56 | table_idx = DHT_TABLE_CX_DC_IDX; 57 | break; 58 | case DHT_TABLE_CX_AC: 59 | table_idx = DHT_TABLE_CX_AC_IDX; 60 | break; 61 | default: 62 | assert(!"ERROR: Bad JPEG"); 63 | break; 64 | } 65 | dprintf("DHT (Table idx %d)\n", table_idx); 66 | 67 | // Reset table 68 | memset(&m_dht_table[table_idx], 0, sizeof(m_dht_table[0])); 69 | 70 | // Extract symbol count 71 | uint8_t symb_count[16]; 72 | for (int x=0;x<16;x++) 73 | { 74 | symb_count[x] = *buf++; 75 | dprintf(" bit length: %d, symbols: %d\n", x, symb_count[x]); 76 | } 77 | 78 | // Extract table values 79 | // Build the Huffman map of (length, code) -> value 80 | uint16_t code = 0; 81 | int entry = 0; 82 | for (int x=0;x<16;x++) 83 | { 84 | for (int j=0;j %x\n", entry, code, dht_val); 91 | 92 | code++; 93 | } 94 | code <<= 1; 95 | } 96 | m_dht_table[table_idx].entries = entry; 97 | 98 | consumed = buf - data; 99 | } 100 | 101 | return buf - data; 102 | } 103 | 104 | // lookup: Perform huffman lookup (starting from bit 15 of w) 105 | int lookup(int table_idx, uint16_t w, uint8_t &value) 106 | { 107 | for (int i=0;i> (16-width); 114 | //printf("- %d: check against %04x ", width, shift_val); 115 | //print_bin(shift_val, width); 116 | //printf(" == %04x -> %02x\n", bitmap, value); 117 | if (shift_val == bitmap) 118 | { 119 | value = m_dht_table[table_idx].value[i]; 120 | return width; 121 | } 122 | } 123 | return 0; 124 | } 125 | 126 | private: 127 | typedef struct 128 | { 129 | // 16-bit (max) code 130 | uint16_t code[255]; 131 | // Code length 132 | uint8_t code_len[255]; 133 | // Value to translate to 134 | uint8_t value[255]; 135 | int entries; 136 | } t_huffman_table; 137 | 138 | t_huffman_table m_dht_table[4]; 139 | }; 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /c_model/jpeg_dqt.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_DQT_H 2 | #define JPEG_DQT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Zigzag table 11 | static const int m_zigzag_table[]= 12 | { 13 | 0, 1, 8, 16,9, 2, 3,10, 14 | 17,24,32,25,18,11, 4, 5, 15 | 12,19,26,33,40,48,41,34, 16 | 27,20,13, 6, 7,14,21,28, 17 | 35,42,49,56,57,50,43,36, 18 | 29,22,15,23,30,37,44,51, 19 | 58,59,52,45,38,31,39,46, 20 | 53,60,61,54,47,55,62,63, 21 | 0 22 | }; 23 | 24 | #define dprintf 25 | 26 | //----------------------------------------------------------------------------- 27 | // jpeg_dqt: 28 | //----------------------------------------------------------------------------- 29 | class jpeg_dqt 30 | { 31 | public: 32 | jpeg_dqt() { reset(); } 33 | 34 | //------------------------------------------------------------------------- 35 | // reset: Reset DQT tables 36 | //------------------------------------------------------------------------- 37 | void reset(void) 38 | { 39 | memset(&m_table_dqt[0], 0, 64 * 4); 40 | } 41 | 42 | //------------------------------------------------------------------------- 43 | // process: Store DQT table from input stream 44 | //------------------------------------------------------------------------- 45 | int process(uint8_t *data, int len) 46 | { 47 | uint8_t *buf = data; 48 | 49 | // Table number 50 | uint8_t table_num = (*buf++) & 0x3; 51 | dprintf(" DQT: Table %d\n", table_num); 52 | 53 | for (int x=0;x<64;x++) 54 | { 55 | // 8-bit 56 | uint8_t qv = *buf++; 57 | dprintf(" %d: %x\n", x, qv); 58 | m_table_dqt[table_num][x] = qv; 59 | } 60 | 61 | return buf - data; 62 | } 63 | 64 | //------------------------------------------------------------------------- 65 | // lookup: DQT table entry lookup 66 | //------------------------------------------------------------------------- 67 | uint8_t lookup(int table_num, int position) 68 | { 69 | return m_table_dqt[table_num][position]; 70 | } 71 | 72 | //------------------------------------------------------------------------- 73 | // process_samples: Multiply out samples and de-zigzag ready for IDCT 74 | // samples: (idx, value) 75 | //------------------------------------------------------------------------- 76 | void process_samples(int quant_table, int *sample_in, int *block_out, int count) 77 | { 78 | // Apply quantisation and zigzag 79 | memset(block_out, 0, sizeof(block_out[0])*64); 80 | for (int i=0;i> 16); 84 | 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]); 85 | block_out[m_zigzag_table[block_idx]] = smpl * lookup(quant_table,block_idx); 86 | } 87 | } 88 | 89 | private: 90 | uint8_t m_table_dqt[4][64]; 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /c_model/jpeg_idct.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_IDCT_H 2 | #define JPEG_IDCT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //----------------------------------------------------------------------------- 11 | // jpeg_idct: 12 | //----------------------------------------------------------------------------- 13 | class jpeg_idct 14 | { 15 | public: 16 | jpeg_idct() { reset(); } 17 | void reset(void) { } 18 | 19 | //----------------------------------------------------------------------------- 20 | // process: Perform inverse DCT on already dequantized data. 21 | // [Not quite sure who to attribute this implementation to...] 22 | //----------------------------------------------------------------------------- 23 | void process(int *data_in, int *data_out) 24 | { 25 | int s0,s1,s2,s3,s4,s5,s6,s7; 26 | int t0,t1,t2,t3,t4,t5,t6,t7; 27 | 28 | int working_buf[64]; 29 | int *temp_buf = working_buf; 30 | 31 | // X - Rows 32 | for(int i=0;i<8;i++) 33 | { 34 | s0 = (data_in[0] + data_in[4]) * C4; 35 | s1 = (data_in[0] - data_in[4]) * C4; 36 | s3 = (data_in[2] * C2) + (data_in[6] * C6); 37 | s2 = (data_in[2] * C6) - (data_in[6] * C2); 38 | s7 = (data_in[1] * C1) + (data_in[7] * C7); 39 | s4 = (data_in[1] * C7) - (data_in[7] * C1); 40 | s6 = (data_in[5] * C5) + (data_in[3] * C3); 41 | s5 = (data_in[5] * C3) - (data_in[3] * C5); 42 | 43 | // Next row 44 | data_in += 8; 45 | 46 | t0 = s0 + s3; 47 | t3 = s0 - s3; 48 | t1 = s1 + s2; 49 | t2 = s1 - s2; 50 | t4 = s4 + s5; 51 | t5 = s4 - s5; 52 | t7 = s7 + s6; 53 | t6 = s7 - s6; 54 | 55 | s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2) 56 | s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2) 57 | 58 | *temp_buf++ = (t0 + t7) >> 11; 59 | *temp_buf++ = (t1 + s6) >> 11; 60 | *temp_buf++ = (t2 + s5) >> 11; 61 | *temp_buf++ = (t3 + t4) >> 11; 62 | *temp_buf++ = (t3 - t4) >> 11; 63 | *temp_buf++ = (t2 - s5) >> 11; 64 | *temp_buf++ = (t1 - s6) >> 11; 65 | *temp_buf++ = (t0 - t7) >> 11; 66 | } 67 | 68 | // Y - Columns 69 | temp_buf = working_buf; 70 | for(int i=0;i<8;i++) 71 | { 72 | s0 = (temp_buf[0] + temp_buf[32]) * C4; 73 | s1 = (temp_buf[0] - temp_buf[32]) * C4; 74 | s3 = temp_buf[16] * C2 + temp_buf[48] * C6; 75 | s2 = temp_buf[16] * C6 - temp_buf[48] * C2; 76 | s7 = temp_buf[8] * C1 + temp_buf[56] * C7; 77 | s4 = temp_buf[8] * C7 - temp_buf[56] * C1; 78 | s6 = temp_buf[40] * C5 + temp_buf[24] * C3; 79 | s5 = temp_buf[40] * C3 - temp_buf[24] * C5; 80 | 81 | t0 = s0 + s3; 82 | t1 = s1 + s2; 83 | t2 = s1 - s2; 84 | t3 = s0 - s3; 85 | t4 = s4 + s5; 86 | t5 = s4 - s5; 87 | t6 = s7 - s6; 88 | t7 = s6 + s7; 89 | 90 | s5 = (t6 - t5) * 181 / 256; // 1/sqrt(2) 91 | s6 = (t5 + t6) * 181 / 256; // 1/sqrt(2) 92 | 93 | data_out[0] = ((t0 + t7) >> 15); 94 | data_out[56] = ((t0 - t7) >> 15); 95 | data_out[8] = ((t1 + s6) >> 15); 96 | data_out[48] = ((t1 - s6) >> 15); 97 | data_out[16] = ((t2 + s5) >> 15); 98 | data_out[40] = ((t2 - s5) >> 15); 99 | data_out[24] = ((t3 + t4) >> 15); 100 | data_out[32] = ((t3 - t4) >> 15); 101 | 102 | temp_buf++; 103 | data_out++; 104 | } 105 | data_out -= 8; 106 | } 107 | 108 | static const int C1 = 4017; // cos( pi/16) x4096 109 | static const int C2 = 3784; // cos(2pi/16) x4096 110 | static const int C3 = 3406; // cos(3pi/16) x4096 111 | static const int C4 = 2896; // cos(4pi/16) x4096 112 | static const int C5 = 2276; // cos(5pi/16) x4096 113 | static const int C6 = 1567; // cos(6pi/16) x4096 114 | static const int C7 = 799; // cos(7pi/16) x4096 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /c_model/jpeg_mcu_block.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_MCU_BLOCK_H 2 | #define JPEG_MCU_BLOCK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "jpeg_bit_buffer.h" 11 | #include "jpeg_dht.h" 12 | 13 | #define dprintf 14 | 15 | //----------------------------------------------------------------------------- 16 | // jpeg_mcu_block: 17 | //----------------------------------------------------------------------------- 18 | class jpeg_mcu_block 19 | { 20 | public: 21 | jpeg_mcu_block(jpeg_bit_buffer *bit_buf, jpeg_dht *dht) 22 | { 23 | m_bit_buffer = bit_buf; 24 | m_dht = dht; 25 | reset(); 26 | } 27 | 28 | void reset(void) { } 29 | 30 | //----------------------------------------------------------------------------- 31 | // decode: Run huffman entropy decoder on input stream, expand to DC + upto 32 | // 63 AC samples. 33 | //----------------------------------------------------------------------------- 34 | int decode(int table_idx, int16_t &olddccoeff, int32_t *block_out) 35 | { 36 | int samples = 0; 37 | 38 | for (int coeff=0;coeff<64;coeff++) 39 | { 40 | // Read 32-bit word 41 | uint32_t input_word = m_bit_buffer->read_word(); 42 | 43 | // Start with upper 16-bits 44 | uint16_t input_data = input_word >> 16; 45 | 46 | // Perform huffman decode on input data (code=RLE,num_bits) 47 | uint8_t code = 0; 48 | int code_width = m_dht->lookup(table_idx + (coeff != 0), input_data, code); 49 | int coef_bits = code & 0xF; 50 | 51 | // Move input point past decoded data 52 | if (coeff == 0) 53 | m_bit_buffer->advance(code_width + coef_bits); 54 | // End of block or ZRL (no coefficient) 55 | else if (code == 0 || code == 0xF0) 56 | m_bit_buffer->advance(code_width); 57 | else 58 | m_bit_buffer->advance(code_width + coef_bits); 59 | 60 | // Use remaining data for actual coeffecient 61 | input_data = input_word >> (16 - code_width); 62 | 63 | // DC 64 | if (coeff == 0) 65 | { 66 | input_data >>= (16 - code); 67 | 68 | int16_t dcoeff = decode_number(input_data, coef_bits) + olddccoeff; 69 | olddccoeff = dcoeff; 70 | block_out[samples++] = (0 << 16) | (dcoeff & 0xFFFF); 71 | } 72 | // AC 73 | else 74 | { 75 | // End of block 76 | if (code == 0) 77 | { 78 | dprintf("SMPL: EOB\n"); 79 | coeff = 64; 80 | break; 81 | } 82 | 83 | // The first part of the AC key_len is the number of leading zeros 84 | if (code == 0xF0) 85 | { 86 | // When the ZRL code comes, it is regarded as 15 zero data 87 | dprintf("SMPL: ZRL\n"); 88 | coeff += 15; // +1 in the loop 89 | continue; 90 | } 91 | else if (code > 15) 92 | coeff += code >> 4; 93 | 94 | input_data >>= (16 - coef_bits); 95 | 96 | if (coeff < 64) 97 | { 98 | int16_t acoeff = decode_number(input_data, coef_bits); 99 | block_out[samples++] = (coeff << 16) | (acoeff & 0xFFFF); 100 | } 101 | } 102 | } 103 | 104 | return samples; 105 | } 106 | 107 | 108 | private: 109 | //----------------------------------------------------------------------------- 110 | // decode_number: Extract number from code / width 111 | //----------------------------------------------------------------------------- 112 | int16_t decode_number(uint16_t code, int bits) 113 | { 114 | if (!(code & (1<<(bits-1))) && bits != 0) 115 | { 116 | code |= (~0) << bits; 117 | code += 1; 118 | } 119 | return code; 120 | } 121 | 122 | private: 123 | jpeg_bit_buffer *m_bit_buffer; 124 | jpeg_dht *m_dht; 125 | 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /c_model/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Makefile 3 | ############################################################################### 4 | 5 | # Target 6 | TARGET ?= jpeg 7 | 8 | # Source Files 9 | SRC_DIR = . 10 | 11 | CFLAGS = -O2 -fPIC 12 | CFLAGS += -Wno-format 13 | 14 | INCLUDE_PATH += $(SRC_DIR) 15 | CFLAGS += $(patsubst %,-I%,$(INCLUDE_PATH)) 16 | 17 | LDFLAGS = 18 | LIBS = 19 | 20 | ############################################################################### 21 | # Variables 22 | ############################################################################### 23 | OBJ_DIR ?= obj/ 24 | 25 | ############################################################################### 26 | # Variables: Lists of objects, source and deps 27 | ############################################################################### 28 | # SRC / Object list 29 | src2obj = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1))) 30 | 31 | SRC ?= $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp)) 32 | OBJ ?= $(foreach src,$(SRC),$(call src2obj,$(src))) 33 | 34 | ############################################################################### 35 | # Rules: Compilation macro 36 | ############################################################################### 37 | define template_cpp 38 | $(call src2obj,$(1)): $(1) | $(OBJ_DIR) 39 | @echo "# Compiling $(notdir $(1))" 40 | @g++ $(CFLAGS) -c $$< -o $$@ 41 | endef 42 | 43 | ############################################################################### 44 | # Rules 45 | ############################################################################### 46 | all: $(TARGET) 47 | 48 | $(OBJ_DIR): 49 | @mkdir -p $@ 50 | 51 | $(foreach src,$(SRC),$(eval $(call template_cpp,$(src)))) 52 | 53 | $(TARGET): $(OBJ) makefile 54 | @echo "# Linking $(notdir $@)" 55 | @g++ $(LDFLAGS) $(OBJ) $(LIBS) -o $@ 56 | 57 | clean: 58 | -rm -rf $(OBJ_DIR) $(TARGET) 59 | -------------------------------------------------------------------------------- /docs/block_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/core_jpeg/bb03cce45d0b7459d395486e9e1db3de1b416bd2/docs/block_diagram.png -------------------------------------------------------------------------------- /docs/resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/core_jpeg/bb03cce45d0b7459d395486e9e1db3de1b416bd2/docs/resources.png -------------------------------------------------------------------------------- /docs/supported_opts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/core_jpeg/bb03cce45d0b7459d395486e9e1db3de1b416bd2/docs/supported_opts.png -------------------------------------------------------------------------------- /src_v/jpeg_bitbuffer.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_bitbuffer 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input inport_valid_i 40 | ,input [ 7:0] inport_data_i 41 | ,input inport_last_i 42 | ,input [ 5:0] outport_pop_i 43 | 44 | // Outputs 45 | ,output inport_accept_o 46 | ,output outport_valid_o 47 | ,output [ 31:0] outport_data_o 48 | ,output outport_last_o 49 | ); 50 | 51 | 52 | 53 | //----------------------------------------------------------------- 54 | // Registers 55 | //----------------------------------------------------------------- 56 | reg [7:0] ram_q[7:0]; 57 | reg [5:0] rd_ptr_q; 58 | reg [5:0] wr_ptr_q; 59 | reg [6:0] count_q; 60 | reg drain_q; 61 | 62 | //----------------------------------------------------------------- 63 | // Input side FIFO 64 | //----------------------------------------------------------------- 65 | reg [6:0] count_r; 66 | always @ * 67 | begin 68 | count_r = count_q; 69 | 70 | // Count up 71 | if (inport_valid_i && inport_accept_o) 72 | count_r = count_r + 7'd8; 73 | 74 | // Count down 75 | if (outport_valid_o && (|outport_pop_i)) 76 | count_r = count_r - outport_pop_i; 77 | end 78 | 79 | always @ (posedge clk_i ) 80 | if (rst_i) 81 | begin 82 | count_q <= 7'b0; 83 | rd_ptr_q <= 6'b0; 84 | wr_ptr_q <= 6'b0; 85 | drain_q <= 1'b0; 86 | end 87 | else if (img_start_i) 88 | begin 89 | count_q <= 7'b0; 90 | rd_ptr_q <= 6'b0; 91 | wr_ptr_q <= 6'b0; 92 | drain_q <= 1'b0; 93 | end 94 | else 95 | begin 96 | // End of image 97 | if (inport_last_i) 98 | drain_q <= 1'b1; 99 | 100 | // Push 101 | if (inport_valid_i && inport_accept_o) 102 | begin 103 | ram_q[wr_ptr_q[5:3]] <= inport_data_i; 104 | wr_ptr_q <= wr_ptr_q + 6'd8; 105 | end 106 | 107 | // Pop 108 | if (outport_valid_o && (|outport_pop_i)) 109 | rd_ptr_q <= rd_ptr_q + outport_pop_i; 110 | 111 | count_q <= count_r; 112 | end 113 | 114 | assign inport_accept_o = (count_q <= 7'd56); 115 | 116 | //------------------------------------------------------------------- 117 | // Output side FIFO 118 | //------------------------------------------------------------------- 119 | reg [39:0] fifo_data_r; 120 | 121 | always @ * 122 | begin 123 | fifo_data_r = 40'b0; 124 | 125 | case (rd_ptr_q[5:3]) 126 | 3'd0: fifo_data_r = {ram_q[0], ram_q[1], ram_q[2], ram_q[3], ram_q[4]}; 127 | 3'd1: fifo_data_r = {ram_q[1], ram_q[2], ram_q[3], ram_q[4], ram_q[5]}; 128 | 3'd2: fifo_data_r = {ram_q[2], ram_q[3], ram_q[4], ram_q[5], ram_q[6]}; 129 | 3'd3: fifo_data_r = {ram_q[3], ram_q[4], ram_q[5], ram_q[6], ram_q[7]}; 130 | 3'd4: fifo_data_r = {ram_q[4], ram_q[5], ram_q[6], ram_q[7], ram_q[0]}; 131 | 3'd5: fifo_data_r = {ram_q[5], ram_q[6], ram_q[7], ram_q[0], ram_q[1]}; 132 | 3'd6: fifo_data_r = {ram_q[6], ram_q[7], ram_q[0], ram_q[1], ram_q[2]}; 133 | 3'd7: fifo_data_r = {ram_q[7], ram_q[0], ram_q[1], ram_q[2], ram_q[3]}; 134 | endcase 135 | end 136 | 137 | wire [39:0] data_shifted_w = fifo_data_r << rd_ptr_q[2:0]; 138 | 139 | assign outport_valid_o = (count_q >= 7'd32) || (drain_q && count_q != 7'd0); 140 | assign outport_data_o = data_shifted_w[39:8]; 141 | assign outport_last_o = 1'b0; 142 | 143 | 144 | `ifdef verilator 145 | function get_valid; /*verilator public*/ 146 | begin 147 | get_valid = inport_valid_i && inport_accept_o; 148 | end 149 | endfunction 150 | function [7:0] get_data; /*verilator public*/ 151 | begin 152 | get_data = inport_data_i; 153 | end 154 | endfunction 155 | `endif 156 | 157 | 158 | 159 | 160 | endmodule 161 | -------------------------------------------------------------------------------- /src_v/jpeg_core.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_core 33 | //----------------------------------------------------------------- 34 | // Params 35 | //----------------------------------------------------------------- 36 | #( 37 | parameter SUPPORT_WRITABLE_DHT = 0 38 | ) 39 | //----------------------------------------------------------------- 40 | // Ports 41 | //----------------------------------------------------------------- 42 | ( 43 | // Inputs 44 | input clk_i 45 | ,input rst_i 46 | ,input inport_valid_i 47 | ,input [ 31:0] inport_data_i 48 | ,input [ 3:0] inport_strb_i 49 | ,input inport_last_i 50 | ,input outport_accept_i 51 | 52 | // Outputs 53 | ,output inport_accept_o 54 | ,output outport_valid_o 55 | ,output [ 15:0] outport_width_o 56 | ,output [ 15:0] outport_height_o 57 | ,output [ 15:0] outport_pixel_x_o 58 | ,output [ 15:0] outport_pixel_y_o 59 | ,output [ 7:0] outport_pixel_r_o 60 | ,output [ 7:0] outport_pixel_g_o 61 | ,output [ 7:0] outport_pixel_b_o 62 | ,output idle_o 63 | ); 64 | 65 | wire [ 15:0] idct_outport_data_w; 66 | wire dqt_inport_valid_w; 67 | wire [ 31:0] dqt_inport_id_w; 68 | wire [ 31:0] output_outport_data_w; 69 | wire [ 5:0] idct_inport_idx_w; 70 | wire dqt_inport_eob_w; 71 | wire img_start_w; 72 | wire [ 15:0] img_height_w; 73 | wire output_inport_accept_w; 74 | wire [ 15:0] img_width_w; 75 | wire dht_cfg_valid_w; 76 | wire lookup_req_w; 77 | wire lookup_valid_w; 78 | wire [ 1:0] img_dqt_table_cb_w; 79 | wire [ 7:0] dht_cfg_data_w; 80 | wire img_end_w; 81 | wire [ 31:0] idct_inport_id_w; 82 | wire [ 4:0] lookup_width_w; 83 | wire idct_inport_accept_w; 84 | wire [ 5:0] output_inport_idx_w; 85 | wire [ 15:0] dqt_outport_data_w; 86 | wire dqt_inport_blk_space_w; 87 | wire idct_inport_valid_w; 88 | wire [ 7:0] dqt_cfg_data_w; 89 | wire [ 1:0] img_dqt_table_y_w; 90 | wire idct_inport_eob_w; 91 | wire dht_cfg_accept_w; 92 | wire [ 31:0] output_inport_id_w; 93 | wire output_inport_valid_w; 94 | wire [ 15:0] lookup_input_w; 95 | wire dqt_cfg_accept_w; 96 | wire [ 7:0] lookup_value_w; 97 | wire [ 1:0] lookup_table_w; 98 | wire dht_cfg_last_w; 99 | wire [ 5:0] dqt_inport_idx_w; 100 | wire [ 1:0] img_mode_w; 101 | wire [ 1:0] img_dqt_table_cr_w; 102 | wire bb_inport_valid_w; 103 | wire bb_outport_last_w; 104 | wire bb_inport_last_w; 105 | wire [ 5:0] bb_outport_pop_w; 106 | wire [ 7:0] bb_inport_data_w; 107 | wire dqt_cfg_valid_w; 108 | wire bb_outport_valid_w; 109 | wire bb_inport_accept_w; 110 | wire [ 31:0] bb_outport_data_w; 111 | wire dqt_cfg_last_w; 112 | 113 | 114 | jpeg_input 115 | u_jpeg_input 116 | ( 117 | // Inputs 118 | .clk_i(clk_i) 119 | ,.rst_i(rst_i) 120 | ,.inport_valid_i(inport_valid_i) 121 | ,.inport_data_i(inport_data_i) 122 | ,.inport_strb_i(inport_strb_i) 123 | ,.inport_last_i(inport_last_i) 124 | ,.dqt_cfg_accept_i(dqt_cfg_accept_w) 125 | ,.dht_cfg_accept_i(dht_cfg_accept_w) 126 | ,.data_accept_i(bb_inport_accept_w) 127 | 128 | // Outputs 129 | ,.inport_accept_o(inport_accept_o) 130 | ,.img_start_o(img_start_w) 131 | ,.img_end_o(img_end_w) 132 | ,.img_width_o(img_width_w) 133 | ,.img_height_o(img_height_w) 134 | ,.img_mode_o(img_mode_w) 135 | ,.img_dqt_table_y_o(img_dqt_table_y_w) 136 | ,.img_dqt_table_cb_o(img_dqt_table_cb_w) 137 | ,.img_dqt_table_cr_o(img_dqt_table_cr_w) 138 | ,.dqt_cfg_valid_o(dqt_cfg_valid_w) 139 | ,.dqt_cfg_data_o(dqt_cfg_data_w) 140 | ,.dqt_cfg_last_o(dqt_cfg_last_w) 141 | ,.dht_cfg_valid_o(dht_cfg_valid_w) 142 | ,.dht_cfg_data_o(dht_cfg_data_w) 143 | ,.dht_cfg_last_o(dht_cfg_last_w) 144 | ,.data_valid_o(bb_inport_valid_w) 145 | ,.data_data_o(bb_inport_data_w) 146 | ,.data_last_o(bb_inport_last_w) 147 | ); 148 | 149 | 150 | jpeg_dht 151 | #( 152 | .SUPPORT_WRITABLE_DHT(SUPPORT_WRITABLE_DHT) 153 | ) 154 | u_jpeg_dht 155 | ( 156 | // Inputs 157 | .clk_i(clk_i) 158 | ,.rst_i(rst_i) 159 | ,.cfg_valid_i(dht_cfg_valid_w) 160 | ,.cfg_data_i(dht_cfg_data_w) 161 | ,.cfg_last_i(dht_cfg_last_w) 162 | ,.lookup_req_i(lookup_req_w) 163 | ,.lookup_table_i(lookup_table_w) 164 | ,.lookup_input_i(lookup_input_w) 165 | 166 | // Outputs 167 | ,.cfg_accept_o(dht_cfg_accept_w) 168 | ,.lookup_valid_o(lookup_valid_w) 169 | ,.lookup_width_o(lookup_width_w) 170 | ,.lookup_value_o(lookup_value_w) 171 | ); 172 | 173 | 174 | jpeg_idct 175 | u_jpeg_idct 176 | ( 177 | // Inputs 178 | .clk_i(clk_i) 179 | ,.rst_i(rst_i) 180 | ,.img_start_i(img_start_w) 181 | ,.img_end_i(img_end_w) 182 | ,.inport_valid_i(idct_inport_valid_w) 183 | ,.inport_data_i(idct_outport_data_w) 184 | ,.inport_idx_i(idct_inport_idx_w) 185 | ,.inport_eob_i(idct_inport_eob_w) 186 | ,.inport_id_i(idct_inport_id_w) 187 | ,.outport_accept_i(output_inport_accept_w) 188 | 189 | // Outputs 190 | ,.inport_accept_o(idct_inport_accept_w) 191 | ,.outport_valid_o(output_inport_valid_w) 192 | ,.outport_data_o(output_outport_data_w) 193 | ,.outport_idx_o(output_inport_idx_w) 194 | ,.outport_id_o(output_inport_id_w) 195 | ); 196 | 197 | 198 | jpeg_dqt 199 | u_jpeg_dqt 200 | ( 201 | // Inputs 202 | .clk_i(clk_i) 203 | ,.rst_i(rst_i) 204 | ,.img_start_i(img_start_w) 205 | ,.img_end_i(img_end_w) 206 | ,.img_dqt_table_y_i(img_dqt_table_y_w) 207 | ,.img_dqt_table_cb_i(img_dqt_table_cb_w) 208 | ,.img_dqt_table_cr_i(img_dqt_table_cr_w) 209 | ,.cfg_valid_i(dqt_cfg_valid_w) 210 | ,.cfg_data_i(dqt_cfg_data_w) 211 | ,.cfg_last_i(dqt_cfg_last_w) 212 | ,.inport_valid_i(dqt_inport_valid_w) 213 | ,.inport_data_i(dqt_outport_data_w) 214 | ,.inport_idx_i(dqt_inport_idx_w) 215 | ,.inport_id_i(dqt_inport_id_w) 216 | ,.inport_eob_i(dqt_inport_eob_w) 217 | ,.outport_accept_i(idct_inport_accept_w) 218 | 219 | // Outputs 220 | ,.cfg_accept_o(dqt_cfg_accept_w) 221 | ,.inport_blk_space_o(dqt_inport_blk_space_w) 222 | ,.outport_valid_o(idct_inport_valid_w) 223 | ,.outport_data_o(idct_outport_data_w) 224 | ,.outport_idx_o(idct_inport_idx_w) 225 | ,.outport_id_o(idct_inport_id_w) 226 | ,.outport_eob_o(idct_inport_eob_w) 227 | ); 228 | 229 | 230 | jpeg_output 231 | u_jpeg_output 232 | ( 233 | // Inputs 234 | .clk_i(clk_i) 235 | ,.rst_i(rst_i) 236 | ,.img_start_i(img_start_w) 237 | ,.img_end_i(img_end_w) 238 | ,.img_width_i(img_width_w) 239 | ,.img_height_i(img_height_w) 240 | ,.img_mode_i(img_mode_w) 241 | ,.inport_valid_i(output_inport_valid_w) 242 | ,.inport_data_i(output_outport_data_w) 243 | ,.inport_idx_i(output_inport_idx_w) 244 | ,.inport_id_i(output_inport_id_w) 245 | ,.outport_accept_i(outport_accept_i) 246 | 247 | // Outputs 248 | ,.inport_accept_o(output_inport_accept_w) 249 | ,.outport_valid_o(outport_valid_o) 250 | ,.outport_width_o(outport_width_o) 251 | ,.outport_height_o(outport_height_o) 252 | ,.outport_pixel_x_o(outport_pixel_x_o) 253 | ,.outport_pixel_y_o(outport_pixel_y_o) 254 | ,.outport_pixel_r_o(outport_pixel_r_o) 255 | ,.outport_pixel_g_o(outport_pixel_g_o) 256 | ,.outport_pixel_b_o(outport_pixel_b_o) 257 | ,.idle_o(idle_o) 258 | ); 259 | 260 | 261 | jpeg_bitbuffer 262 | u_jpeg_bitbuffer 263 | ( 264 | // Inputs 265 | .clk_i(clk_i) 266 | ,.rst_i(rst_i) 267 | ,.img_start_i(img_start_w) 268 | ,.img_end_i(img_end_w) 269 | ,.inport_valid_i(bb_inport_valid_w) 270 | ,.inport_data_i(bb_inport_data_w) 271 | ,.inport_last_i(bb_inport_last_w) 272 | ,.outport_pop_i(bb_outport_pop_w) 273 | 274 | // Outputs 275 | ,.inport_accept_o(bb_inport_accept_w) 276 | ,.outport_valid_o(bb_outport_valid_w) 277 | ,.outport_data_o(bb_outport_data_w) 278 | ,.outport_last_o(bb_outport_last_w) 279 | ); 280 | 281 | 282 | jpeg_mcu_proc 283 | u_jpeg_mcu_proc 284 | ( 285 | // Inputs 286 | .clk_i(clk_i) 287 | ,.rst_i(rst_i) 288 | ,.img_start_i(img_start_w) 289 | ,.img_end_i(img_end_w) 290 | ,.img_width_i(img_width_w) 291 | ,.img_height_i(img_height_w) 292 | ,.img_mode_i(img_mode_w) 293 | ,.inport_valid_i(bb_outport_valid_w) 294 | ,.inport_data_i(bb_outport_data_w) 295 | ,.inport_last_i(bb_outport_last_w) 296 | ,.lookup_valid_i(lookup_valid_w) 297 | ,.lookup_width_i(lookup_width_w) 298 | ,.lookup_value_i(lookup_value_w) 299 | ,.outport_blk_space_i(dqt_inport_blk_space_w) 300 | 301 | // Outputs 302 | ,.inport_pop_o(bb_outport_pop_w) 303 | ,.lookup_req_o(lookup_req_w) 304 | ,.lookup_table_o(lookup_table_w) 305 | ,.lookup_input_o(lookup_input_w) 306 | ,.outport_valid_o(dqt_inport_valid_w) 307 | ,.outport_data_o(dqt_outport_data_w) 308 | ,.outport_idx_o(dqt_inport_idx_w) 309 | ,.outport_id_o(dqt_inport_id_w) 310 | ,.outport_eob_o(dqt_inport_eob_w) 311 | ); 312 | 313 | 314 | 315 | endmodule 316 | -------------------------------------------------------------------------------- /src_v/jpeg_dht_std_cx_dc.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | module jpeg_dht_std_cx_dc 32 | ( 33 | input [ 15:0] lookup_input_i 34 | ,output [ 4:0] lookup_width_o 35 | ,output [ 7:0] lookup_value_o 36 | ); 37 | 38 | //----------------------------------------------------------------- 39 | // Cx DC Table (standard) 40 | //----------------------------------------------------------------- 41 | reg [7:0] cx_dc_value_r; 42 | reg [4:0] cx_dc_width_r; 43 | 44 | always @ * 45 | begin 46 | cx_dc_value_r = 8'b0; 47 | cx_dc_width_r = 5'b0; 48 | 49 | if (lookup_input_i[15:14] == 2'h0) 50 | begin 51 | cx_dc_value_r = 8'h00; 52 | cx_dc_width_r = 5'd2; 53 | end 54 | else if (lookup_input_i[15:14] == 2'h1) 55 | begin 56 | cx_dc_value_r = 8'h01; 57 | cx_dc_width_r = 5'd2; 58 | end 59 | else if (lookup_input_i[15:14] == 2'h2) 60 | begin 61 | cx_dc_value_r = 8'h02; 62 | cx_dc_width_r = 5'd2; 63 | end 64 | else if (lookup_input_i[15:13] == 3'h6) 65 | begin 66 | cx_dc_value_r = 8'h03; 67 | cx_dc_width_r = 5'd3; 68 | end 69 | else if (lookup_input_i[15:12] == 4'he) 70 | begin 71 | cx_dc_value_r = 8'h04; 72 | cx_dc_width_r = 5'd4; 73 | end 74 | else if (lookup_input_i[15:11] == 5'h1e) 75 | begin 76 | cx_dc_value_r = 8'h05; 77 | cx_dc_width_r = 5'd5; 78 | end 79 | else if (lookup_input_i[15:10] == 6'h3e) 80 | begin 81 | cx_dc_value_r = 8'h06; 82 | cx_dc_width_r = 5'd6; 83 | end 84 | else if (lookup_input_i[15:9] == 7'h7e) 85 | begin 86 | cx_dc_value_r = 8'h07; 87 | cx_dc_width_r = 5'd7; 88 | end 89 | else if (lookup_input_i[15:8] == 8'hfe) 90 | begin 91 | cx_dc_value_r = 8'h08; 92 | cx_dc_width_r = 5'd8; 93 | end 94 | else if (lookup_input_i[15:7] == 9'h1fe) 95 | begin 96 | cx_dc_value_r = 8'h09; 97 | cx_dc_width_r = 5'd9; 98 | end 99 | else if (lookup_input_i[15:6] == 10'h3fe) 100 | begin 101 | cx_dc_value_r = 8'h0a; 102 | cx_dc_width_r = 5'd10; 103 | end 104 | else if (lookup_input_i[15:5] == 11'h7fe) 105 | begin 106 | cx_dc_value_r = 8'h0b; 107 | cx_dc_width_r = 5'd11; 108 | end 109 | end 110 | 111 | assign lookup_width_o = cx_dc_width_r; 112 | assign lookup_value_o = cx_dc_value_r; 113 | 114 | endmodule 115 | 116 | -------------------------------------------------------------------------------- /src_v/jpeg_dht_std_y_dc.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | module jpeg_dht_std_y_dc 32 | ( 33 | input [ 15:0] lookup_input_i 34 | ,output [ 4:0] lookup_width_o 35 | ,output [ 7:0] lookup_value_o 36 | ); 37 | 38 | //----------------------------------------------------------------- 39 | // Y DC Table (standard) 40 | //----------------------------------------------------------------- 41 | reg [7:0] y_dc_value_r; 42 | reg [4:0] y_dc_width_r; 43 | 44 | always @ * 45 | begin 46 | y_dc_value_r = 8'b0; 47 | y_dc_width_r = 5'b0; 48 | 49 | if (lookup_input_i[15:14] == 2'h0) 50 | begin 51 | y_dc_value_r = 8'h00; 52 | y_dc_width_r = 5'd2; 53 | end 54 | else if (lookup_input_i[15:13] == 3'h2) 55 | begin 56 | y_dc_value_r = 8'h01; 57 | y_dc_width_r = 5'd3; 58 | end 59 | else if (lookup_input_i[15:13] == 3'h3) 60 | begin 61 | y_dc_value_r = 8'h02; 62 | y_dc_width_r = 5'd3; 63 | end 64 | else if (lookup_input_i[15:13] == 3'h4) 65 | begin 66 | y_dc_value_r = 8'h03; 67 | y_dc_width_r = 5'd3; 68 | end 69 | else if (lookup_input_i[15:13] == 3'h5) 70 | begin 71 | y_dc_value_r = 8'h04; 72 | y_dc_width_r = 5'd3; 73 | end 74 | else if (lookup_input_i[15:13] == 3'h6) 75 | begin 76 | y_dc_value_r = 8'h05; 77 | y_dc_width_r = 5'd3; 78 | end 79 | else if (lookup_input_i[15:12] == 4'he) 80 | begin 81 | y_dc_value_r = 8'h06; 82 | y_dc_width_r = 5'd4; 83 | end 84 | else if (lookup_input_i[15:11] == 5'h1e) 85 | begin 86 | y_dc_value_r = 8'h07; 87 | y_dc_width_r = 5'd5; 88 | end 89 | else if (lookup_input_i[15:10] == 6'h3e) 90 | begin 91 | y_dc_value_r = 8'h08; 92 | y_dc_width_r = 5'd6; 93 | end 94 | else if (lookup_input_i[15:9] == 7'h7e) 95 | begin 96 | y_dc_value_r = 8'h09; 97 | y_dc_width_r = 5'd7; 98 | end 99 | else if (lookup_input_i[15:8] == 8'hfe) 100 | begin 101 | y_dc_value_r = 8'h0a; 102 | y_dc_width_r = 5'd8; 103 | end 104 | else if (lookup_input_i[15:7] == 9'h1fe) 105 | begin 106 | y_dc_value_r = 8'h0b; 107 | y_dc_width_r = 5'd9; 108 | end 109 | end 110 | 111 | assign lookup_width_o = y_dc_width_r; 112 | assign lookup_value_o = y_dc_value_r; 113 | 114 | endmodule -------------------------------------------------------------------------------- /src_v/jpeg_dqt.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_dqt 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input [ 1:0] img_dqt_table_y_i 40 | ,input [ 1:0] img_dqt_table_cb_i 41 | ,input [ 1:0] img_dqt_table_cr_i 42 | ,input cfg_valid_i 43 | ,input [ 7:0] cfg_data_i 44 | ,input cfg_last_i 45 | ,input inport_valid_i 46 | ,input [ 15:0] inport_data_i 47 | ,input [ 5:0] inport_idx_i 48 | ,input [ 31:0] inport_id_i 49 | ,input inport_eob_i 50 | ,input outport_accept_i 51 | 52 | // Outputs 53 | ,output cfg_accept_o 54 | ,output inport_blk_space_o 55 | ,output outport_valid_o 56 | ,output [ 15:0] outport_data_o 57 | ,output [ 5:0] outport_idx_o 58 | ,output [ 31:0] outport_id_o 59 | ,output outport_eob_o 60 | ); 61 | 62 | 63 | 64 | //----------------------------------------------------------------- 65 | // DQT tables 66 | //----------------------------------------------------------------- 67 | // 4 * 256 68 | reg [7:0] table_dqt_q[0:255]; 69 | 70 | //----------------------------------------------------------------- 71 | // Capture Index 72 | //----------------------------------------------------------------- 73 | reg [7:0] idx_q; 74 | 75 | always @ (posedge clk_i ) 76 | if (rst_i) 77 | idx_q <= 8'hFF; 78 | else if (cfg_valid_i && cfg_last_i && cfg_accept_o) 79 | idx_q <= 8'hFF; 80 | else if (cfg_valid_i && cfg_accept_o) 81 | idx_q <= idx_q + 8'd1; 82 | 83 | assign cfg_accept_o = 1'b1; 84 | 85 | //----------------------------------------------------------------- 86 | // Write DQT table 87 | //----------------------------------------------------------------- 88 | reg [1:0] cfg_table_q; 89 | 90 | always @ (posedge clk_i ) 91 | if (rst_i) 92 | cfg_table_q <= 2'b0; 93 | else if (cfg_valid_i && cfg_accept_o && idx_q == 8'hFF) 94 | cfg_table_q <= cfg_data_i[1:0]; 95 | 96 | wire [7:0] cfg_table_addr_w = {cfg_table_q, idx_q[5:0]}; 97 | 98 | wire [1:0] table_src_w[3:0]; 99 | 100 | assign table_src_w[0] = img_dqt_table_y_i; 101 | assign table_src_w[1] = img_dqt_table_cb_i; 102 | assign table_src_w[2] = img_dqt_table_cr_i; 103 | assign table_src_w[3] = 2'b0; 104 | 105 | wire [7:0] table_rd_idx_w = {table_src_w[inport_id_i[31:30]], inport_idx_i}; 106 | 107 | wire dqt_write_w = cfg_valid_i && cfg_accept_o && idx_q != 8'hFF; 108 | wire [7:0] dqt_table_addr_w = dqt_write_w ? cfg_table_addr_w : table_rd_idx_w; 109 | 110 | reg [7:0] dqt_entry_q; 111 | 112 | always @ (posedge clk_i ) 113 | begin 114 | if (dqt_write_w) 115 | table_dqt_q[dqt_table_addr_w] <= cfg_data_i; 116 | 117 | dqt_entry_q <= table_dqt_q[dqt_table_addr_w]; 118 | end 119 | 120 | //----------------------------------------------------------------- 121 | // dezigzag: Reverse zigzag process 122 | //----------------------------------------------------------------- 123 | function [5:0] dezigzag; 124 | input [5:0] idx; 125 | reg [5:0] out_idx; 126 | begin 127 | case (idx) 128 | 6'd0: out_idx = 6'd0; 129 | 6'd1: out_idx = 6'd1; 130 | 6'd2: out_idx = 6'd8; 131 | 6'd3: out_idx = 6'd16; 132 | 6'd4: out_idx = 6'd9; 133 | 6'd5: out_idx = 6'd2; 134 | 6'd6: out_idx = 6'd3; 135 | 6'd7: out_idx = 6'd10; 136 | 6'd8: out_idx = 6'd17; 137 | 6'd9: out_idx = 6'd24; 138 | 6'd10: out_idx = 6'd32; 139 | 6'd11: out_idx = 6'd25; 140 | 6'd12: out_idx = 6'd18; 141 | 6'd13: out_idx = 6'd11; 142 | 6'd14: out_idx = 6'd4; 143 | 6'd15: out_idx = 6'd5; 144 | 6'd16: out_idx = 6'd12; 145 | 6'd17: out_idx = 6'd19; 146 | 6'd18: out_idx = 6'd26; 147 | 6'd19: out_idx = 6'd33; 148 | 6'd20: out_idx = 6'd40; 149 | 6'd21: out_idx = 6'd48; 150 | 6'd22: out_idx = 6'd41; 151 | 6'd23: out_idx = 6'd34; 152 | 6'd24: out_idx = 6'd27; 153 | 6'd25: out_idx = 6'd20; 154 | 6'd26: out_idx = 6'd13; 155 | 6'd27: out_idx = 6'd6; 156 | 6'd28: out_idx = 6'd7; 157 | 6'd29: out_idx = 6'd14; 158 | 6'd30: out_idx = 6'd21; 159 | 6'd31: out_idx = 6'd28; 160 | 6'd32: out_idx = 6'd35; 161 | 6'd33: out_idx = 6'd42; 162 | 6'd34: out_idx = 6'd49; 163 | 6'd35: out_idx = 6'd56; 164 | 6'd36: out_idx = 6'd57; 165 | 6'd37: out_idx = 6'd50; 166 | 6'd38: out_idx = 6'd43; 167 | 6'd39: out_idx = 6'd36; 168 | 6'd40: out_idx = 6'd29; 169 | 6'd41: out_idx = 6'd22; 170 | 6'd42: out_idx = 6'd15; 171 | 6'd43: out_idx = 6'd23; 172 | 6'd44: out_idx = 6'd30; 173 | 6'd45: out_idx = 6'd37; 174 | 6'd46: out_idx = 6'd44; 175 | 6'd47: out_idx = 6'd51; 176 | 6'd48: out_idx = 6'd58; 177 | 6'd49: out_idx = 6'd59; 178 | 6'd50: out_idx = 6'd52; 179 | 6'd51: out_idx = 6'd45; 180 | 6'd52: out_idx = 6'd38; 181 | 6'd53: out_idx = 6'd31; 182 | 6'd54: out_idx = 6'd39; 183 | 6'd55: out_idx = 6'd46; 184 | 6'd56: out_idx = 6'd53; 185 | 6'd57: out_idx = 6'd60; 186 | 6'd58: out_idx = 6'd61; 187 | 6'd59: out_idx = 6'd54; 188 | 6'd60: out_idx = 6'd47; 189 | 6'd61: out_idx = 6'd55; 190 | 6'd62: out_idx = 6'd62; 191 | default: out_idx = 6'd63; 192 | endcase 193 | 194 | dezigzag = out_idx; 195 | end 196 | endfunction 197 | 198 | //----------------------------------------------------------------- 199 | // Process dequantisation and dezigzag 200 | //----------------------------------------------------------------- 201 | reg inport_valid_q; 202 | reg [15:0] inport_data_q; 203 | reg [5:0] inport_idx_q; 204 | reg [31:0] inport_id_q; 205 | reg inport_eob_q; 206 | 207 | always @ (posedge clk_i ) 208 | if (rst_i) 209 | inport_valid_q <= 1'b0; 210 | else 211 | inport_valid_q <= inport_valid_i && ~img_start_i; 212 | 213 | always @ (posedge clk_i ) 214 | if (rst_i) 215 | inport_idx_q <= 6'b0; 216 | else 217 | inport_idx_q <= inport_idx_i; 218 | 219 | always @ (posedge clk_i ) 220 | if (rst_i) 221 | inport_data_q <= 16'b0; 222 | else 223 | inport_data_q <= inport_data_i; 224 | 225 | always @ (posedge clk_i ) 226 | if (rst_i) 227 | inport_id_q <= 32'b0; 228 | else if (inport_valid_i) 229 | inport_id_q <= inport_id_i; 230 | 231 | always @ (posedge clk_i ) 232 | if (rst_i) 233 | inport_eob_q <= 1'b0; 234 | else 235 | inport_eob_q <= inport_eob_i; 236 | 237 | //----------------------------------------------------------------- 238 | // Output 239 | //----------------------------------------------------------------- 240 | reg outport_valid_q; 241 | reg signed [15:0] outport_data_q; 242 | reg [5:0] outport_idx_q; 243 | reg [31:0] outport_id_q; 244 | reg outport_eob_q; 245 | 246 | always @ (posedge clk_i ) 247 | if (rst_i) 248 | outport_valid_q <= 1'b0; 249 | else 250 | outport_valid_q <= inport_valid_q && ~img_start_i; 251 | 252 | always @ (posedge clk_i ) 253 | if (rst_i) 254 | outport_data_q <= 16'b0; 255 | else 256 | outport_data_q <= inport_data_q * dqt_entry_q; 257 | 258 | always @ (posedge clk_i ) 259 | if (rst_i) 260 | outport_idx_q <= 6'b0; 261 | else 262 | outport_idx_q <= dezigzag(inport_idx_q); 263 | 264 | always @ (posedge clk_i ) 265 | if (rst_i) 266 | outport_id_q <= 32'b0; 267 | else 268 | outport_id_q <= inport_id_q; 269 | 270 | always @ (posedge clk_i ) 271 | if (rst_i) 272 | outport_eob_q <= 1'b0; 273 | else 274 | outport_eob_q <= inport_eob_q; 275 | 276 | assign outport_valid_o = outport_valid_q; 277 | assign outport_data_o = outport_data_q; 278 | assign outport_idx_o = outport_idx_q; 279 | assign outport_id_o = outport_id_q; 280 | assign outport_eob_o = outport_eob_q; 281 | 282 | // TODO: Perf 283 | assign inport_blk_space_o = outport_accept_i && !(outport_eob_q || inport_eob_q); 284 | 285 | `ifdef verilator 286 | function get_valid; /*verilator public*/ 287 | begin 288 | get_valid = outport_valid_o; 289 | end 290 | endfunction 291 | function [15:0] get_sample; /*verilator public*/ 292 | begin 293 | get_sample = outport_data_o; 294 | end 295 | endfunction 296 | function [5:0] get_sample_idx; /*verilator public*/ 297 | begin 298 | get_sample_idx = outport_idx_o; 299 | end 300 | endfunction 301 | `endif 302 | 303 | endmodule 304 | -------------------------------------------------------------------------------- /src_v/jpeg_idct.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input inport_valid_i 40 | ,input [ 15:0] inport_data_i 41 | ,input [ 5:0] inport_idx_i 42 | ,input inport_eob_i 43 | ,input [ 31:0] inport_id_i 44 | ,input outport_accept_i 45 | 46 | // Outputs 47 | ,output inport_accept_o 48 | ,output outport_valid_o 49 | ,output [ 31:0] outport_data_o 50 | ,output [ 5:0] outport_idx_o 51 | ,output [ 31:0] outport_id_o 52 | ); 53 | 54 | 55 | 56 | 57 | wire input_valid_w; 58 | wire [ 15:0] input_data0_w; 59 | wire [ 15:0] input_data1_w; 60 | wire [ 15:0] input_data2_w; 61 | wire [ 15:0] input_data3_w; 62 | wire [ 2:0] input_idx_w; 63 | wire input_ready_w; 64 | 65 | 66 | jpeg_idct_ram 67 | u_input 68 | ( 69 | .clk_i(clk_i) 70 | ,.rst_i(rst_i) 71 | 72 | ,.img_start_i(img_start_i) 73 | ,.img_end_i(img_end_i) 74 | 75 | ,.inport_valid_i(inport_valid_i) 76 | ,.inport_data_i(inport_data_i) 77 | ,.inport_idx_i(inport_idx_i) 78 | ,.inport_eob_i(inport_eob_i) 79 | ,.inport_accept_o(inport_accept_o) 80 | 81 | ,.outport_valid_o(input_valid_w) 82 | ,.outport_data0_o(input_data0_w) 83 | ,.outport_data1_o(input_data1_w) 84 | ,.outport_data2_o(input_data2_w) 85 | ,.outport_data3_o(input_data3_w) 86 | ,.outport_idx_o(input_idx_w) 87 | ,.outport_ready_i(outport_accept_i) 88 | ); 89 | 90 | wire idct_x_valid_w; 91 | wire [ 31:0] idct_x_data_w; 92 | wire [ 5:0] idct_x_idx_w; 93 | wire idct_x_accept_w; 94 | 95 | jpeg_idct_x 96 | u_idct_x 97 | ( 98 | .clk_i(clk_i) 99 | ,.rst_i(rst_i) 100 | 101 | ,.img_start_i(img_start_i) 102 | ,.img_end_i(img_end_i) 103 | 104 | ,.inport_valid_i(input_valid_w) 105 | ,.inport_data0_i(input_data0_w) 106 | ,.inport_data1_i(input_data1_w) 107 | ,.inport_data2_i(input_data2_w) 108 | ,.inport_data3_i(input_data3_w) 109 | ,.inport_idx_i(input_idx_w) 110 | 111 | ,.outport_valid_o(idct_x_valid_w) 112 | ,.outport_data_o(idct_x_data_w) 113 | ,.outport_idx_o(idct_x_idx_w) 114 | ); 115 | 116 | wire transpose_valid_w; 117 | wire [ 31:0] transpose_data0_w; 118 | wire [ 31:0] transpose_data1_w; 119 | wire [ 31:0] transpose_data2_w; 120 | wire [ 31:0] transpose_data3_w; 121 | wire [ 2:0] transpose_idx_w; 122 | wire transpose_ready_w = 1'b1; 123 | 124 | jpeg_idct_transpose 125 | u_transpose 126 | ( 127 | .clk_i(clk_i) 128 | ,.rst_i(rst_i) 129 | 130 | ,.img_start_i(img_start_i) 131 | ,.img_end_i(img_end_i) 132 | 133 | ,.inport_valid_i(idct_x_valid_w) 134 | ,.inport_data_i(idct_x_data_w) 135 | ,.inport_idx_i(idct_x_idx_w) 136 | ,.inport_accept_o(idct_x_accept_w) 137 | 138 | ,.outport_valid_o(transpose_valid_w) 139 | ,.outport_data0_o(transpose_data0_w) 140 | ,.outport_data1_o(transpose_data1_w) 141 | ,.outport_data2_o(transpose_data2_w) 142 | ,.outport_data3_o(transpose_data3_w) 143 | ,.outport_idx_o(transpose_idx_w) 144 | ,.outport_ready_i(transpose_ready_w) 145 | ); 146 | 147 | jpeg_idct_y 148 | u_idct_y 149 | ( 150 | .clk_i(clk_i) 151 | ,.rst_i(rst_i) 152 | 153 | ,.img_start_i(img_start_i) 154 | ,.img_end_i(img_end_i) 155 | 156 | ,.inport_valid_i(transpose_valid_w) 157 | ,.inport_data0_i(transpose_data0_w) 158 | ,.inport_data1_i(transpose_data1_w) 159 | ,.inport_data2_i(transpose_data2_w) 160 | ,.inport_data3_i(transpose_data3_w) 161 | ,.inport_idx_i(transpose_idx_w) 162 | 163 | ,.outport_valid_o(outport_valid_o) 164 | ,.outport_data_o(outport_data_o) 165 | ,.outport_idx_o(outport_idx_o) 166 | ); 167 | 168 | 169 | jpeg_idct_fifo 170 | #( 171 | .WIDTH(32) 172 | ,.DEPTH(8) 173 | ,.ADDR_W(3) 174 | ) 175 | u_id_fifo 176 | ( 177 | .clk_i(clk_i) 178 | ,.rst_i(rst_i) 179 | 180 | ,.flush_i(img_start_i) 181 | 182 | ,.push_i(inport_eob_i) 183 | ,.data_in_i(inport_id_i) 184 | ,.accept_o() 185 | 186 | ,.valid_o() 187 | ,.data_out_o(outport_id_o) 188 | ,.pop_i(outport_valid_o && outport_idx_o == 6'd63) 189 | ); 190 | 191 | `ifdef verilator 192 | function get_valid; /*verilator public*/ 193 | begin 194 | get_valid = outport_valid_o; 195 | end 196 | endfunction 197 | function [5:0] get_sample_idx; /*verilator public*/ 198 | begin 199 | get_sample_idx = outport_idx_o; 200 | end 201 | endfunction 202 | function [31:0] get_sample; /*verilator public*/ 203 | begin 204 | get_sample = outport_data_o; 205 | end 206 | endfunction 207 | `endif 208 | 209 | 210 | endmodule 211 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_fifo.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_fifo 33 | //----------------------------------------------------------------- 34 | // Params 35 | //----------------------------------------------------------------- 36 | #( 37 | parameter WIDTH = 8 38 | ,parameter DEPTH = 4 39 | ,parameter ADDR_W = 2 40 | ) 41 | //----------------------------------------------------------------- 42 | // Ports 43 | //----------------------------------------------------------------- 44 | ( 45 | // Inputs 46 | input clk_i 47 | ,input rst_i 48 | ,input [WIDTH-1:0] data_in_i 49 | ,input push_i 50 | ,input pop_i 51 | ,input flush_i 52 | 53 | // Outputs 54 | ,output [WIDTH-1:0] data_out_o 55 | ,output accept_o 56 | ,output valid_o 57 | ); 58 | 59 | 60 | 61 | //----------------------------------------------------------------- 62 | // Local Params 63 | //----------------------------------------------------------------- 64 | localparam COUNT_W = ADDR_W + 1; 65 | 66 | //----------------------------------------------------------------- 67 | // Registers 68 | //----------------------------------------------------------------- 69 | reg [WIDTH-1:0] ram_q[DEPTH-1:0]; 70 | reg [ADDR_W-1:0] rd_ptr_q; 71 | reg [ADDR_W-1:0] wr_ptr_q; 72 | reg [COUNT_W-1:0] count_q; 73 | 74 | //----------------------------------------------------------------- 75 | // Sequential 76 | //----------------------------------------------------------------- 77 | always @ (posedge clk_i or posedge rst_i) 78 | if (rst_i) 79 | begin 80 | count_q <= {(COUNT_W) {1'b0}}; 81 | rd_ptr_q <= {(ADDR_W) {1'b0}}; 82 | wr_ptr_q <= {(ADDR_W) {1'b0}}; 83 | end 84 | else if (flush_i) 85 | begin 86 | count_q <= {(COUNT_W) {1'b0}}; 87 | rd_ptr_q <= {(ADDR_W) {1'b0}}; 88 | wr_ptr_q <= {(ADDR_W) {1'b0}}; 89 | end 90 | else 91 | begin 92 | // Push 93 | if (push_i & accept_o) 94 | begin 95 | ram_q[wr_ptr_q] <= data_in_i; 96 | wr_ptr_q <= wr_ptr_q + 1; 97 | end 98 | 99 | // Pop 100 | if (pop_i & valid_o) 101 | rd_ptr_q <= rd_ptr_q + 1; 102 | 103 | // Count up 104 | if ((push_i & accept_o) & ~(pop_i & valid_o)) 105 | count_q <= count_q + 1; 106 | // Count down 107 | else if (~(push_i & accept_o) & (pop_i & valid_o)) 108 | count_q <= count_q - 1; 109 | end 110 | 111 | //------------------------------------------------------------------- 112 | // Combinatorial 113 | //------------------------------------------------------------------- 114 | /* verilator lint_off WIDTH */ 115 | assign valid_o = (count_q != 0); 116 | assign accept_o = (count_q != DEPTH); 117 | /* verilator lint_on WIDTH */ 118 | 119 | assign data_out_o = ram_q[rd_ptr_q]; 120 | 121 | 122 | 123 | endmodule 124 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_ram 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input inport_valid_i 40 | ,input [ 15:0] inport_data_i 41 | ,input [ 5:0] inport_idx_i 42 | ,input inport_eob_i 43 | ,input outport_ready_i 44 | 45 | // Outputs 46 | ,output inport_accept_o 47 | ,output outport_valid_o 48 | ,output [ 15:0] outport_data0_o 49 | ,output [ 15:0] outport_data1_o 50 | ,output [ 15:0] outport_data2_o 51 | ,output [ 15:0] outport_data3_o 52 | ,output [ 2:0] outport_idx_o 53 | ); 54 | 55 | 56 | 57 | reg [1:0] block_wr_q; 58 | reg [1:0] block_rd_q; 59 | reg [5:0] rd_idx_q; 60 | reg [3:0] rd_addr_q; 61 | 62 | wire [5:0] wr_ptr_w = {block_wr_q, inport_idx_i[5:3], inport_idx_i[0]}; 63 | 64 | wire [15:0] outport_data0_w; 65 | wire [15:0] outport_data1_w; 66 | wire [15:0] outport_data2_w; 67 | wire [15:0] outport_data3_w; 68 | 69 | wire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd0 || inport_idx_i[2:0] == 3'd1); 70 | wire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd2 || inport_idx_i[2:0] == 3'd3); 71 | wire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd4 || inport_idx_i[2:0] == 3'd5); 72 | wire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[2:0] == 3'd6 || inport_idx_i[2:0] == 3'd7); 73 | 74 | jpeg_idct_ram_dp 75 | u_ram0 76 | ( 77 | .clk0_i(clk_i) 78 | ,.rst0_i(rst_i) 79 | ,.clk1_i(clk_i) 80 | ,.rst1_i(rst_i) 81 | 82 | ,.addr0_i(wr_ptr_w) 83 | ,.data0_i(inport_data_i) 84 | ,.wr0_i(wr0_w) 85 | ,.data0_o() 86 | 87 | ,.addr1_i({block_rd_q, rd_addr_q}) 88 | ,.data1_i(16'b0) 89 | ,.wr1_i(1'b0) 90 | ,.data1_o(outport_data0_w) 91 | ); 92 | 93 | jpeg_idct_ram_dp 94 | u_ram1 95 | ( 96 | .clk0_i(clk_i) 97 | ,.rst0_i(rst_i) 98 | ,.clk1_i(clk_i) 99 | ,.rst1_i(rst_i) 100 | 101 | ,.addr0_i(wr_ptr_w) 102 | ,.data0_i(inport_data_i) 103 | ,.wr0_i(wr1_w) 104 | ,.data0_o() 105 | 106 | ,.addr1_i({block_rd_q, rd_addr_q}) 107 | ,.data1_i(16'b0) 108 | ,.wr1_i(1'b0) 109 | ,.data1_o(outport_data1_w) 110 | ); 111 | 112 | jpeg_idct_ram_dp 113 | u_ram2 114 | ( 115 | .clk0_i(clk_i) 116 | ,.rst0_i(rst_i) 117 | ,.clk1_i(clk_i) 118 | ,.rst1_i(rst_i) 119 | 120 | ,.addr0_i(wr_ptr_w) 121 | ,.data0_i(inport_data_i) 122 | ,.wr0_i(wr2_w) 123 | ,.data0_o() 124 | 125 | ,.addr1_i({block_rd_q, rd_addr_q}) 126 | ,.data1_i(16'b0) 127 | ,.wr1_i(1'b0) 128 | ,.data1_o(outport_data2_w) 129 | ); 130 | 131 | jpeg_idct_ram_dp 132 | u_ram3 133 | ( 134 | .clk0_i(clk_i) 135 | ,.rst0_i(rst_i) 136 | ,.clk1_i(clk_i) 137 | ,.rst1_i(rst_i) 138 | 139 | ,.addr0_i(wr_ptr_w) 140 | ,.data0_i(inport_data_i) 141 | ,.wr0_i(wr3_w) 142 | ,.data0_o() 143 | 144 | ,.addr1_i({block_rd_q, rd_addr_q}) 145 | ,.data1_i(16'b0) 146 | ,.wr1_i(1'b0) 147 | ,.data1_o(outport_data3_w) 148 | ); 149 | 150 | //----------------------------------------------------------------- 151 | // Data Qualifiers 152 | //----------------------------------------------------------------- 153 | reg [63:0] data_valid0_r; 154 | reg [63:0] data_valid0_q; 155 | 156 | always @ * 157 | begin 158 | data_valid0_r = data_valid0_q; 159 | 160 | // End of block read out - reset data valid state 161 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 162 | begin 163 | case (block_rd_q) 164 | 2'd0: data_valid0_r[15:0] = 16'b0; 165 | 2'd1: data_valid0_r[31:16] = 16'b0; 166 | 2'd2: data_valid0_r[47:32] = 16'b0; 167 | default: data_valid0_r[63:48] = 16'b0; 168 | endcase 169 | end 170 | 171 | if (wr0_w) 172 | data_valid0_r[wr_ptr_w] = 1'b1; 173 | end 174 | 175 | always @ (posedge clk_i ) 176 | if (rst_i) 177 | data_valid0_q <= 64'b0; 178 | else if (img_start_i) 179 | data_valid0_q <= 64'b0; 180 | else 181 | data_valid0_q <= data_valid0_r; 182 | 183 | reg [63:0] data_valid1_r; 184 | reg [63:0] data_valid1_q; 185 | 186 | always @ * 187 | begin 188 | data_valid1_r = data_valid1_q; 189 | 190 | // End of block read out - reset data valid state 191 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 192 | begin 193 | case (block_rd_q) 194 | 2'd0: data_valid1_r[15:0] = 16'b0; 195 | 2'd1: data_valid1_r[31:16] = 16'b0; 196 | 2'd2: data_valid1_r[47:32] = 16'b0; 197 | default: data_valid1_r[63:48] = 16'b0; 198 | endcase 199 | end 200 | 201 | if (wr1_w) 202 | data_valid1_r[wr_ptr_w] = 1'b1; 203 | end 204 | 205 | always @ (posedge clk_i ) 206 | if (rst_i) 207 | data_valid1_q <= 64'b0; 208 | else if (img_start_i) 209 | data_valid1_q <= 64'b0; 210 | else 211 | data_valid1_q <= data_valid1_r; 212 | 213 | reg [63:0] data_valid2_r; 214 | reg [63:0] data_valid2_q; 215 | 216 | always @ * 217 | begin 218 | data_valid2_r = data_valid2_q; 219 | 220 | // End of block read out - reset data valid state 221 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 222 | begin 223 | case (block_rd_q) 224 | 2'd0: data_valid2_r[15:0] = 16'b0; 225 | 2'd1: data_valid2_r[31:16] = 16'b0; 226 | 2'd2: data_valid2_r[47:32] = 16'b0; 227 | default: data_valid2_r[63:48] = 16'b0; 228 | endcase 229 | end 230 | 231 | if (wr2_w) 232 | data_valid2_r[wr_ptr_w] = 1'b1; 233 | end 234 | 235 | always @ (posedge clk_i ) 236 | if (rst_i) 237 | data_valid2_q <= 64'b0; 238 | else if (img_start_i) 239 | data_valid2_q <= 64'b0; 240 | else 241 | data_valid2_q <= data_valid2_r; 242 | 243 | reg [63:0] data_valid3_r; 244 | reg [63:0] data_valid3_q; 245 | 246 | always @ * 247 | begin 248 | data_valid3_r = data_valid3_q; 249 | 250 | // End of block read out - reset data valid state 251 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 252 | begin 253 | case (block_rd_q) 254 | 2'd0: data_valid3_r[15:0] = 16'b0; 255 | 2'd1: data_valid3_r[31:16] = 16'b0; 256 | 2'd2: data_valid3_r[47:32] = 16'b0; 257 | default: data_valid3_r[63:48] = 16'b0; 258 | endcase 259 | end 260 | 261 | if (wr3_w) 262 | data_valid3_r[wr_ptr_w] = 1'b1; 263 | end 264 | 265 | always @ (posedge clk_i ) 266 | if (rst_i) 267 | data_valid3_q <= 64'b0; 268 | else if (img_start_i) 269 | data_valid3_q <= 64'b0; 270 | else 271 | data_valid3_q <= data_valid3_r; 272 | 273 | 274 | //----------------------------------------------------------------- 275 | // Input Buffer 276 | //----------------------------------------------------------------- 277 | reg [3:0] block_ready_q; 278 | 279 | always @ (posedge clk_i ) 280 | if (rst_i) 281 | begin 282 | block_ready_q <= 4'b0; 283 | block_wr_q <= 2'b0; 284 | block_rd_q <= 2'b0; 285 | end 286 | else if (img_start_i) 287 | begin 288 | block_ready_q <= 4'b0; 289 | block_wr_q <= 2'b0; 290 | block_rd_q <= 2'b0; 291 | end 292 | else 293 | begin 294 | if (inport_eob_i && inport_accept_o) 295 | begin 296 | block_ready_q[block_wr_q] <= 1'b1; 297 | block_wr_q <= block_wr_q + 2'd1; 298 | end 299 | 300 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 301 | begin 302 | block_ready_q[block_rd_q] <= 1'b0; 303 | block_rd_q <= block_rd_q + 2'd1; 304 | end 305 | end 306 | 307 | assign inport_accept_o = ~block_ready_q[block_wr_q]; 308 | 309 | //----------------------------------------------------------------- 310 | // FSM 311 | //----------------------------------------------------------------- 312 | localparam STATE_W = 2; 313 | localparam STATE_IDLE = 2'd0; 314 | localparam STATE_SETUP = 2'd1; 315 | localparam STATE_ACTIVE = 2'd2; 316 | 317 | reg [STATE_W-1:0] state_q; 318 | reg [STATE_W-1:0] next_state_r; 319 | 320 | always @ * 321 | begin 322 | next_state_r = state_q; 323 | 324 | case (state_q) 325 | STATE_IDLE: 326 | begin 327 | if (block_ready_q[block_rd_q] && outport_ready_i) 328 | next_state_r = STATE_SETUP; 329 | end 330 | STATE_SETUP: 331 | begin 332 | next_state_r = STATE_ACTIVE; 333 | end 334 | STATE_ACTIVE: 335 | begin 336 | if (outport_valid_o && rd_idx_q == 6'd63) 337 | next_state_r = STATE_IDLE; 338 | end 339 | default: ; 340 | endcase 341 | 342 | if (img_start_i) 343 | next_state_r = STATE_IDLE; 344 | end 345 | 346 | always @ (posedge clk_i ) 347 | if (rst_i) 348 | state_q <= STATE_IDLE; 349 | else 350 | state_q <= next_state_r; 351 | 352 | always @ (posedge clk_i ) 353 | if (rst_i) 354 | rd_idx_q <= 6'b0; 355 | else if (img_start_i) 356 | rd_idx_q <= 6'b0; 357 | else if (state_q == STATE_ACTIVE) 358 | rd_idx_q <= rd_idx_q + 6'd1; 359 | 360 | always @ (posedge clk_i ) 361 | if (rst_i) 362 | rd_addr_q <= 4'b0; 363 | else if (state_q == STATE_IDLE) 364 | rd_addr_q <= 4'b0; 365 | else if (state_q == STATE_SETUP) 366 | rd_addr_q <= 4'd1; 367 | else if (state_q == STATE_ACTIVE) 368 | begin 369 | case (rd_idx_q[2:0]) 370 | 3'd0: rd_addr_q <= rd_addr_q - 1; 371 | 3'd1: rd_addr_q <= rd_addr_q + 1; 372 | 3'd2: ; 373 | 3'd3: rd_addr_q <= rd_addr_q - 1; 374 | 3'd4: rd_addr_q <= rd_addr_q + 1; 375 | 3'd5: rd_addr_q <= rd_addr_q - 1; 376 | 3'd6: rd_addr_q <= rd_addr_q + 2; 377 | 3'd7: rd_addr_q <= rd_addr_q + 1; 378 | endcase 379 | end 380 | 381 | reg data_val0_q; 382 | reg data_val1_q; 383 | reg data_val2_q; 384 | reg data_val3_q; 385 | 386 | always @ (posedge clk_i ) 387 | if (rst_i) 388 | begin 389 | data_val0_q <= 1'b0; 390 | data_val1_q <= 1'b0; 391 | data_val2_q <= 1'b0; 392 | data_val3_q <= 1'b0; 393 | end 394 | else 395 | begin 396 | data_val0_q <= data_valid0_q[{block_rd_q, rd_addr_q}]; 397 | data_val1_q <= data_valid1_q[{block_rd_q, rd_addr_q}]; 398 | data_val2_q <= data_valid2_q[{block_rd_q, rd_addr_q}]; 399 | data_val3_q <= data_valid3_q[{block_rd_q, rd_addr_q}]; 400 | end 401 | 402 | assign outport_valid_o = (state_q == STATE_ACTIVE); 403 | assign outport_idx_o = rd_idx_q[2:0]; 404 | assign outport_data0_o = {16{data_val0_q}} & outport_data0_w; 405 | assign outport_data1_o = {16{data_val1_q}} & outport_data1_w; 406 | assign outport_data2_o = {16{data_val2_q}} & outport_data2_w; 407 | assign outport_data3_o = {16{data_val3_q}} & outport_data3_w; 408 | 409 | 410 | endmodule 411 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_ram_dp.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_ram_dp 33 | ( 34 | // Inputs 35 | input clk0_i 36 | ,input rst0_i 37 | ,input [ 5:0] addr0_i 38 | ,input [ 15:0] data0_i 39 | ,input wr0_i 40 | ,input clk1_i 41 | ,input rst1_i 42 | ,input [ 5:0] addr1_i 43 | ,input [ 15:0] data1_i 44 | ,input wr1_i 45 | 46 | // Outputs 47 | ,output [ 15:0] data0_o 48 | ,output [ 15:0] data1_o 49 | ); 50 | 51 | 52 | 53 | //----------------------------------------------------------------- 54 | // Dual Port RAM 55 | // Mode: Read First 56 | //----------------------------------------------------------------- 57 | /* verilator lint_off MULTIDRIVEN */ 58 | reg [15:0] ram [63:0] /*verilator public*/; 59 | /* verilator lint_on MULTIDRIVEN */ 60 | 61 | reg [15:0] ram_read0_q; 62 | reg [15:0] ram_read1_q; 63 | 64 | 65 | // Synchronous write 66 | always @ (posedge clk0_i) 67 | begin 68 | if (wr0_i) 69 | ram[addr0_i][15:0] <= data0_i[15:0]; 70 | 71 | ram_read0_q <= ram[addr0_i]; 72 | end 73 | 74 | always @ (posedge clk1_i) 75 | begin 76 | if (wr1_i) 77 | ram[addr1_i][15:0] <= data1_i[15:0]; 78 | 79 | ram_read1_q <= ram[addr1_i]; 80 | end 81 | 82 | 83 | assign data0_o = ram_read0_q; 84 | assign data1_o = ram_read1_q; 85 | 86 | 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_transpose.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_transpose 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input inport_valid_i 40 | ,input [ 31:0] inport_data_i 41 | ,input [ 5:0] inport_idx_i 42 | ,input outport_ready_i 43 | 44 | // Outputs 45 | ,output inport_accept_o 46 | ,output outport_valid_o 47 | ,output [ 31:0] outport_data0_o 48 | ,output [ 31:0] outport_data1_o 49 | ,output [ 31:0] outport_data2_o 50 | ,output [ 31:0] outport_data3_o 51 | ,output [ 2:0] outport_idx_o 52 | ); 53 | 54 | 55 | 56 | reg block_wr_q; 57 | reg block_rd_q; 58 | reg [5:0] rd_idx_q; 59 | reg [3:0] rd_addr_q; 60 | 61 | wire [4:0] wr_ptr_w = {block_wr_q, inport_idx_i[3:0]}; 62 | 63 | wire [31:0] outport_data0_w; 64 | wire [31:0] outport_data1_w; 65 | wire [31:0] outport_data2_w; 66 | wire [31:0] outport_data3_w; 67 | 68 | wire wr0_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd0); 69 | wire wr1_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd1); 70 | wire wr2_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd2); 71 | wire wr3_w = inport_valid_i && inport_accept_o && (inport_idx_i[5:4] == 2'd3); 72 | 73 | jpeg_idct_transpose_ram 74 | u_ram0 75 | ( 76 | .clk0_i(clk_i) 77 | ,.rst0_i(rst_i) 78 | ,.clk1_i(clk_i) 79 | ,.rst1_i(rst_i) 80 | 81 | ,.addr0_i(wr_ptr_w) 82 | ,.data0_i(inport_data_i) 83 | ,.wr0_i(wr0_w) 84 | ,.data0_o() 85 | 86 | ,.addr1_i({block_rd_q, rd_addr_q}) 87 | ,.data1_i(32'b0) 88 | ,.wr1_i(1'b0) 89 | ,.data1_o(outport_data0_w) 90 | ); 91 | 92 | jpeg_idct_transpose_ram 93 | u_ram1 94 | ( 95 | .clk0_i(clk_i) 96 | ,.rst0_i(rst_i) 97 | ,.clk1_i(clk_i) 98 | ,.rst1_i(rst_i) 99 | 100 | ,.addr0_i(wr_ptr_w) 101 | ,.data0_i(inport_data_i) 102 | ,.wr0_i(wr1_w) 103 | ,.data0_o() 104 | 105 | ,.addr1_i({block_rd_q, rd_addr_q}) 106 | ,.data1_i(32'b0) 107 | ,.wr1_i(1'b0) 108 | ,.data1_o(outport_data1_w) 109 | ); 110 | 111 | jpeg_idct_transpose_ram 112 | u_ram2 113 | ( 114 | .clk0_i(clk_i) 115 | ,.rst0_i(rst_i) 116 | ,.clk1_i(clk_i) 117 | ,.rst1_i(rst_i) 118 | 119 | ,.addr0_i(wr_ptr_w) 120 | ,.data0_i(inport_data_i) 121 | ,.wr0_i(wr2_w) 122 | ,.data0_o() 123 | 124 | ,.addr1_i({block_rd_q, rd_addr_q}) 125 | ,.data1_i(32'b0) 126 | ,.wr1_i(1'b0) 127 | ,.data1_o(outport_data2_w) 128 | ); 129 | 130 | jpeg_idct_transpose_ram 131 | u_ram3 132 | ( 133 | .clk0_i(clk_i) 134 | ,.rst0_i(rst_i) 135 | ,.clk1_i(clk_i) 136 | ,.rst1_i(rst_i) 137 | 138 | ,.addr0_i(wr_ptr_w) 139 | ,.data0_i(inport_data_i) 140 | ,.wr0_i(wr3_w) 141 | ,.data0_o() 142 | 143 | ,.addr1_i({block_rd_q, rd_addr_q}) 144 | ,.data1_i(32'b0) 145 | ,.wr1_i(1'b0) 146 | ,.data1_o(outport_data3_w) 147 | ); 148 | 149 | //----------------------------------------------------------------- 150 | // Input Buffer 151 | //----------------------------------------------------------------- 152 | reg [1:0] block_ready_q; 153 | 154 | always @ (posedge clk_i ) 155 | if (rst_i) 156 | begin 157 | block_ready_q <= 2'b0; 158 | block_wr_q <= 1'b0; 159 | block_rd_q <= 1'b0; 160 | end 161 | else if (img_start_i) 162 | begin 163 | block_ready_q <= 2'b0; 164 | block_wr_q <= 1'b0; 165 | block_rd_q <= 1'b0; 166 | end 167 | else 168 | begin 169 | if (inport_valid_i && inport_idx_i == 6'd63 && inport_accept_o) 170 | begin 171 | block_ready_q[block_wr_q] <= 1'b1; 172 | block_wr_q <= ~block_wr_q; 173 | end 174 | 175 | if (outport_valid_o && rd_idx_q[5:0] == 6'd63) 176 | begin 177 | block_ready_q[block_rd_q] <= 1'b0; 178 | block_rd_q <= ~block_rd_q; 179 | end 180 | end 181 | 182 | assign inport_accept_o = ~block_ready_q[block_wr_q]; 183 | 184 | //----------------------------------------------------------------- 185 | // FSM 186 | //----------------------------------------------------------------- 187 | localparam STATE_W = 2; 188 | localparam STATE_IDLE = 2'd0; 189 | localparam STATE_SETUP = 2'd1; 190 | localparam STATE_ACTIVE = 2'd2; 191 | 192 | reg [STATE_W-1:0] state_q; 193 | reg [STATE_W-1:0] next_state_r; 194 | 195 | always @ * 196 | begin 197 | next_state_r = state_q; 198 | 199 | case (state_q) 200 | STATE_IDLE: 201 | begin 202 | if (block_ready_q[block_rd_q] && outport_ready_i) 203 | next_state_r = STATE_SETUP; 204 | end 205 | STATE_SETUP: 206 | begin 207 | next_state_r = STATE_ACTIVE; 208 | end 209 | STATE_ACTIVE: 210 | begin 211 | if (outport_valid_o && rd_idx_q == 6'd63) 212 | next_state_r = STATE_IDLE; 213 | end 214 | default: ; 215 | endcase 216 | 217 | if (img_start_i) 218 | next_state_r = STATE_IDLE; 219 | end 220 | 221 | always @ (posedge clk_i ) 222 | if (rst_i) 223 | state_q <= STATE_IDLE; 224 | else 225 | state_q <= next_state_r; 226 | 227 | always @ (posedge clk_i ) 228 | if (rst_i) 229 | rd_idx_q <= 6'b0; 230 | else if (img_start_i) 231 | rd_idx_q <= 6'b0; 232 | else if (state_q == STATE_ACTIVE) 233 | rd_idx_q <= rd_idx_q + 6'd1; 234 | 235 | always @ (posedge clk_i ) 236 | if (rst_i) 237 | rd_addr_q <= 4'b0; 238 | else if (state_q == STATE_IDLE) 239 | rd_addr_q <= 4'b0; 240 | else if (state_q == STATE_SETUP) 241 | rd_addr_q <= 4'd8; 242 | else if (state_q == STATE_ACTIVE) 243 | begin 244 | case (rd_idx_q[2:0]) 245 | 3'd0: rd_addr_q <= rd_addr_q - 4'd8; 246 | 3'd1: rd_addr_q <= rd_addr_q + 4'd8; 247 | 3'd2: ; 248 | 3'd3: rd_addr_q <= rd_addr_q - 4'd8; 249 | 3'd4: rd_addr_q <= rd_addr_q + 4'd8; 250 | 3'd5: rd_addr_q <= rd_addr_q - 4'd8; 251 | 3'd6: rd_addr_q <= rd_addr_q + 4'd1; 252 | 3'd7: rd_addr_q <= rd_addr_q + 4'd8; 253 | endcase 254 | end 255 | 256 | assign outport_valid_o = (state_q == STATE_ACTIVE); 257 | assign outport_idx_o = rd_idx_q[2:0]; 258 | assign outport_data0_o = outport_data0_w; 259 | assign outport_data1_o = outport_data1_w; 260 | assign outport_data2_o = outport_data2_w; 261 | assign outport_data3_o = outport_data3_w; 262 | 263 | 264 | endmodule 265 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_transpose_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_transpose_ram 33 | ( 34 | // Inputs 35 | input clk0_i 36 | ,input rst0_i 37 | ,input [ 4:0] addr0_i 38 | ,input [ 31:0] data0_i 39 | ,input wr0_i 40 | ,input clk1_i 41 | ,input rst1_i 42 | ,input [ 4:0] addr1_i 43 | ,input [ 31:0] data1_i 44 | ,input wr1_i 45 | 46 | // Outputs 47 | ,output [ 31:0] data0_o 48 | ,output [ 31:0] data1_o 49 | ); 50 | 51 | 52 | 53 | //----------------------------------------------------------------- 54 | // Dual Port RAM 55 | // Mode: Read First 56 | //----------------------------------------------------------------- 57 | /* verilator lint_off MULTIDRIVEN */ 58 | reg [31:0] ram [31:0] /*verilator public*/; 59 | /* verilator lint_on MULTIDRIVEN */ 60 | 61 | reg [31:0] ram_read0_q; 62 | reg [31:0] ram_read1_q; 63 | 64 | 65 | // Synchronous write 66 | always @ (posedge clk0_i) 67 | begin 68 | if (wr0_i) 69 | ram[addr0_i][31:0] <= data0_i[31:0]; 70 | 71 | ram_read0_q <= ram[addr0_i]; 72 | end 73 | 74 | always @ (posedge clk1_i) 75 | begin 76 | if (wr1_i) 77 | ram[addr1_i][31:0] <= data1_i[31:0]; 78 | 79 | ram_read1_q <= ram[addr1_i]; 80 | end 81 | 82 | 83 | assign data0_o = ram_read0_q; 84 | assign data1_o = ram_read1_q; 85 | 86 | 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_x.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_x 33 | //----------------------------------------------------------------- 34 | // Params 35 | //----------------------------------------------------------------- 36 | #( 37 | parameter OUT_SHIFT = 11 38 | ,parameter INPUT_WIDTH = 16 39 | ) 40 | //----------------------------------------------------------------- 41 | // Ports 42 | //----------------------------------------------------------------- 43 | ( 44 | // Inputs 45 | input clk_i 46 | ,input rst_i 47 | ,input img_start_i 48 | ,input img_end_i 49 | ,input inport_valid_i 50 | ,input [ 15:0] inport_data0_i 51 | ,input [ 15:0] inport_data1_i 52 | ,input [ 15:0] inport_data2_i 53 | ,input [ 15:0] inport_data3_i 54 | ,input [ 2:0] inport_idx_i 55 | 56 | // Outputs 57 | ,output outport_valid_o 58 | ,output [ 31:0] outport_data_o 59 | ,output [ 5:0] outport_idx_o 60 | ); 61 | 62 | 63 | 64 | 65 | localparam [15:0] C1_16 = 4017; // cos( pi/16) x4096 66 | localparam [15:0] C2_16 = 3784; // cos(2pi/16) x4096 67 | localparam [15:0] C3_16 = 3406; // cos(3pi/16) x4096 68 | localparam [15:0] C4_16 = 2896; // cos(4pi/16) x4096 69 | localparam [15:0] C5_16 = 2276; // cos(5pi/16) x4096 70 | localparam [15:0] C6_16 = 1567; // cos(6pi/16) x4096 71 | localparam [15:0] C7_16 = 799; // cos(7pi/16) x4096 72 | 73 | wire signed [31:0] block_in_0_1 = {{16{inport_data0_i[15]}}, inport_data0_i}; 74 | wire signed [31:0] block_in_2_3 = {{16{inport_data1_i[15]}}, inport_data1_i}; 75 | wire signed [31:0] block_in_4_5 = {{16{inport_data2_i[15]}}, inport_data2_i}; 76 | wire signed [31:0] block_in_6_7 = {{16{inport_data3_i[15]}}, inport_data3_i}; 77 | 78 | //----------------------------------------------------------------- 79 | // IDCT 80 | //----------------------------------------------------------------- 81 | reg signed [31:0] i0; 82 | reg signed [31:0] mul0_a; 83 | reg signed [31:0] mul0_b; 84 | reg signed [31:0] mul1_a; 85 | reg signed [31:0] mul1_b; 86 | reg signed [31:0] mul2_a; 87 | reg signed [31:0] mul2_b; 88 | reg signed [31:0] mul3_a; 89 | reg signed [31:0] mul3_b; 90 | reg signed [31:0] mul4_a; 91 | reg signed [31:0] mul4_b; 92 | 93 | always @ (posedge clk_i ) 94 | if (rst_i) 95 | begin 96 | i0 <= 32'b0; 97 | mul0_a <= 32'b0; 98 | mul0_b <= 32'b0; 99 | mul1_a <= 32'b0; 100 | mul1_b <= 32'b0; 101 | mul2_a <= 32'b0; 102 | mul2_b <= 32'b0; 103 | mul3_a <= 32'b0; 104 | mul3_b <= 32'b0; 105 | mul4_a <= 32'b0; 106 | mul4_b <= 32'b0; 107 | end 108 | else 109 | begin 110 | /* verilator lint_off WIDTH */ 111 | case (inport_idx_i) 112 | 3'd0: 113 | begin 114 | i0 <= block_in_0_1 + block_in_4_5; 115 | mul0_a <= block_in_2_3; 116 | mul0_b <= C2_16; 117 | mul1_a <= block_in_6_7; 118 | mul1_b <= C6_16; 119 | end 120 | 3'd1: 121 | begin 122 | mul0_a <= block_in_0_1; 123 | mul0_b <= C1_16; 124 | mul1_a <= block_in_6_7; 125 | mul1_b <= C7_16; 126 | mul2_a <= block_in_4_5; 127 | mul2_b <= C5_16; 128 | mul3_a <= block_in_2_3; 129 | mul3_b <= C3_16; 130 | mul4_a <= i0; 131 | mul4_b <= C4_16; 132 | end 133 | 3'd2: 134 | begin 135 | i0 <= block_in_0_1 - block_in_4_5; 136 | end 137 | 3'd3: 138 | begin 139 | mul0_a <= block_in_0_1; 140 | mul0_b <= C7_16; 141 | mul1_a <= block_in_6_7; 142 | mul1_b <= C1_16; 143 | mul2_a <= block_in_4_5; 144 | mul2_b <= C3_16; 145 | mul3_a <= block_in_2_3; 146 | mul3_b <= C5_16; 147 | end 148 | 3'd4: 149 | begin 150 | mul0_a <= block_in_0_1; 151 | mul0_b <= C7_16; 152 | mul1_a <= block_in_6_7; 153 | mul1_b <= C1_16; 154 | mul2_a <= block_in_4_5; 155 | mul2_b <= C3_16; 156 | mul3_a <= block_in_2_3; 157 | mul3_b <= C5_16; 158 | end 159 | 3'd5: 160 | begin 161 | mul0_a <= block_in_2_3; 162 | mul0_b <= C6_16; 163 | mul1_a <= block_in_6_7; 164 | mul1_b <= C2_16; 165 | mul4_a <= i0; 166 | mul4_b <= C4_16; 167 | end 168 | default: 169 | ; 170 | endcase 171 | /* verilator lint_on WIDTH */ 172 | end 173 | 174 | reg signed [31:0] mul0_q; 175 | reg signed [31:0] mul1_q; 176 | reg signed [31:0] mul2_q; 177 | reg signed [31:0] mul3_q; 178 | reg signed [31:0] mul4_q; 179 | 180 | always @ (posedge clk_i ) 181 | if (rst_i) 182 | begin 183 | mul0_q <= 32'b0; 184 | mul1_q <= 32'b0; 185 | mul2_q <= 32'b0; 186 | mul3_q <= 32'b0; 187 | mul4_q <= 32'b0; 188 | end 189 | else 190 | begin 191 | mul0_q <= mul0_a * mul0_b; 192 | mul1_q <= mul1_a * mul1_b; 193 | mul2_q <= mul2_a * mul2_b; 194 | mul3_q <= mul3_a * mul3_b; 195 | mul4_q <= mul4_a * mul4_b; 196 | end 197 | 198 | reg signed [31:0] mul0; 199 | reg signed [31:0] mul1; 200 | reg signed [31:0] mul2; 201 | reg signed [31:0] mul3; 202 | reg signed [31:0] mul4; 203 | 204 | always @ (posedge clk_i ) 205 | if (rst_i) 206 | begin 207 | mul0 <= 32'b0; 208 | mul1 <= 32'b0; 209 | mul2 <= 32'b0; 210 | mul3 <= 32'b0; 211 | mul4 <= 32'b0; 212 | end 213 | else 214 | begin 215 | mul0 <= mul0_q; 216 | mul1 <= mul1_q; 217 | mul2 <= mul2_q; 218 | mul3 <= mul3_q; 219 | mul4 <= mul4_q; 220 | end 221 | 222 | reg out_stg0_valid_q; 223 | reg [2:0] out_stg0_idx_q; 224 | 225 | always @ (posedge clk_i ) 226 | if (rst_i) 227 | begin 228 | out_stg0_valid_q <= 1'b0; 229 | out_stg0_idx_q <= 3'b0; 230 | end 231 | else 232 | begin 233 | out_stg0_valid_q <= inport_valid_i; 234 | out_stg0_idx_q <= inport_idx_i; 235 | end 236 | 237 | reg out_stg1_valid_q; 238 | reg [2:0] out_stg1_idx_q; 239 | 240 | always @ (posedge clk_i ) 241 | if (rst_i) 242 | begin 243 | out_stg1_valid_q <= 1'b0; 244 | out_stg1_idx_q <= 3'b0; 245 | end 246 | else 247 | begin 248 | out_stg1_valid_q <= out_stg0_valid_q; 249 | out_stg1_idx_q <= out_stg0_idx_q; 250 | end 251 | 252 | reg out_stg2_valid_q; 253 | reg [2:0] out_stg2_idx_q; 254 | 255 | always @ (posedge clk_i ) 256 | if (rst_i) 257 | begin 258 | out_stg2_valid_q <= 1'b0; 259 | out_stg2_idx_q <= 3'b0; 260 | end 261 | else 262 | begin 263 | out_stg2_valid_q <= out_stg1_valid_q; 264 | out_stg2_idx_q <= out_stg1_idx_q; 265 | end 266 | 267 | reg signed [31:0] o_s5; 268 | reg signed [31:0] o_s6; 269 | reg signed [31:0] o_s7; 270 | reg signed [31:0] o_t0; 271 | reg signed [31:0] o_t1; 272 | reg signed [31:0] o_t2; 273 | reg signed [31:0] o_t3; 274 | reg signed [31:0] o_t4; 275 | reg signed [31:0] o_t5; 276 | reg signed [31:0] o_t6; 277 | reg signed [31:0] o_t7; 278 | reg signed [31:0] o_t6_5; 279 | reg signed [31:0] o_t5_6; 280 | 281 | always @ (posedge clk_i ) 282 | if (rst_i) 283 | begin 284 | o_s5 <= 32'b0; 285 | o_s6 <= 32'b0; 286 | o_s7 <= 32'b0; 287 | o_t0 <= 32'b0; 288 | o_t1 <= 32'b0; 289 | o_t2 <= 32'b0; 290 | o_t3 <= 32'b0; 291 | o_t4 <= 32'b0; 292 | o_t5 <= 32'b0; 293 | o_t6 <= 32'b0; 294 | o_t7 <= 32'b0; 295 | o_t6_5 <= 32'b0; 296 | o_t5_6 <= 32'b0; 297 | end 298 | else 299 | begin 300 | case (out_stg2_idx_q) 301 | 3'd0: 302 | begin 303 | o_t3 <= mul0 + mul1; // s3 304 | end 305 | 3'd1: 306 | begin 307 | o_s7 <= mul0 + mul1; 308 | o_s6 <= mul2 + mul3; 309 | o_t0 <= mul4; // s0 310 | end 311 | 3'd2: 312 | begin 313 | o_t0 <= o_t0 + o_t3; // t0 314 | o_t3 <= o_t0 - o_t3; // t3 315 | o_t7 <= o_s6 + o_s7; 316 | end 317 | 3'd3: 318 | begin 319 | o_t4 <= (mul0 - mul1) + (mul2 - mul3); 320 | end 321 | 3'd4: 322 | begin 323 | o_t0 <= mul0 - mul1; // s4 324 | o_s5 <= mul2 - mul3; 325 | end 326 | 3'd5: 327 | begin 328 | o_t3 <= mul0 - mul1; // s2 329 | o_t4 <= mul4; // s1 330 | o_t5 <= o_t0 - o_s5; 331 | o_t6 <= o_s7 - o_s6; 332 | end 333 | 3'd6: 334 | begin 335 | o_t1 <= o_t4 + o_t3; 336 | o_t2 <= o_t4 - o_t3; 337 | o_t6_5 <= o_t6 - o_t5; 338 | o_t5_6 <= o_t5 + o_t6; 339 | end 340 | default: 341 | begin 342 | o_s5 <= (o_t6_5 * 181) / 256; // 1/sqrt(2) 343 | o_s6 <= (o_t5_6 * 181) / 256; // 1/sqrt(2) 344 | end 345 | endcase 346 | end 347 | 348 | reg out_stg3_valid_q; 349 | reg [2:0] out_stg3_idx_q; 350 | 351 | always @ (posedge clk_i ) 352 | if (rst_i) 353 | begin 354 | out_stg3_valid_q <= 1'b0; 355 | out_stg3_idx_q <= 3'b0; 356 | end 357 | else 358 | begin 359 | out_stg3_valid_q <= out_stg2_valid_q; 360 | out_stg3_idx_q <= out_stg2_idx_q; 361 | end 362 | 363 | reg signed [31:0] block_out[0:7]; 364 | reg signed [31:0] block_out_tmp; 365 | 366 | always @ (posedge clk_i ) 367 | if (rst_i) 368 | begin 369 | block_out[0] <= 32'b0; 370 | block_out[1] <= 32'b0; 371 | block_out[2] <= 32'b0; 372 | block_out[3] <= 32'b0; 373 | block_out[4] <= 32'b0; 374 | block_out[5] <= 32'b0; 375 | block_out[6] <= 32'b0; 376 | block_out[7] <= 32'b0; 377 | block_out_tmp <= 32'b0; 378 | end 379 | else if (out_stg3_valid_q) 380 | begin 381 | if (out_stg3_idx_q == 3'd3) 382 | begin 383 | block_out[0] <= ((o_t0 + o_t7) >>> OUT_SHIFT); 384 | block_out_tmp <= ((o_t0 - o_t7) >>> OUT_SHIFT); // block_out[7] 385 | block_out[3] <= ((o_t3 + o_t4) >>> OUT_SHIFT); 386 | block_out[4] <= ((o_t3 - o_t4) >>> OUT_SHIFT); 387 | end 388 | 389 | if (out_stg3_idx_q == 3'd6) 390 | block_out[7] <= block_out_tmp; 391 | 392 | if (out_stg3_idx_q == 3'd7) 393 | begin 394 | block_out[2] <= ((o_t2 + o_s5) >>> OUT_SHIFT); 395 | block_out[5] <= ((o_t2 - o_s5) >>> OUT_SHIFT); 396 | block_out[1] <= ((o_t1 + o_s6) >>> OUT_SHIFT); 397 | block_out[6] <= ((o_t1 - o_s6) >>> OUT_SHIFT); 398 | end 399 | end 400 | 401 | reg [7:0] valid_q; 402 | 403 | always @ (posedge clk_i ) 404 | if (rst_i) 405 | valid_q <= 8'b0; 406 | else if (img_start_i) 407 | valid_q <= 8'b0; 408 | else 409 | valid_q <= {valid_q[6:0], out_stg3_valid_q}; 410 | 411 | reg [5:0] ptr_q; 412 | 413 | always @ (posedge clk_i ) 414 | if (rst_i) 415 | ptr_q <= 6'd0; 416 | else if (img_start_i) 417 | ptr_q <= 6'd0; 418 | else if (outport_valid_o) 419 | ptr_q <= ptr_q + 6'd1; 420 | 421 | assign outport_valid_o = valid_q[6]; 422 | assign outport_data_o = block_out[ptr_q[2:0]]; 423 | 424 | assign outport_idx_o = ptr_q; 425 | 426 | 427 | 428 | endmodule 429 | -------------------------------------------------------------------------------- /src_v/jpeg_idct_y.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_idct_y 33 | //----------------------------------------------------------------- 34 | // Params 35 | //----------------------------------------------------------------- 36 | #( 37 | parameter OUT_SHIFT = 15 38 | ,parameter INPUT_WIDTH = 32 39 | ) 40 | //----------------------------------------------------------------- 41 | // Ports 42 | //----------------------------------------------------------------- 43 | ( 44 | // Inputs 45 | input clk_i 46 | ,input rst_i 47 | ,input img_start_i 48 | ,input img_end_i 49 | ,input inport_valid_i 50 | ,input [ 31:0] inport_data0_i 51 | ,input [ 31:0] inport_data1_i 52 | ,input [ 31:0] inport_data2_i 53 | ,input [ 31:0] inport_data3_i 54 | ,input [ 2:0] inport_idx_i 55 | 56 | // Outputs 57 | ,output outport_valid_o 58 | ,output [ 31:0] outport_data_o 59 | ,output [ 5:0] outport_idx_o 60 | ); 61 | 62 | 63 | 64 | 65 | localparam [15:0] C1_16 = 4017; // cos( pi/16) x4096 66 | localparam [15:0] C2_16 = 3784; // cos(2pi/16) x4096 67 | localparam [15:0] C3_16 = 3406; // cos(3pi/16) x4096 68 | localparam [15:0] C4_16 = 2896; // cos(4pi/16) x4096 69 | localparam [15:0] C5_16 = 2276; // cos(5pi/16) x4096 70 | localparam [15:0] C6_16 = 1567; // cos(6pi/16) x4096 71 | localparam [15:0] C7_16 = 799; // cos(7pi/16) x4096 72 | 73 | wire signed [31:0] block_in_0_1 = inport_data0_i; 74 | wire signed [31:0] block_in_2_3 = inport_data1_i; 75 | wire signed [31:0] block_in_4_5 = inport_data2_i; 76 | wire signed [31:0] block_in_6_7 = inport_data3_i; 77 | 78 | //----------------------------------------------------------------- 79 | // IDCT 80 | //----------------------------------------------------------------- 81 | reg signed [31:0] i0; 82 | reg signed [31:0] mul0_a; 83 | reg signed [31:0] mul0_b; 84 | reg signed [31:0] mul1_a; 85 | reg signed [31:0] mul1_b; 86 | reg signed [31:0] mul2_a; 87 | reg signed [31:0] mul2_b; 88 | reg signed [31:0] mul3_a; 89 | reg signed [31:0] mul3_b; 90 | reg signed [31:0] mul4_a; 91 | reg signed [31:0] mul4_b; 92 | 93 | always @ (posedge clk_i ) 94 | if (rst_i) 95 | begin 96 | i0 <= 32'b0; 97 | mul0_a <= 32'b0; 98 | mul0_b <= 32'b0; 99 | mul1_a <= 32'b0; 100 | mul1_b <= 32'b0; 101 | mul2_a <= 32'b0; 102 | mul2_b <= 32'b0; 103 | mul3_a <= 32'b0; 104 | mul3_b <= 32'b0; 105 | mul4_a <= 32'b0; 106 | mul4_b <= 32'b0; 107 | end 108 | else 109 | begin 110 | /* verilator lint_off WIDTH */ 111 | case (inport_idx_i) 112 | 3'd0: 113 | begin 114 | i0 <= block_in_0_1 + block_in_4_5; 115 | mul0_a <= block_in_2_3; 116 | mul0_b <= C2_16; 117 | mul1_a <= block_in_6_7; 118 | mul1_b <= C6_16; 119 | end 120 | 3'd1: 121 | begin 122 | mul0_a <= block_in_0_1; 123 | mul0_b <= C1_16; 124 | mul1_a <= block_in_6_7; 125 | mul1_b <= C7_16; 126 | mul2_a <= block_in_4_5; 127 | mul2_b <= C5_16; 128 | mul3_a <= block_in_2_3; 129 | mul3_b <= C3_16; 130 | mul4_a <= i0; 131 | mul4_b <= C4_16; 132 | end 133 | 3'd2: 134 | begin 135 | i0 <= block_in_0_1 - block_in_4_5; 136 | end 137 | 3'd3: 138 | begin 139 | mul0_a <= block_in_0_1; 140 | mul0_b <= C7_16; 141 | mul1_a <= block_in_6_7; 142 | mul1_b <= C1_16; 143 | mul2_a <= block_in_4_5; 144 | mul2_b <= C3_16; 145 | mul3_a <= block_in_2_3; 146 | mul3_b <= C5_16; 147 | end 148 | 3'd4: 149 | begin 150 | mul0_a <= block_in_0_1; 151 | mul0_b <= C7_16; 152 | mul1_a <= block_in_6_7; 153 | mul1_b <= C1_16; 154 | mul2_a <= block_in_4_5; 155 | mul2_b <= C3_16; 156 | mul3_a <= block_in_2_3; 157 | mul3_b <= C5_16; 158 | end 159 | 3'd5: 160 | begin 161 | mul0_a <= block_in_2_3; 162 | mul0_b <= C6_16; 163 | mul1_a <= block_in_6_7; 164 | mul1_b <= C2_16; 165 | mul4_a <= i0; 166 | mul4_b <= C4_16; 167 | end 168 | default: 169 | ; 170 | endcase 171 | /* verilator lint_on WIDTH */ 172 | end 173 | 174 | reg signed [31:0] mul0_q; 175 | reg signed [31:0] mul1_q; 176 | reg signed [31:0] mul2_q; 177 | reg signed [31:0] mul3_q; 178 | reg signed [31:0] mul4_q; 179 | 180 | always @ (posedge clk_i ) 181 | if (rst_i) 182 | begin 183 | mul0_q <= 32'b0; 184 | mul1_q <= 32'b0; 185 | mul2_q <= 32'b0; 186 | mul3_q <= 32'b0; 187 | mul4_q <= 32'b0; 188 | end 189 | else 190 | begin 191 | mul0_q <= mul0_a * mul0_b; 192 | mul1_q <= mul1_a * mul1_b; 193 | mul2_q <= mul2_a * mul2_b; 194 | mul3_q <= mul3_a * mul3_b; 195 | mul4_q <= mul4_a * mul4_b; 196 | end 197 | 198 | reg signed [31:0] mul0; 199 | reg signed [31:0] mul1; 200 | reg signed [31:0] mul2; 201 | reg signed [31:0] mul3; 202 | reg signed [31:0] mul4; 203 | 204 | always @ (posedge clk_i ) 205 | if (rst_i) 206 | begin 207 | mul0 <= 32'b0; 208 | mul1 <= 32'b0; 209 | mul2 <= 32'b0; 210 | mul3 <= 32'b0; 211 | mul4 <= 32'b0; 212 | end 213 | else 214 | begin 215 | mul0 <= mul0_q; 216 | mul1 <= mul1_q; 217 | mul2 <= mul2_q; 218 | mul3 <= mul3_q; 219 | mul4 <= mul4_q; 220 | end 221 | 222 | reg out_stg0_valid_q; 223 | reg [2:0] out_stg0_idx_q; 224 | 225 | always @ (posedge clk_i ) 226 | if (rst_i) 227 | begin 228 | out_stg0_valid_q <= 1'b0; 229 | out_stg0_idx_q <= 3'b0; 230 | end 231 | else 232 | begin 233 | out_stg0_valid_q <= inport_valid_i; 234 | out_stg0_idx_q <= inport_idx_i; 235 | end 236 | 237 | reg out_stg1_valid_q; 238 | reg [2:0] out_stg1_idx_q; 239 | 240 | always @ (posedge clk_i ) 241 | if (rst_i) 242 | begin 243 | out_stg1_valid_q <= 1'b0; 244 | out_stg1_idx_q <= 3'b0; 245 | end 246 | else 247 | begin 248 | out_stg1_valid_q <= out_stg0_valid_q; 249 | out_stg1_idx_q <= out_stg0_idx_q; 250 | end 251 | 252 | reg out_stg2_valid_q; 253 | reg [2:0] out_stg2_idx_q; 254 | 255 | always @ (posedge clk_i ) 256 | if (rst_i) 257 | begin 258 | out_stg2_valid_q <= 1'b0; 259 | out_stg2_idx_q <= 3'b0; 260 | end 261 | else 262 | begin 263 | out_stg2_valid_q <= out_stg1_valid_q; 264 | out_stg2_idx_q <= out_stg1_idx_q; 265 | end 266 | 267 | reg signed [31:0] o_s5; 268 | reg signed [31:0] o_s6; 269 | reg signed [31:0] o_s7; 270 | reg signed [31:0] o_t0; 271 | reg signed [31:0] o_t1; 272 | reg signed [31:0] o_t2; 273 | reg signed [31:0] o_t3; 274 | reg signed [31:0] o_t4; 275 | reg signed [31:0] o_t5; 276 | reg signed [31:0] o_t6; 277 | reg signed [31:0] o_t7; 278 | reg signed [31:0] o_t6_5; 279 | reg signed [31:0] o_t5_6; 280 | 281 | always @ (posedge clk_i ) 282 | if (rst_i) 283 | begin 284 | o_s5 <= 32'b0; 285 | o_s6 <= 32'b0; 286 | o_s7 <= 32'b0; 287 | o_t0 <= 32'b0; 288 | o_t1 <= 32'b0; 289 | o_t2 <= 32'b0; 290 | o_t3 <= 32'b0; 291 | o_t4 <= 32'b0; 292 | o_t5 <= 32'b0; 293 | o_t6 <= 32'b0; 294 | o_t7 <= 32'b0; 295 | o_t6_5 <= 32'b0; 296 | o_t5_6 <= 32'b0; 297 | end 298 | else 299 | begin 300 | case (out_stg2_idx_q) 301 | 3'd0: 302 | begin 303 | o_t3 <= mul0 + mul1; // s3 304 | end 305 | 3'd1: 306 | begin 307 | o_s7 <= mul0 + mul1; 308 | o_s6 <= mul2 + mul3; 309 | o_t0 <= mul4; // s0 310 | end 311 | 3'd2: 312 | begin 313 | o_t0 <= o_t0 + o_t3; // t0 314 | o_t3 <= o_t0 - o_t3; // t3 315 | o_t7 <= o_s6 + o_s7; 316 | end 317 | 3'd3: 318 | begin 319 | o_t4 <= (mul0 - mul1) + (mul2 - mul3); 320 | end 321 | 3'd4: 322 | begin 323 | o_t0 <= mul0 - mul1; // s4 324 | o_s5 <= mul2 - mul3; 325 | end 326 | 3'd5: 327 | begin 328 | o_t3 <= mul0 - mul1; // s2 329 | o_t4 <= mul4; // s1 330 | o_t5 <= o_t0 - o_s5; 331 | o_t6 <= o_s7 - o_s6; 332 | end 333 | 3'd6: 334 | begin 335 | o_t1 <= o_t4 + o_t3; 336 | o_t2 <= o_t4 - o_t3; 337 | o_t6_5 <= o_t6 - o_t5; 338 | o_t5_6 <= o_t5 + o_t6; 339 | end 340 | default: 341 | begin 342 | o_s5 <= (o_t6_5 * 181) / 256; // 1/sqrt(2) 343 | o_s6 <= (o_t5_6 * 181) / 256; // 1/sqrt(2) 344 | end 345 | endcase 346 | end 347 | 348 | reg out_stg3_valid_q; 349 | reg [2:0] out_stg3_idx_q; 350 | 351 | always @ (posedge clk_i ) 352 | if (rst_i) 353 | begin 354 | out_stg3_valid_q <= 1'b0; 355 | out_stg3_idx_q <= 3'b0; 356 | end 357 | else 358 | begin 359 | out_stg3_valid_q <= out_stg2_valid_q; 360 | out_stg3_idx_q <= out_stg2_idx_q; 361 | end 362 | 363 | reg signed [31:0] block_out[0:7]; 364 | reg signed [31:0] block_out_tmp; 365 | 366 | always @ (posedge clk_i ) 367 | if (rst_i) 368 | begin 369 | block_out[0] <= 32'b0; 370 | block_out[1] <= 32'b0; 371 | block_out[2] <= 32'b0; 372 | block_out[3] <= 32'b0; 373 | block_out[4] <= 32'b0; 374 | block_out[5] <= 32'b0; 375 | block_out[6] <= 32'b0; 376 | block_out[7] <= 32'b0; 377 | block_out_tmp <= 32'b0; 378 | end 379 | else if (out_stg3_valid_q) 380 | begin 381 | if (out_stg3_idx_q == 3'd3) 382 | begin 383 | block_out[0] <= ((o_t0 + o_t7) >>> OUT_SHIFT); 384 | block_out_tmp <= ((o_t0 - o_t7) >>> OUT_SHIFT); // block_out[7] 385 | block_out[3] <= ((o_t3 + o_t4) >>> OUT_SHIFT); 386 | block_out[4] <= ((o_t3 - o_t4) >>> OUT_SHIFT); 387 | end 388 | 389 | if (out_stg3_idx_q == 3'd6) 390 | block_out[7] <= block_out_tmp; 391 | 392 | if (out_stg3_idx_q == 3'd7) 393 | begin 394 | block_out[2] <= ((o_t2 + o_s5) >>> OUT_SHIFT); 395 | block_out[5] <= ((o_t2 - o_s5) >>> OUT_SHIFT); 396 | block_out[1] <= ((o_t1 + o_s6) >>> OUT_SHIFT); 397 | block_out[6] <= ((o_t1 - o_s6) >>> OUT_SHIFT); 398 | end 399 | end 400 | 401 | reg [7:0] valid_q; 402 | 403 | always @ (posedge clk_i ) 404 | if (rst_i) 405 | valid_q <= 8'b0; 406 | else if (img_start_i) 407 | valid_q <= 8'b0; 408 | else 409 | valid_q <= {valid_q[6:0], out_stg3_valid_q}; 410 | 411 | reg [5:0] ptr_q; 412 | 413 | always @ (posedge clk_i ) 414 | if (rst_i) 415 | ptr_q <= 6'd0; 416 | else if (img_start_i) 417 | ptr_q <= 6'd0; 418 | else if (outport_valid_o) 419 | ptr_q <= ptr_q + 6'd1; 420 | 421 | assign outport_valid_o = valid_q[6]; 422 | assign outport_data_o = block_out[ptr_q[2:0]]; 423 | 424 | 425 | 426 | function [5:0] ptr_conv; 427 | input [5:0] idx; 428 | reg [5:0] out_idx; 429 | begin 430 | case (idx) 431 | 6'd0: out_idx = 6'd0; 432 | 6'd1: out_idx = 6'd8; 433 | 6'd2: out_idx = 6'd16; 434 | 6'd3: out_idx = 6'd24; 435 | 6'd4: out_idx = 6'd32; 436 | 6'd5: out_idx = 6'd40; 437 | 6'd6: out_idx = 6'd48; 438 | 6'd7: out_idx = 6'd56; 439 | 6'd8: out_idx = 6'd1; 440 | 6'd9: out_idx = 6'd9; 441 | 6'd10: out_idx = 6'd17; 442 | 6'd11: out_idx = 6'd25; 443 | 6'd12: out_idx = 6'd33; 444 | 6'd13: out_idx = 6'd41; 445 | 6'd14: out_idx = 6'd49; 446 | 6'd15: out_idx = 6'd57; 447 | 6'd16: out_idx = 6'd2; 448 | 6'd17: out_idx = 6'd10; 449 | 6'd18: out_idx = 6'd18; 450 | 6'd19: out_idx = 6'd26; 451 | 6'd20: out_idx = 6'd34; 452 | 6'd21: out_idx = 6'd42; 453 | 6'd22: out_idx = 6'd50; 454 | 6'd23: out_idx = 6'd58; 455 | 6'd24: out_idx = 6'd3; 456 | 6'd25: out_idx = 6'd11; 457 | 6'd26: out_idx = 6'd19; 458 | 6'd27: out_idx = 6'd27; 459 | 6'd28: out_idx = 6'd35; 460 | 6'd29: out_idx = 6'd43; 461 | 6'd30: out_idx = 6'd51; 462 | 6'd31: out_idx = 6'd59; 463 | 6'd32: out_idx = 6'd4; 464 | 6'd33: out_idx = 6'd12; 465 | 6'd34: out_idx = 6'd20; 466 | 6'd35: out_idx = 6'd28; 467 | 6'd36: out_idx = 6'd36; 468 | 6'd37: out_idx = 6'd44; 469 | 6'd38: out_idx = 6'd52; 470 | 6'd39: out_idx = 6'd60; 471 | 6'd40: out_idx = 6'd5; 472 | 6'd41: out_idx = 6'd13; 473 | 6'd42: out_idx = 6'd21; 474 | 6'd43: out_idx = 6'd29; 475 | 6'd44: out_idx = 6'd37; 476 | 6'd45: out_idx = 6'd45; 477 | 6'd46: out_idx = 6'd53; 478 | 6'd47: out_idx = 6'd61; 479 | 6'd48: out_idx = 6'd6; 480 | 6'd49: out_idx = 6'd14; 481 | 6'd50: out_idx = 6'd22; 482 | 6'd51: out_idx = 6'd30; 483 | 6'd52: out_idx = 6'd38; 484 | 6'd53: out_idx = 6'd46; 485 | 6'd54: out_idx = 6'd54; 486 | 6'd55: out_idx = 6'd62; 487 | 6'd56: out_idx = 6'd7; 488 | 6'd57: out_idx = 6'd15; 489 | 6'd58: out_idx = 6'd23; 490 | 6'd59: out_idx = 6'd31; 491 | 6'd60: out_idx = 6'd39; 492 | 6'd61: out_idx = 6'd47; 493 | 6'd62: out_idx = 6'd55; 494 | default: out_idx = 6'd63; 495 | endcase 496 | 497 | ptr_conv = out_idx; 498 | end 499 | endfunction 500 | 501 | 502 | assign outport_idx_o = ptr_conv(ptr_q); 503 | 504 | 505 | 506 | endmodule 507 | -------------------------------------------------------------------------------- /src_v/jpeg_input.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_input 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input inport_valid_i 38 | ,input [ 31:0] inport_data_i 39 | ,input [ 3:0] inport_strb_i 40 | ,input inport_last_i 41 | ,input dqt_cfg_accept_i 42 | ,input dht_cfg_accept_i 43 | ,input data_accept_i 44 | 45 | // Outputs 46 | ,output inport_accept_o 47 | ,output img_start_o 48 | ,output img_end_o 49 | ,output [ 15:0] img_width_o 50 | ,output [ 15:0] img_height_o 51 | ,output [ 1:0] img_mode_o 52 | ,output [ 1:0] img_dqt_table_y_o 53 | ,output [ 1:0] img_dqt_table_cb_o 54 | ,output [ 1:0] img_dqt_table_cr_o 55 | ,output dqt_cfg_valid_o 56 | ,output [ 7:0] dqt_cfg_data_o 57 | ,output dqt_cfg_last_o 58 | ,output dht_cfg_valid_o 59 | ,output [ 7:0] dht_cfg_data_o 60 | ,output dht_cfg_last_o 61 | ,output data_valid_o 62 | ,output [ 7:0] data_data_o 63 | ,output data_last_o 64 | ); 65 | 66 | 67 | 68 | wire inport_accept_w; 69 | 70 | //----------------------------------------------------------------- 71 | // Input data read index 72 | //----------------------------------------------------------------- 73 | reg [1:0] byte_idx_q; 74 | 75 | always @ (posedge clk_i ) 76 | if (rst_i) 77 | byte_idx_q <= 2'b0; 78 | else if (inport_valid_i && inport_accept_w && inport_last_i) 79 | byte_idx_q <= 2'b0; 80 | else if (inport_valid_i && inport_accept_w) 81 | byte_idx_q <= byte_idx_q + 2'd1; 82 | 83 | //----------------------------------------------------------------- 84 | // Data mux 85 | //----------------------------------------------------------------- 86 | reg [7:0] data_r; 87 | 88 | always @ * 89 | begin 90 | data_r = 8'b0; 91 | 92 | case (byte_idx_q) 93 | default: data_r = {8{inport_strb_i[0]}} & inport_data_i[7:0]; 94 | 2'd1: data_r = {8{inport_strb_i[1]}} & inport_data_i[15:8]; 95 | 2'd2: data_r = {8{inport_strb_i[2]}} & inport_data_i[23:16]; 96 | 2'd3: data_r = {8{inport_strb_i[3]}} & inport_data_i[31:24]; 97 | endcase 98 | end 99 | 100 | //----------------------------------------------------------------- 101 | // Last data 102 | //----------------------------------------------------------------- 103 | reg [7:0] last_b_q; 104 | 105 | always @ (posedge clk_i ) 106 | if (rst_i) 107 | last_b_q <= 8'b0; 108 | else if (inport_valid_i && inport_accept_w) 109 | last_b_q <= inport_last_i ? 8'b0 : data_r; 110 | 111 | //----------------------------------------------------------------- 112 | // Token decoder 113 | //----------------------------------------------------------------- 114 | wire token_soi_w = (last_b_q == 8'hFF && data_r == 8'hd8); 115 | wire token_sof0_w = (last_b_q == 8'hFF && data_r == 8'hc0); 116 | wire token_dqt_w = (last_b_q == 8'hFF && data_r == 8'hdb); 117 | wire token_dht_w = (last_b_q == 8'hFF && data_r == 8'hc4); 118 | wire token_eoi_w = (last_b_q == 8'hFF && data_r == 8'hd9); 119 | wire token_sos_w = (last_b_q == 8'hFF && data_r == 8'hda); 120 | wire token_pad_w = (last_b_q == 8'hFF && data_r == 8'h00); 121 | 122 | // Unsupported 123 | wire token_sof2_w = (last_b_q == 8'hFF && data_r == 8'hc2); 124 | wire token_dri_w = (last_b_q == 8'hFF && data_r == 8'hdd); 125 | wire token_rst_w = (last_b_q == 8'hFF && data_r >= 8'hd0 && data_r <= 8'hd7); 126 | wire token_app_w = (last_b_q == 8'hFF && data_r >= 8'he0 && data_r <= 8'hef); 127 | wire token_com_w = (last_b_q == 8'hFF && data_r == 8'hfe); 128 | 129 | //----------------------------------------------------------------- 130 | // FSM 131 | //----------------------------------------------------------------- 132 | localparam STATE_W = 5; 133 | localparam STATE_IDLE = 5'd0; 134 | localparam STATE_ACTIVE = 5'd1; 135 | localparam STATE_UXP_LENH = 5'd2; 136 | localparam STATE_UXP_LENL = 5'd3; 137 | localparam STATE_UXP_DATA = 5'd4; 138 | localparam STATE_DQT_LENH = 5'd5; 139 | localparam STATE_DQT_LENL = 5'd6; 140 | localparam STATE_DQT_DATA = 5'd7; 141 | localparam STATE_DHT_LENH = 5'd8; 142 | localparam STATE_DHT_LENL = 5'd9; 143 | localparam STATE_DHT_DATA = 5'd10; 144 | localparam STATE_IMG_LENH = 5'd11; 145 | localparam STATE_IMG_LENL = 5'd12; 146 | localparam STATE_IMG_SOS = 5'd13; 147 | localparam STATE_IMG_DATA = 5'd14; 148 | localparam STATE_SOF_LENH = 5'd15; 149 | localparam STATE_SOF_LENL = 5'd16; 150 | localparam STATE_SOF_DATA = 5'd17; 151 | 152 | reg [STATE_W-1:0] state_q; 153 | reg [15:0] length_q; 154 | 155 | reg [STATE_W-1:0] next_state_r; 156 | always @ * 157 | begin 158 | next_state_r = state_q; 159 | 160 | case (state_q) 161 | //------------------------------------------------------------- 162 | // IDLE - waiting for SOI 163 | //------------------------------------------------------------- 164 | STATE_IDLE : 165 | begin 166 | if (token_soi_w) 167 | next_state_r = STATE_ACTIVE; 168 | end 169 | //------------------------------------------------------------- 170 | // ACTIVE - waiting for various image markers 171 | //------------------------------------------------------------- 172 | STATE_ACTIVE : 173 | begin 174 | if (token_eoi_w) 175 | next_state_r = STATE_IDLE; 176 | else if (token_dqt_w) 177 | next_state_r = STATE_DQT_LENH; 178 | else if (token_dht_w) 179 | next_state_r = STATE_DHT_LENH; 180 | else if (token_sos_w) 181 | next_state_r = STATE_IMG_LENH; 182 | else if (token_sof0_w) 183 | next_state_r = STATE_SOF_LENH; 184 | // Unsupported 185 | else if (token_sof2_w || 186 | token_dri_w || 187 | token_rst_w || 188 | token_app_w || 189 | token_com_w) 190 | next_state_r = STATE_UXP_LENH; 191 | 192 | end 193 | //------------------------------------------------------------- 194 | // IMG 195 | //------------------------------------------------------------- 196 | STATE_IMG_LENH : 197 | begin 198 | if (inport_valid_i) 199 | next_state_r = STATE_IMG_LENL; 200 | end 201 | STATE_IMG_LENL : 202 | begin 203 | if (inport_valid_i) 204 | next_state_r = STATE_IMG_SOS; 205 | end 206 | STATE_IMG_SOS : 207 | begin 208 | if (inport_valid_i && length_q <= 16'd1) 209 | next_state_r = STATE_IMG_DATA; 210 | end 211 | STATE_IMG_DATA : 212 | begin 213 | if (token_eoi_w) 214 | next_state_r = STATE_IDLE; 215 | end 216 | //------------------------------------------------------------- 217 | // DQT 218 | //------------------------------------------------------------- 219 | STATE_DQT_LENH : 220 | begin 221 | if (inport_valid_i) 222 | next_state_r = STATE_DQT_LENL; 223 | end 224 | STATE_DQT_LENL : 225 | begin 226 | if (inport_valid_i) 227 | next_state_r = STATE_DQT_DATA; 228 | end 229 | STATE_DQT_DATA : 230 | begin 231 | if (inport_valid_i && inport_accept_w && length_q <= 16'd1) 232 | next_state_r = STATE_ACTIVE; 233 | end 234 | //------------------------------------------------------------- 235 | // SOF 236 | //------------------------------------------------------------- 237 | STATE_SOF_LENH : 238 | begin 239 | if (inport_valid_i) 240 | next_state_r = STATE_SOF_LENL; 241 | end 242 | STATE_SOF_LENL : 243 | begin 244 | if (inport_valid_i) 245 | next_state_r = STATE_SOF_DATA; 246 | end 247 | STATE_SOF_DATA : 248 | begin 249 | if (inport_valid_i && inport_accept_w && length_q <= 16'd1) 250 | next_state_r = STATE_ACTIVE; 251 | end 252 | //------------------------------------------------------------- 253 | // DHT 254 | //------------------------------------------------------------- 255 | STATE_DHT_LENH : 256 | begin 257 | if (inport_valid_i) 258 | next_state_r = STATE_DHT_LENL; 259 | end 260 | STATE_DHT_LENL : 261 | begin 262 | if (inport_valid_i) 263 | next_state_r = STATE_DHT_DATA; 264 | end 265 | STATE_DHT_DATA : 266 | begin 267 | if (inport_valid_i && inport_accept_w && length_q <= 16'd1) 268 | next_state_r = STATE_ACTIVE; 269 | end 270 | //------------------------------------------------------------- 271 | // Unsupported sections - skip 272 | //------------------------------------------------------------- 273 | STATE_UXP_LENH : 274 | begin 275 | if (inport_valid_i) 276 | next_state_r = STATE_UXP_LENL; 277 | end 278 | STATE_UXP_LENL : 279 | begin 280 | if (inport_valid_i) 281 | next_state_r = STATE_UXP_DATA; 282 | end 283 | STATE_UXP_DATA : 284 | begin 285 | if (inport_valid_i && inport_accept_w && length_q <= 16'd1) 286 | next_state_r = STATE_ACTIVE; 287 | end 288 | default: 289 | ; 290 | endcase 291 | 292 | // End of data stream 293 | if (inport_valid_i && inport_last_i && inport_accept_w) 294 | next_state_r = STATE_IDLE; 295 | end 296 | 297 | always @ (posedge clk_i ) 298 | if (rst_i) 299 | state_q <= STATE_IDLE; 300 | else 301 | state_q <= next_state_r; 302 | 303 | //----------------------------------------------------------------- 304 | // Length 305 | //----------------------------------------------------------------- 306 | always @ (posedge clk_i ) 307 | if (rst_i) 308 | length_q <= 16'b0; 309 | else if (state_q == STATE_UXP_LENH || state_q == STATE_DQT_LENH || 310 | state_q == STATE_DHT_LENH || state_q == STATE_IMG_LENH || 311 | state_q == STATE_SOF_LENH) 312 | length_q <= {data_r, 8'b0}; 313 | else if (state_q == STATE_UXP_LENL || state_q == STATE_DQT_LENL || 314 | state_q == STATE_DHT_LENL || state_q == STATE_IMG_LENL || 315 | state_q == STATE_SOF_LENL) 316 | length_q <= {8'b0, data_r} - 16'd2; 317 | else if ((state_q == STATE_UXP_DATA || 318 | state_q == STATE_DQT_DATA || 319 | state_q == STATE_DHT_DATA || 320 | state_q == STATE_SOF_DATA || 321 | state_q == STATE_IMG_SOS) && inport_valid_i && inport_accept_w) 322 | length_q <= length_q - 16'd1; 323 | 324 | //----------------------------------------------------------------- 325 | // DQT 326 | //----------------------------------------------------------------- 327 | assign dqt_cfg_valid_o = (state_q == STATE_DQT_DATA) && inport_valid_i; 328 | assign dqt_cfg_data_o = data_r; 329 | assign dqt_cfg_last_o = inport_last_i || (length_q == 16'd1); 330 | 331 | //----------------------------------------------------------------- 332 | // DQT 333 | //----------------------------------------------------------------- 334 | assign dht_cfg_valid_o = (state_q == STATE_DHT_DATA) && inport_valid_i; 335 | assign dht_cfg_data_o = data_r; 336 | assign dht_cfg_last_o = inport_last_i || (length_q == 16'd1); 337 | 338 | //----------------------------------------------------------------- 339 | // Image data 340 | //----------------------------------------------------------------- 341 | reg data_valid_q; 342 | reg [7:0] data_data_q; 343 | reg data_last_q; 344 | 345 | always @ (posedge clk_i ) 346 | if (rst_i) 347 | data_valid_q <= 1'b0; 348 | else if (inport_valid_i && data_accept_i) 349 | data_valid_q <= (state_q == STATE_IMG_DATA) && (inport_valid_i && ~token_pad_w && ~token_eoi_w); 350 | else if (state_q != STATE_IMG_DATA) 351 | data_valid_q <= 1'b0; 352 | 353 | always @ (posedge clk_i ) 354 | if (rst_i) 355 | data_data_q <= 8'b0; 356 | else if (inport_valid_i && data_accept_i) 357 | data_data_q <= data_r; 358 | 359 | assign data_valid_o = data_valid_q && inport_valid_i && !token_eoi_w; 360 | assign data_data_o = data_data_q; 361 | 362 | // NOTE: Last is delayed by one cycles (not qualified by data_valid_o) 363 | assign data_last_o = data_valid_q && inport_valid_i && token_eoi_w; 364 | 365 | //----------------------------------------------------------------- 366 | // Handshaking 367 | //----------------------------------------------------------------- 368 | wire last_byte_w = (byte_idx_q == 2'd3) || inport_last_i; 369 | 370 | assign inport_accept_w = (state_q == STATE_DQT_DATA && dqt_cfg_accept_i) || 371 | (state_q == STATE_DHT_DATA && dht_cfg_accept_i) || 372 | (state_q == STATE_IMG_DATA && (data_accept_i || token_pad_w)) || 373 | (state_q != STATE_DQT_DATA && 374 | state_q != STATE_DHT_DATA && 375 | state_q != STATE_IMG_DATA); 376 | 377 | assign inport_accept_o = last_byte_w && inport_accept_w; 378 | 379 | //----------------------------------------------------------------- 380 | // Capture Index 381 | //----------------------------------------------------------------- 382 | reg [5:0] idx_q; 383 | 384 | always @ (posedge clk_i ) 385 | if (rst_i) 386 | idx_q <= 6'b0; 387 | else if (inport_valid_i && inport_accept_w && state_q == STATE_SOF_DATA) 388 | idx_q <= idx_q + 6'd1; 389 | else if (state_q == STATE_SOF_LENH) 390 | idx_q <= 6'b0; 391 | 392 | //----------------------------------------------------------------- 393 | // SOF capture 394 | //----------------------------------------------------------------- 395 | reg [7:0] img_precision_q; 396 | 397 | always @ (posedge clk_i ) 398 | if (rst_i) 399 | img_precision_q <= 8'b0; 400 | else if (token_sof0_w) 401 | img_precision_q <= 8'b0; 402 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd0) 403 | img_precision_q <= data_r; 404 | 405 | reg [15:0] img_height_q; 406 | 407 | always @ (posedge clk_i ) 408 | if (rst_i) 409 | img_height_q <= 16'b0; 410 | else if (token_sof0_w) 411 | img_height_q <= 16'b0; 412 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd1) 413 | img_height_q <= {data_r, 8'b0}; 414 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd2) 415 | img_height_q <= {img_height_q[15:8], data_r}; 416 | 417 | assign img_height_o = img_height_q; 418 | 419 | reg [15:0] img_width_q; 420 | 421 | always @ (posedge clk_i ) 422 | if (rst_i) 423 | img_width_q <= 16'b0; 424 | else if (token_sof0_w) 425 | img_width_q <= 16'b0; 426 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd3) 427 | img_width_q <= {data_r, 8'b0}; 428 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd4) 429 | img_width_q <= {img_width_q[15:8], data_r}; 430 | 431 | assign img_width_o = img_width_q; 432 | 433 | reg [7:0] img_num_comp_q; 434 | 435 | always @ (posedge clk_i ) 436 | if (rst_i) 437 | img_num_comp_q <= 8'b0; 438 | else if (token_sof0_w) 439 | img_num_comp_q <= 8'b0; 440 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd5) 441 | img_num_comp_q <= data_r; 442 | 443 | reg [7:0] img_y_factor_q; 444 | 445 | always @ (posedge clk_i ) 446 | if (rst_i) 447 | img_y_factor_q <= 8'b0; 448 | else if (token_sof0_w) 449 | img_y_factor_q <= 8'b0; 450 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd7) 451 | img_y_factor_q <= data_r; 452 | 453 | reg [1:0] img_y_dqt_table_q; 454 | 455 | always @ (posedge clk_i ) 456 | if (rst_i) 457 | img_y_dqt_table_q <= 2'b0; 458 | else if (token_sof0_w) 459 | img_y_dqt_table_q <= 2'b0; 460 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd8) 461 | img_y_dqt_table_q <= data_r[1:0]; 462 | 463 | reg [7:0] img_cb_factor_q; 464 | 465 | always @ (posedge clk_i ) 466 | if (rst_i) 467 | img_cb_factor_q <= 8'b0; 468 | else if (token_sof0_w) 469 | img_cb_factor_q <= 8'b0; 470 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd10) 471 | img_cb_factor_q <= data_r; 472 | 473 | reg [1:0] img_cb_dqt_table_q; 474 | 475 | always @ (posedge clk_i ) 476 | if (rst_i) 477 | img_cb_dqt_table_q <= 2'b0; 478 | else if (token_sof0_w) 479 | img_cb_dqt_table_q <= 2'b0; 480 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd11) 481 | img_cb_dqt_table_q <= data_r[1:0]; 482 | 483 | reg [7:0] img_cr_factor_q; 484 | 485 | always @ (posedge clk_i ) 486 | if (rst_i) 487 | img_cr_factor_q <= 8'b0; 488 | else if (token_sof0_w) 489 | img_cr_factor_q <= 8'b0; 490 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd13) 491 | img_cr_factor_q <= data_r; 492 | 493 | reg [1:0] img_cr_dqt_table_q; 494 | 495 | always @ (posedge clk_i ) 496 | if (rst_i) 497 | img_cr_dqt_table_q <= 2'b0; 498 | else if (token_sof0_w) 499 | img_cr_dqt_table_q <= 2'b0; 500 | else if (state_q == STATE_SOF_DATA && idx_q == 6'd14) 501 | img_cr_dqt_table_q <= data_r[1:0]; 502 | 503 | assign img_dqt_table_y_o = img_y_dqt_table_q; 504 | assign img_dqt_table_cb_o = img_cb_dqt_table_q; 505 | assign img_dqt_table_cr_o = img_cr_dqt_table_q; 506 | 507 | wire [3:0] y_horiz_factor_w = img_y_factor_q[7:4]; 508 | wire [3:0] y_vert_factor_w = img_y_factor_q[3:0]; 509 | wire [3:0] cb_horiz_factor_w = img_cb_factor_q[7:4]; 510 | wire [3:0] cb_vert_factor_w = img_cb_factor_q[3:0]; 511 | wire [3:0] cr_horiz_factor_w = img_cr_factor_q[7:4]; 512 | wire [3:0] cr_vert_factor_w = img_cr_factor_q[3:0]; 513 | 514 | localparam JPEG_MONOCHROME = 2'd0; 515 | localparam JPEG_YCBCR_444 = 2'd1; 516 | localparam JPEG_YCBCR_420 = 2'd2; 517 | localparam JPEG_UNSUPPORTED = 2'd3; 518 | 519 | reg [1:0] img_mode_q; 520 | 521 | always @ (posedge clk_i ) 522 | if (rst_i) 523 | img_mode_q <= JPEG_UNSUPPORTED; 524 | else if (token_sof0_w) 525 | img_mode_q <= JPEG_UNSUPPORTED; 526 | else if (state_q == STATE_SOF_DATA && next_state_r == STATE_ACTIVE) 527 | begin 528 | // Single component (Y) 529 | if (img_num_comp_q == 8'd1) 530 | img_mode_q <= JPEG_MONOCHROME; 531 | // Colour image (YCbCr) 532 | else if (img_num_comp_q == 8'd3) 533 | begin 534 | if (y_horiz_factor_w == 4'd1 && y_vert_factor_w == 4'd1 && 535 | cb_horiz_factor_w == 4'd1 && cb_vert_factor_w == 4'd1 && 536 | cr_horiz_factor_w == 4'd1 && cr_vert_factor_w == 4'd1) 537 | img_mode_q <= JPEG_YCBCR_444; 538 | else if (y_horiz_factor_w == 4'd2 && y_vert_factor_w == 4'd2 && 539 | cb_horiz_factor_w == 4'd1 && cb_vert_factor_w == 4'd1 && 540 | cr_horiz_factor_w == 4'd1 && cr_vert_factor_w == 4'd1) 541 | img_mode_q <= JPEG_YCBCR_420; 542 | end 543 | end 544 | 545 | reg eof_q; 546 | 547 | always @ (posedge clk_i ) 548 | if (rst_i) 549 | eof_q <= 1'b1; 550 | else if (state_q == STATE_IDLE && token_soi_w) 551 | eof_q <= 1'b0; 552 | else if (img_end_o) 553 | eof_q <= 1'b1; 554 | 555 | reg start_q; 556 | 557 | always @ (posedge clk_i ) 558 | if (rst_i) 559 | start_q <= 1'b0; 560 | else if (inport_valid_i & token_sos_w) 561 | start_q <= 1'b0; 562 | else if (state_q == STATE_IDLE && token_soi_w) 563 | start_q <= 1'b1; 564 | 565 | assign img_start_o = start_q; 566 | assign img_end_o = eof_q | (inport_valid_i & token_eoi_w); 567 | assign img_mode_o = img_mode_q; 568 | 569 | 570 | endmodule 571 | -------------------------------------------------------------------------------- /src_v/jpeg_mcu_id.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_mcu_id 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input [ 15:0] img_width_i 40 | ,input [ 15:0] img_height_i 41 | ,input [ 1:0] img_mode_i 42 | ,input start_of_block_i 43 | ,input end_of_block_i 44 | 45 | // Outputs 46 | ,output [ 31:0] block_id_o 47 | ,output [ 1:0] block_type_o 48 | ,output end_of_image_o 49 | ); 50 | 51 | 52 | 53 | //----------------------------------------------------------------- 54 | // Block Type (Y, Cb, Cr) 55 | //----------------------------------------------------------------- 56 | localparam JPEG_MONOCHROME = 2'd0; 57 | localparam JPEG_YCBCR_444 = 2'd1; 58 | localparam JPEG_YCBCR_420 = 2'd2; 59 | localparam JPEG_UNSUPPORTED = 2'd3; 60 | 61 | localparam BLOCK_Y = 2'd0; 62 | localparam BLOCK_CB = 2'd1; 63 | localparam BLOCK_CR = 2'd2; 64 | localparam BLOCK_EOF = 2'd3; 65 | 66 | reg [1:0] block_type_q; 67 | reg [2:0] type_idx_q; 68 | 69 | always @ (posedge clk_i ) 70 | if (rst_i) 71 | begin 72 | block_type_q <= BLOCK_Y; 73 | type_idx_q <= 3'd0; 74 | end 75 | else if (img_start_i) 76 | begin 77 | block_type_q <= BLOCK_Y; 78 | type_idx_q <= 3'd0; 79 | end 80 | else if (start_of_block_i && end_of_image_o) 81 | begin 82 | block_type_q <= BLOCK_EOF; 83 | type_idx_q <= 3'd0; 84 | end 85 | else if (img_mode_i == JPEG_MONOCHROME) 86 | block_type_q <= BLOCK_Y; 87 | else if (img_mode_i == JPEG_YCBCR_444 && end_of_block_i) 88 | begin 89 | if (block_type_q == BLOCK_CR) 90 | block_type_q <= BLOCK_Y; 91 | else 92 | block_type_q <= block_type_q + 2'd1; 93 | end 94 | else if (img_mode_i == JPEG_YCBCR_420 && end_of_block_i) 95 | begin 96 | type_idx_q <= type_idx_q + 3'd1; 97 | 98 | case (type_idx_q) 99 | default: 100 | block_type_q <= BLOCK_Y; 101 | 3'd3: 102 | block_type_q <= BLOCK_CB; 103 | 3'd4: 104 | block_type_q <= BLOCK_CR; 105 | 3'd5: 106 | begin 107 | block_type_q <= BLOCK_Y; 108 | type_idx_q <= 3'd0; 109 | end 110 | endcase 111 | end 112 | 113 | //----------------------------------------------------------------- 114 | // Block index 115 | //----------------------------------------------------------------- 116 | wire [15:0] width_rnd_w = ((img_width_i+7) / 8) * 8; 117 | wire [15:0] block_x_max_w = width_rnd_w / 8; 118 | wire [15:0] img_w_div4_w = width_rnd_w / 4; 119 | 120 | reg [15:0] block_x_q; 121 | reg [15:0] block_y_q; 122 | 123 | reg [15:0] x_idx_q; 124 | reg [15:0] y_idx_q; 125 | 126 | wire [15:0] block_x_next_w = block_x_q + 16'd1; 127 | 128 | reg end_of_image_q; 129 | 130 | always @ (posedge clk_i ) 131 | if (rst_i) 132 | begin 133 | block_x_q <= 16'b0; 134 | block_y_q <= 16'b0; 135 | x_idx_q <= 16'b0; 136 | y_idx_q <= 16'b0; 137 | end_of_image_q <= 1'b0; 138 | end 139 | else if (img_start_i) 140 | begin 141 | block_x_q <= 16'b0; 142 | block_y_q <= 16'b0; 143 | x_idx_q <= 16'b0; 144 | y_idx_q <= 16'b0; 145 | end_of_image_q <= 1'b0; 146 | end 147 | else if (end_of_block_i && ((img_mode_i == JPEG_MONOCHROME) || (img_mode_i == JPEG_YCBCR_444 && block_type_q == BLOCK_CR))) 148 | begin 149 | if (block_x_next_w == block_x_max_w) 150 | begin 151 | block_x_q <= 16'b0; 152 | block_y_q <= block_y_q + 16'd1; 153 | end 154 | else 155 | block_x_q <= block_x_next_w; 156 | 157 | if (img_end_i && block_x_next_w == block_x_max_w) 158 | end_of_image_q <= 1'b1; 159 | end 160 | else if (start_of_block_i && img_mode_i == JPEG_YCBCR_420 && block_type_q == BLOCK_Y) 161 | begin 162 | block_x_q <= ({x_idx_q[15:2], 2'b0} / 2) + (type_idx_q[0] ? 16'd1 : 16'd0); 163 | block_y_q <= y_idx_q + (type_idx_q[1] ? 16'd1 : 16'd0); 164 | 165 | // Y component 166 | if (type_idx_q < 3'd4) 167 | begin 168 | if ((x_idx_q + 16'd1) == img_w_div4_w) 169 | begin 170 | x_idx_q <= 16'd0; 171 | y_idx_q <= y_idx_q + 16'd2; 172 | end 173 | else 174 | x_idx_q <= x_idx_q + 16'd1; 175 | end 176 | end 177 | else if (start_of_block_i && img_mode_i == JPEG_YCBCR_420 && block_type_q == BLOCK_CR) 178 | begin 179 | if (img_end_i && block_x_next_w == block_x_max_w) 180 | end_of_image_q <= 1'b1; 181 | end 182 | 183 | //----------------------------------------------------------------- 184 | // Outputs 185 | //----------------------------------------------------------------- 186 | // Block ID (type=y|cb|cr, y pos, x pos) 187 | assign block_id_o = {block_type_q, block_y_q[13:0], block_x_q}; 188 | assign block_type_o = block_type_q; 189 | 190 | // End of image detection 191 | assign end_of_image_o = end_of_image_q; 192 | 193 | 194 | endmodule 195 | -------------------------------------------------------------------------------- /src_v/jpeg_mcu_proc.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_mcu_proc 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input [ 15:0] img_width_i 40 | ,input [ 15:0] img_height_i 41 | ,input [ 1:0] img_mode_i 42 | ,input inport_valid_i 43 | ,input [ 31:0] inport_data_i 44 | ,input inport_last_i 45 | ,input lookup_valid_i 46 | ,input [ 4:0] lookup_width_i 47 | ,input [ 7:0] lookup_value_i 48 | ,input outport_blk_space_i 49 | 50 | // Outputs 51 | ,output [ 5:0] inport_pop_o 52 | ,output lookup_req_o 53 | ,output [ 1:0] lookup_table_o 54 | ,output [ 15:0] lookup_input_o 55 | ,output outport_valid_o 56 | ,output [ 15:0] outport_data_o 57 | ,output [ 5:0] outport_idx_o 58 | ,output [ 31:0] outport_id_o 59 | ,output outport_eob_o 60 | ); 61 | 62 | 63 | 64 | //----------------------------------------------------------------- 65 | // Block Type (Y, Cb, Cr) 66 | //----------------------------------------------------------------- 67 | wire start_block_w; 68 | wire next_block_w; 69 | wire end_of_image_w; 70 | 71 | localparam JPEG_MONOCHROME = 2'd0; 72 | localparam JPEG_YCBCR_444 = 2'd1; 73 | localparam JPEG_YCBCR_420 = 2'd2; 74 | localparam JPEG_UNSUPPORTED = 2'd3; 75 | 76 | localparam BLOCK_Y = 2'd0; 77 | localparam BLOCK_CB = 2'd1; 78 | localparam BLOCK_CR = 2'd2; 79 | localparam BLOCK_EOF = 2'd3; 80 | 81 | wire [1:0] block_type_w; 82 | 83 | localparam DHT_TABLE_Y_DC_IDX = 2'd0; 84 | localparam DHT_TABLE_Y_AC_IDX = 2'd1; 85 | localparam DHT_TABLE_CX_DC_IDX = 2'd2; 86 | localparam DHT_TABLE_CX_AC_IDX = 2'd3; 87 | 88 | jpeg_mcu_id 89 | u_id 90 | ( 91 | .clk_i(clk_i) 92 | ,.rst_i(rst_i) 93 | 94 | ,.img_start_i(img_start_i) 95 | ,.img_end_i(img_end_i) 96 | ,.img_width_i(img_width_i) 97 | ,.img_height_i(img_height_i) 98 | ,.img_mode_i(img_mode_i) 99 | 100 | ,.start_of_block_i(start_block_w) 101 | ,.end_of_block_i(next_block_w) 102 | 103 | ,.block_id_o(outport_id_o) 104 | ,.block_type_o(block_type_w) 105 | ,.end_of_image_o(end_of_image_w) 106 | ); 107 | 108 | //----------------------------------------------------------------- 109 | // FSM 110 | //----------------------------------------------------------------- 111 | localparam STATE_W = 5; 112 | localparam STATE_IDLE = 5'd0; 113 | localparam STATE_FETCH_WORD = 5'd1; 114 | localparam STATE_HUFF_LOOKUP = 5'd2; 115 | localparam STATE_OUTPUT = 5'd3; 116 | localparam STATE_EOB = 5'd4; 117 | localparam STATE_EOF = 5'd5; 118 | 119 | reg [STATE_W-1:0] state_q; 120 | reg [STATE_W-1:0] next_state_r; 121 | 122 | reg [7:0] code_bits_q; 123 | reg [7:0] coeff_idx_q; 124 | 125 | always @ * 126 | begin 127 | next_state_r = state_q; 128 | 129 | case (state_q) 130 | STATE_IDLE: 131 | begin 132 | if (end_of_image_w && outport_blk_space_i) 133 | next_state_r = STATE_EOF; 134 | else if (inport_valid_i && outport_blk_space_i) 135 | next_state_r = STATE_FETCH_WORD; 136 | end 137 | STATE_FETCH_WORD: 138 | begin 139 | if (coeff_idx_q >= 8'd63) 140 | next_state_r = STATE_EOB; 141 | else if (inport_valid_i) 142 | next_state_r = STATE_HUFF_LOOKUP; 143 | end 144 | STATE_HUFF_LOOKUP: 145 | begin 146 | if (lookup_valid_i) 147 | next_state_r = STATE_OUTPUT; 148 | end 149 | STATE_OUTPUT: 150 | begin 151 | next_state_r = STATE_FETCH_WORD; 152 | end 153 | STATE_EOB: 154 | begin 155 | next_state_r = STATE_IDLE; 156 | end 157 | STATE_EOF: 158 | begin 159 | if (!img_end_i) 160 | next_state_r = STATE_IDLE; 161 | end 162 | default : ; 163 | endcase 164 | 165 | if (img_start_i) 166 | next_state_r = STATE_IDLE; 167 | end 168 | 169 | assign start_block_w = (state_q == STATE_IDLE && next_state_r != STATE_IDLE); 170 | assign next_block_w = (state_q == STATE_EOB); 171 | 172 | always @ (posedge clk_i ) 173 | if (rst_i) 174 | state_q <= STATE_IDLE; 175 | else 176 | state_q <= next_state_r; 177 | 178 | reg first_q; 179 | 180 | always @ (posedge clk_i ) 181 | if (rst_i) 182 | first_q <= 1'b1; 183 | else if (state_q == STATE_IDLE) 184 | first_q <= 1'b1; 185 | else if (state_q == STATE_OUTPUT) 186 | first_q <= 1'b0; 187 | 188 | //----------------------------------------------------------------- 189 | // Huffman code lookup stash 190 | //----------------------------------------------------------------- 191 | reg [7:0] code_q; 192 | 193 | always @ (posedge clk_i ) 194 | if (rst_i) 195 | code_q <= 8'b0; 196 | else if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i) 197 | code_q <= lookup_value_i; 198 | 199 | //----------------------------------------------------------------- 200 | // code[3:0] = width of symbol 201 | //----------------------------------------------------------------- 202 | always @ (posedge clk_i ) 203 | if (rst_i) 204 | code_bits_q <= 8'b0; 205 | else if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i) 206 | code_bits_q <= {4'b0, lookup_value_i[3:0]}; 207 | 208 | //----------------------------------------------------------------- 209 | // Lookup width flops 210 | //----------------------------------------------------------------- 211 | reg [4:0] lookup_width_q; 212 | 213 | always @ (posedge clk_i ) 214 | if (rst_i) 215 | lookup_width_q <= 5'b0; 216 | else if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i) 217 | lookup_width_q <= lookup_width_i; 218 | 219 | //----------------------------------------------------------------- 220 | // Data for coefficient (remainder from Huffman lookup) 221 | //----------------------------------------------------------------- 222 | reg [15:0] input_data_q; 223 | 224 | wire [31:0] input_shift_w = inport_data_i >> (5'd16 - lookup_width_i); 225 | 226 | always @ (posedge clk_i ) 227 | if (rst_i) 228 | input_data_q <= 16'b0; 229 | // Use remaining data for actual coeffecient 230 | else if (state_q == STATE_HUFF_LOOKUP && lookup_valid_i) 231 | input_data_q <= input_shift_w[15:0]; 232 | 233 | //----------------------------------------------------------------- 234 | // Bit buffer pop 235 | //----------------------------------------------------------------- 236 | reg [5:0] pop_bits_r; 237 | 238 | wire [4:0] coef_bits_w = {1'b0, code_q[3:0]}; 239 | 240 | always @ * 241 | begin 242 | pop_bits_r = 6'b0; 243 | 244 | case (state_q) 245 | STATE_OUTPUT: 246 | begin 247 | // DC coefficient 248 | if (coeff_idx_q == 8'd0) 249 | pop_bits_r = {1'b0, lookup_width_q} + coef_bits_w; 250 | // End of block or ZRL (no coefficient) 251 | else if (code_q == 8'b0 || code_q == 8'hF0) 252 | pop_bits_r = {1'b0, lookup_width_q}; 253 | else 254 | pop_bits_r = {1'b0, lookup_width_q} + coef_bits_w; 255 | end 256 | default : ; 257 | endcase 258 | end 259 | 260 | assign lookup_req_o = (state_q == STATE_FETCH_WORD) & inport_valid_i; 261 | assign lookup_input_o = inport_data_i[31:16]; 262 | assign inport_pop_o = pop_bits_r; 263 | 264 | reg [1:0] lookup_table_r; 265 | always @ * 266 | begin 267 | lookup_table_r = DHT_TABLE_Y_DC_IDX; 268 | 269 | if (first_q) // (coeff_idx_q == 8'd0) 270 | begin 271 | if (block_type_w == BLOCK_Y) 272 | lookup_table_r = DHT_TABLE_Y_DC_IDX; 273 | else 274 | lookup_table_r = DHT_TABLE_CX_DC_IDX; 275 | end 276 | else 277 | begin 278 | if (block_type_w == BLOCK_Y) 279 | lookup_table_r = DHT_TABLE_Y_AC_IDX; 280 | else 281 | lookup_table_r = DHT_TABLE_CX_AC_IDX; 282 | end 283 | end 284 | assign lookup_table_o = lookup_table_r; 285 | 286 | //----------------------------------------------------------------------------- 287 | // decode_number: Extract number from code / width 288 | //----------------------------------------------------------------------------- 289 | function [15:0] decode_number; 290 | input [15:0] w; 291 | input [4:0] bits; 292 | reg signed [15:0] code; 293 | begin 294 | code = w; 295 | 296 | if ((code & (1<<(bits - 5'd1))) == 16'b0 && bits != 5'd0) 297 | begin 298 | code = (code | ((~0) << bits)) + 1; 299 | end 300 | decode_number = code; 301 | end 302 | endfunction 303 | 304 | //----------------------------------------------------------------- 305 | // Previous DC coeffecient 306 | //----------------------------------------------------------------- 307 | wire [1:0] comp_idx_w = block_type_w; 308 | 309 | reg [15:0] prev_dc_coeff_q[3:0]; 310 | reg [15:0] dc_coeff_q; 311 | 312 | always @ (posedge clk_i ) 313 | if (rst_i) 314 | begin 315 | prev_dc_coeff_q[0] <= 16'b0; 316 | prev_dc_coeff_q[1] <= 16'b0; 317 | prev_dc_coeff_q[2] <= 16'b0; 318 | prev_dc_coeff_q[3] <= 16'b0; // X 319 | end 320 | else if (img_start_i) 321 | begin 322 | prev_dc_coeff_q[0] <= 16'b0; 323 | prev_dc_coeff_q[1] <= 16'b0; 324 | prev_dc_coeff_q[2] <= 16'b0; 325 | prev_dc_coeff_q[3] <= 16'b0; // X 326 | end 327 | else if (state_q == STATE_EOB) 328 | prev_dc_coeff_q[comp_idx_w] <= dc_coeff_q; 329 | 330 | //----------------------------------------------------------------- 331 | // coeff 332 | //----------------------------------------------------------------- 333 | reg [15:0] coeff_r; 334 | 335 | always @ * 336 | begin 337 | if (coeff_idx_q == 8'b0) 338 | coeff_r = decode_number(input_data_q >> (16 - coef_bits_w), coef_bits_w) + prev_dc_coeff_q[comp_idx_w]; 339 | else 340 | coeff_r = decode_number(input_data_q >> (16 - coef_bits_w), coef_bits_w); 341 | end 342 | 343 | //----------------------------------------------------------------- 344 | // dc_coeff 345 | //----------------------------------------------------------------- 346 | always @ (posedge clk_i ) 347 | if (rst_i) 348 | dc_coeff_q <= 16'b0; 349 | else if (state_q == STATE_OUTPUT && coeff_idx_q == 8'b0) 350 | dc_coeff_q <= coeff_r; 351 | 352 | //----------------------------------------------------------------- 353 | // DC / AC coeff 354 | //----------------------------------------------------------------- 355 | reg [15:0] coeff_q; 356 | 357 | always @ (posedge clk_i ) 358 | if (rst_i) 359 | coeff_q <= 16'b0; 360 | else if (state_q == STATE_OUTPUT) 361 | coeff_q <= coeff_r; 362 | 363 | //----------------------------------------------------------------- 364 | // Coeffecient index 365 | //----------------------------------------------------------------- 366 | always @ (posedge clk_i ) 367 | if (rst_i) 368 | coeff_idx_q <= 8'b0; 369 | else if (state_q == STATE_EOB || img_start_i) 370 | coeff_idx_q <= 8'b0; 371 | else if (state_q == STATE_FETCH_WORD && !first_q && inport_valid_i) 372 | coeff_idx_q <= coeff_idx_q + 8'd1; 373 | else if (state_q == STATE_OUTPUT) 374 | begin 375 | // DC 376 | if (coeff_idx_q == 8'b0) 377 | ; 378 | // AC 379 | else 380 | begin 381 | // End of block 382 | if (code_q == 8'b0) 383 | coeff_idx_q <= 8'd64; 384 | // ZRL - 16 zeros 385 | else if (code_q == 8'hF0) 386 | coeff_idx_q <= coeff_idx_q + 8'd15; 387 | // RLE number zeros (0 - 15) 388 | else 389 | coeff_idx_q <= coeff_idx_q + {4'b0, code_q[7:4]}; 390 | end 391 | end 392 | 393 | //----------------------------------------------------------------- 394 | // Output push 395 | //----------------------------------------------------------------- 396 | reg push_q; 397 | 398 | always @ (posedge clk_i ) 399 | if (rst_i) 400 | push_q <= 1'b0; 401 | else if (state_q == STATE_OUTPUT || state_q == STATE_EOF) 402 | push_q <= 1'b1; 403 | else 404 | push_q <= 1'b0; 405 | 406 | assign outport_valid_o = push_q && (coeff_idx_q < 8'd64); 407 | assign outport_data_o = coeff_q; 408 | assign outport_idx_o = coeff_idx_q[5:0]; 409 | assign outport_eob_o = (state_q == STATE_EOB) || 410 | (state_q == STATE_EOF && push_q); 411 | 412 | `ifdef verilator 413 | function get_valid; /*verilator public*/ 414 | begin 415 | get_valid = outport_valid_o && block_type_w != BLOCK_EOF; 416 | end 417 | endfunction 418 | function [5:0] get_sample_idx; /*verilator public*/ 419 | begin 420 | get_sample_idx = outport_idx_o; 421 | end 422 | endfunction 423 | function [15:0] get_sample; /*verilator public*/ 424 | begin 425 | get_sample = outport_data_o; 426 | end 427 | endfunction 428 | 429 | function [5:0] get_bitbuffer_pop; /*verilator public*/ 430 | begin 431 | get_bitbuffer_pop = inport_pop_o; 432 | end 433 | endfunction 434 | 435 | function get_dht_valid; /*verilator public*/ 436 | begin 437 | get_dht_valid = lookup_valid_i && (state_q == STATE_HUFF_LOOKUP); 438 | end 439 | endfunction 440 | function [4:0] get_dht_width; /*verilator public*/ 441 | begin 442 | get_dht_width = lookup_width_i; 443 | end 444 | endfunction 445 | function [7:0] get_dht_value; /*verilator public*/ 446 | begin 447 | get_dht_value = lookup_value_i; 448 | end 449 | endfunction 450 | `endif 451 | 452 | 453 | endmodule 454 | -------------------------------------------------------------------------------- /src_v/jpeg_output.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_output 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input img_start_i 38 | ,input img_end_i 39 | ,input [ 15:0] img_width_i 40 | ,input [ 15:0] img_height_i 41 | ,input [ 1:0] img_mode_i 42 | ,input inport_valid_i 43 | ,input [ 31:0] inport_data_i 44 | ,input [ 5:0] inport_idx_i 45 | ,input [ 31:0] inport_id_i 46 | ,input outport_accept_i 47 | 48 | // Outputs 49 | ,output inport_accept_o 50 | ,output outport_valid_o 51 | ,output [ 15:0] outport_width_o 52 | ,output [ 15:0] outport_height_o 53 | ,output [ 15:0] outport_pixel_x_o 54 | ,output [ 15:0] outport_pixel_y_o 55 | ,output [ 7:0] outport_pixel_r_o 56 | ,output [ 7:0] outport_pixel_g_o 57 | ,output [ 7:0] outport_pixel_b_o 58 | ,output idle_o 59 | ); 60 | 61 | 62 | 63 | localparam BLOCK_Y = 2'd0; 64 | localparam BLOCK_CB = 2'd1; 65 | localparam BLOCK_CR = 2'd2; 66 | localparam BLOCK_EOF = 2'd3; 67 | 68 | localparam JPEG_MONOCHROME = 2'd0; 69 | localparam JPEG_YCBCR_444 = 2'd1; 70 | localparam JPEG_YCBCR_420 = 2'd2; 71 | localparam JPEG_UNSUPPORTED = 2'd3; 72 | 73 | reg valid_r; 74 | wire output_space_w = (!outport_valid_o || outport_accept_i); 75 | 76 | //----------------------------------------------------------------- 77 | // FIFO: Y 78 | //----------------------------------------------------------------- 79 | wire y_valid_w; 80 | wire signed [31:0] y_value_w; 81 | wire y_pop_w; 82 | wire [31:0] y_level_w; 83 | 84 | jpeg_output_y_ram 85 | u_ram_y 86 | ( 87 | .clk_i(clk_i) 88 | ,.rst_i(rst_i) 89 | 90 | ,.flush_i(img_start_i) 91 | ,.level_o(y_level_w) 92 | 93 | ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_Y || inport_id_i[31:30] == BLOCK_EOF)) 94 | ,.wr_idx_i(inport_idx_i) 95 | ,.data_in_i(inport_data_i) 96 | 97 | ,.valid_o(y_valid_w) 98 | ,.data_out_o(y_value_w) 99 | ,.pop_i(y_pop_w) 100 | ); 101 | 102 | //----------------------------------------------------------------- 103 | // FIFO: Cb 104 | //----------------------------------------------------------------- 105 | wire cb_valid_w; 106 | wire signed [31:0] cb_value_w; 107 | wire cb_pop_w; 108 | wire [31:0] cb_level_w; 109 | 110 | jpeg_output_cx_ram 111 | u_ram_cb 112 | ( 113 | .clk_i(clk_i) 114 | ,.rst_i(rst_i) 115 | 116 | ,.flush_i(img_start_i) 117 | ,.level_o(cb_level_w) 118 | ,.mode420_i(img_mode_i == JPEG_YCBCR_420) 119 | 120 | ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_CB || inport_id_i[31:30] == BLOCK_EOF)) 121 | ,.wr_idx_i(inport_idx_i) 122 | ,.data_in_i(inport_data_i) 123 | 124 | ,.valid_o(cb_valid_w) 125 | ,.data_out_o(cb_value_w) 126 | ,.pop_i(cb_pop_w) 127 | ); 128 | 129 | //----------------------------------------------------------------- 130 | // FIFO: Cr 131 | //----------------------------------------------------------------- 132 | wire cr_valid_w; 133 | wire signed [31:0] cr_value_w; 134 | wire cr_pop_w; 135 | wire [31:0] cr_level_w; 136 | 137 | jpeg_output_cx_ram 138 | u_ram_cr 139 | ( 140 | .clk_i(clk_i) 141 | ,.rst_i(rst_i) 142 | 143 | ,.flush_i(img_start_i) 144 | ,.level_o(cr_level_w) 145 | ,.mode420_i(img_mode_i == JPEG_YCBCR_420) 146 | 147 | ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_CR || inport_id_i[31:30] == BLOCK_EOF)) 148 | ,.wr_idx_i(inport_idx_i) 149 | ,.data_in_i(inport_data_i) 150 | 151 | ,.valid_o(cr_valid_w) 152 | ,.data_out_o(cr_value_w) 153 | ,.pop_i(cr_pop_w) 154 | ); 155 | 156 | //----------------------------------------------------------------- 157 | // FIFO: Info 158 | //----------------------------------------------------------------- 159 | wire id_valid_w; 160 | wire [31:0] id_value_w; 161 | wire id_pop_w; 162 | 163 | jpeg_output_fifo 164 | #( 165 | .WIDTH(32) 166 | ,.DEPTH(8) 167 | ,.ADDR_W(3) 168 | ) 169 | u_info 170 | ( 171 | .clk_i(clk_i) 172 | ,.rst_i(rst_i) 173 | ,.flush_i(img_start_i) 174 | 175 | ,.push_i(inport_valid_i && (inport_id_i[31:30] == BLOCK_Y || inport_id_i[31:30] == BLOCK_EOF) && inport_idx_i == 6'd0) 176 | ,.data_in_i(inport_id_i) 177 | ,.accept_o() 178 | 179 | ,.valid_o(id_valid_w) 180 | ,.data_out_o(id_value_w) 181 | ,.pop_i(id_pop_w) 182 | ); 183 | 184 | assign inport_accept_o = (y_level_w <= 32'd384 && cr_level_w <= 32'd128) | idle_o; 185 | 186 | //----------------------------------------------------------------- 187 | // Block counter (0 - 63) 188 | //----------------------------------------------------------------- 189 | reg [5:0] idx_q; 190 | 191 | always @ (posedge clk_i ) 192 | if (rst_i) 193 | idx_q <= 6'b0; 194 | else if (img_start_i) 195 | idx_q <= 6'b0; 196 | else if (valid_r && output_space_w) 197 | idx_q <= idx_q + 6'd1; 198 | 199 | //----------------------------------------------------------------- 200 | // Subsampling counter (420 chroma subsampling) 201 | //----------------------------------------------------------------- 202 | reg [1:0] subsmpl_q; 203 | 204 | always @ (posedge clk_i ) 205 | if (rst_i) 206 | subsmpl_q <= 2'b0; 207 | else if (img_start_i) 208 | subsmpl_q <= 2'b0; 209 | else if (valid_r && output_space_w && img_mode_i == JPEG_YCBCR_420 && idx_q == 6'd63) 210 | subsmpl_q <= subsmpl_q + 2'd1; 211 | 212 | //----------------------------------------------------------------- 213 | // YUV -> RGB 214 | //----------------------------------------------------------------- 215 | reg active_q; 216 | 217 | always @ (posedge clk_i ) 218 | if (rst_i) 219 | active_q <= 1'b0; 220 | else if (img_start_i) 221 | active_q <= 1'b0; 222 | else if (!active_q) 223 | begin 224 | if (img_mode_i == JPEG_MONOCHROME) 225 | active_q <= (y_level_w >= 32'd64); 226 | else if (img_mode_i == JPEG_YCBCR_444) 227 | active_q <= (y_level_w >= 32'd64) && (cb_level_w >= 32'd64) && (cr_level_w >= 32'd64); 228 | else if (subsmpl_q != 2'b0) // 420 229 | active_q <= 1'b1; 230 | else // 420 231 | active_q <= (y_level_w >= 32'd256) && (cb_level_w >= 32'd256) && (cr_level_w >= 32'd256); 232 | end 233 | else if (valid_r && output_space_w && idx_q == 6'd63) 234 | active_q <= 1'b0; 235 | 236 | reg signed [31:0] r_conv_r; 237 | reg signed [31:0] g_conv_r; 238 | reg signed [31:0] b_conv_r; 239 | 240 | wire signed [31:0] cr_1_402_w = (cr_value_w * 5743) >>> 12; // cr_value_w * 1.402 241 | wire signed [31:0] cr_0_714_w = (cr_value_w * 2925) >>> 12; // cr_value_w * 0.71414 242 | wire signed [31:0] cb_0_344_w = (cb_value_w * 1410) >>> 12; // cb_value_w * 0.34414 243 | wire signed [31:0] cb_1_772_w = (cb_value_w * 7258) >>> 12; // cb_value_w * 1.772 244 | 245 | always @ * 246 | begin 247 | valid_r = active_q; 248 | r_conv_r = 32'b0; 249 | g_conv_r = 32'b0; 250 | b_conv_r = 32'b0; 251 | 252 | if (img_mode_i == JPEG_MONOCHROME) 253 | begin 254 | r_conv_r = 128 + y_value_w; 255 | g_conv_r = 128 + y_value_w; 256 | b_conv_r = 128 + y_value_w; 257 | end 258 | else// if (img_mode_i == JPEG_YCBCR_444) 259 | begin 260 | r_conv_r = 128 + y_value_w + cr_1_402_w; 261 | g_conv_r = 128 + y_value_w - cb_0_344_w - cr_0_714_w; 262 | b_conv_r = 128 + y_value_w + cb_1_772_w; 263 | end 264 | end 265 | 266 | assign y_pop_w = output_space_w && active_q; 267 | assign cb_pop_w = output_space_w && active_q; 268 | assign cr_pop_w = output_space_w && active_q; 269 | assign id_pop_w = output_space_w && (idx_q == 6'd63); 270 | 271 | //----------------------------------------------------------------- 272 | // Outputs 273 | //----------------------------------------------------------------- 274 | reg valid_q; 275 | reg [15:0] pixel_x_q; 276 | reg [15:0] pixel_y_q; 277 | reg [7:0] pixel_r_q; 278 | reg [7:0] pixel_g_q; 279 | reg [7:0] pixel_b_q; 280 | 281 | always @ (posedge clk_i ) 282 | if (rst_i) 283 | valid_q <= 1'b0; 284 | else if (output_space_w) 285 | valid_q <= valid_r && (id_value_w[31:30] != BLOCK_EOF); 286 | 287 | wire [31:0] x_start_w = {13'b0, id_value_w[15:0],3'b0}; 288 | wire [31:0] y_start_w = {15'b0, id_value_w[29:16],3'b0}; 289 | 290 | always @ (posedge clk_i ) 291 | if (rst_i) 292 | begin 293 | pixel_x_q <= 16'b0; 294 | pixel_y_q <= 16'b0; 295 | end 296 | else if (output_space_w) 297 | begin 298 | /* verilator lint_off WIDTH */ 299 | pixel_x_q <= x_start_w + (idx_q % 8); 300 | pixel_y_q <= y_start_w + (idx_q / 8); 301 | /* verilator lint_on WIDTH */ 302 | end 303 | 304 | always @ (posedge clk_i ) 305 | if (rst_i) 306 | begin 307 | pixel_r_q <= 8'b0; 308 | pixel_g_q <= 8'b0; 309 | pixel_b_q <= 8'b0; 310 | end 311 | else if (output_space_w) 312 | begin 313 | pixel_r_q <= (|r_conv_r[31:8]) ? (r_conv_r[31:24] ^ 8'hff) : r_conv_r[7:0]; 314 | pixel_g_q <= (|g_conv_r[31:8]) ? (g_conv_r[31:24] ^ 8'hff) : g_conv_r[7:0]; 315 | pixel_b_q <= (|b_conv_r[31:8]) ? (b_conv_r[31:24] ^ 8'hff) : b_conv_r[7:0]; 316 | end 317 | 318 | assign outport_valid_o = valid_q; 319 | assign outport_pixel_x_o = pixel_x_q; 320 | assign outport_pixel_y_o = pixel_y_q; 321 | assign outport_width_o = img_width_i; 322 | assign outport_height_o = img_height_i; 323 | assign outport_pixel_r_o = pixel_r_q; 324 | assign outport_pixel_g_o = pixel_g_q; 325 | assign outport_pixel_b_o = pixel_b_q; 326 | 327 | //----------------------------------------------------------------- 328 | // Idle 329 | //----------------------------------------------------------------- 330 | reg idle_q; 331 | 332 | always @ (posedge clk_i ) 333 | if (rst_i) 334 | idle_q <= 1'b1; 335 | else if (img_start_i) 336 | idle_q <= 1'b0; 337 | else if (id_valid_w && id_value_w[31:30] == BLOCK_EOF) 338 | idle_q <= 1'b1; 339 | 340 | assign idle_o = idle_q; 341 | 342 | 343 | endmodule 344 | -------------------------------------------------------------------------------- /src_v/jpeg_output_cx_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_output_cx_ram 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input [ 5:0] wr_idx_i 38 | ,input [ 31:0] data_in_i 39 | ,input push_i 40 | ,input mode420_i 41 | ,input pop_i 42 | ,input flush_i 43 | 44 | // Outputs 45 | ,output [ 31:0] data_out_o 46 | ,output valid_o 47 | ,output [ 31:0] level_o 48 | ); 49 | 50 | 51 | 52 | //----------------------------------------------------------------- 53 | // Registers 54 | //----------------------------------------------------------------- 55 | reg [7:0] rd_ptr_q; 56 | reg [7:0] wr_ptr_q; 57 | 58 | //----------------------------------------------------------------- 59 | // Write Side 60 | //----------------------------------------------------------------- 61 | wire [7:0] write_next_w = wr_ptr_q + 8'd1; 62 | 63 | always @ (posedge clk_i ) 64 | if (rst_i) 65 | wr_ptr_q <= 8'b0; 66 | else if (flush_i) 67 | wr_ptr_q <= 8'b0; 68 | // Push 69 | else if (push_i) 70 | wr_ptr_q <= write_next_w; 71 | 72 | //----------------------------------------------------------------- 73 | // Read Side 74 | //----------------------------------------------------------------- 75 | wire read_ok_w = (level_o > 32'd1); 76 | reg rd_q; 77 | 78 | always @ (posedge clk_i ) 79 | if (rst_i) 80 | rd_q <= 1'b0; 81 | else if (flush_i) 82 | rd_q <= 1'b0; 83 | else 84 | rd_q <= read_ok_w; 85 | 86 | wire [7:0] rd_ptr_next_w = rd_ptr_q + 8'd1; 87 | 88 | always @ (posedge clk_i ) 89 | if (rst_i) 90 | rd_ptr_q <= 8'b0; 91 | else if (flush_i) 92 | rd_ptr_q <= 8'b0; 93 | else if (read_ok_w && ((!valid_o) || (valid_o && pop_i))) 94 | rd_ptr_q <= rd_ptr_next_w; 95 | 96 | //------------------------------------------------------------------- 97 | // Chroma subsampling (420) sample addressing 98 | //------------------------------------------------------------------- 99 | reg [7:0] cx_idx_q; 100 | 101 | reg [5:0] cx_rd_ptr_r; 102 | 103 | always @ * 104 | begin 105 | case (cx_idx_q) 106 | 8'd0: cx_rd_ptr_r = 6'd0; 107 | 8'd1: cx_rd_ptr_r = 6'd1; 108 | 8'd2: cx_rd_ptr_r = 6'd1; 109 | 8'd3: cx_rd_ptr_r = 6'd2; 110 | 8'd4: cx_rd_ptr_r = 6'd2; 111 | 8'd5: cx_rd_ptr_r = 6'd3; 112 | 8'd6: cx_rd_ptr_r = 6'd3; 113 | 8'd7: cx_rd_ptr_r = 6'd0; 114 | 8'd8: cx_rd_ptr_r = 6'd0; 115 | 8'd9: cx_rd_ptr_r = 6'd1; 116 | 8'd10: cx_rd_ptr_r = 6'd1; 117 | 8'd11: cx_rd_ptr_r = 6'd2; 118 | 8'd12: cx_rd_ptr_r = 6'd2; 119 | 8'd13: cx_rd_ptr_r = 6'd3; 120 | 8'd14: cx_rd_ptr_r = 6'd3; 121 | 8'd15: cx_rd_ptr_r = 6'd8; 122 | 8'd16: cx_rd_ptr_r = 6'd8; 123 | 8'd17: cx_rd_ptr_r = 6'd9; 124 | 8'd18: cx_rd_ptr_r = 6'd9; 125 | 8'd19: cx_rd_ptr_r = 6'd10; 126 | 8'd20: cx_rd_ptr_r = 6'd10; 127 | 8'd21: cx_rd_ptr_r = 6'd11; 128 | 8'd22: cx_rd_ptr_r = 6'd11; 129 | 8'd23: cx_rd_ptr_r = 6'd8; 130 | 8'd24: cx_rd_ptr_r = 6'd8; 131 | 8'd25: cx_rd_ptr_r = 6'd9; 132 | 8'd26: cx_rd_ptr_r = 6'd9; 133 | 8'd27: cx_rd_ptr_r = 6'd10; 134 | 8'd28: cx_rd_ptr_r = 6'd10; 135 | 8'd29: cx_rd_ptr_r = 6'd11; 136 | 8'd30: cx_rd_ptr_r = 6'd11; 137 | 8'd31: cx_rd_ptr_r = 6'd16; 138 | 8'd32: cx_rd_ptr_r = 6'd16; 139 | 8'd33: cx_rd_ptr_r = 6'd17; 140 | 8'd34: cx_rd_ptr_r = 6'd17; 141 | 8'd35: cx_rd_ptr_r = 6'd18; 142 | 8'd36: cx_rd_ptr_r = 6'd18; 143 | 8'd37: cx_rd_ptr_r = 6'd19; 144 | 8'd38: cx_rd_ptr_r = 6'd19; 145 | 8'd39: cx_rd_ptr_r = 6'd16; 146 | 8'd40: cx_rd_ptr_r = 6'd16; 147 | 8'd41: cx_rd_ptr_r = 6'd17; 148 | 8'd42: cx_rd_ptr_r = 6'd17; 149 | 8'd43: cx_rd_ptr_r = 6'd18; 150 | 8'd44: cx_rd_ptr_r = 6'd18; 151 | 8'd45: cx_rd_ptr_r = 6'd19; 152 | 8'd46: cx_rd_ptr_r = 6'd19; 153 | 8'd47: cx_rd_ptr_r = 6'd24; 154 | 8'd48: cx_rd_ptr_r = 6'd24; 155 | 8'd49: cx_rd_ptr_r = 6'd25; 156 | 8'd50: cx_rd_ptr_r = 6'd25; 157 | 8'd51: cx_rd_ptr_r = 6'd26; 158 | 8'd52: cx_rd_ptr_r = 6'd26; 159 | 8'd53: cx_rd_ptr_r = 6'd27; 160 | 8'd54: cx_rd_ptr_r = 6'd27; 161 | 8'd55: cx_rd_ptr_r = 6'd24; 162 | 8'd56: cx_rd_ptr_r = 6'd24; 163 | 8'd57: cx_rd_ptr_r = 6'd25; 164 | 8'd58: cx_rd_ptr_r = 6'd25; 165 | 8'd59: cx_rd_ptr_r = 6'd26; 166 | 8'd60: cx_rd_ptr_r = 6'd26; 167 | 8'd61: cx_rd_ptr_r = 6'd27; 168 | 8'd62: cx_rd_ptr_r = 6'd27; 169 | 8'd63: cx_rd_ptr_r = 6'd4; 170 | 8'd64: cx_rd_ptr_r = 6'd4; 171 | 8'd65: cx_rd_ptr_r = 6'd5; 172 | 8'd66: cx_rd_ptr_r = 6'd5; 173 | 8'd67: cx_rd_ptr_r = 6'd6; 174 | 8'd68: cx_rd_ptr_r = 6'd6; 175 | 8'd69: cx_rd_ptr_r = 6'd7; 176 | 8'd70: cx_rd_ptr_r = 6'd7; 177 | 8'd71: cx_rd_ptr_r = 6'd4; 178 | 8'd72: cx_rd_ptr_r = 6'd4; 179 | 8'd73: cx_rd_ptr_r = 6'd5; 180 | 8'd74: cx_rd_ptr_r = 6'd5; 181 | 8'd75: cx_rd_ptr_r = 6'd6; 182 | 8'd76: cx_rd_ptr_r = 6'd6; 183 | 8'd77: cx_rd_ptr_r = 6'd7; 184 | 8'd78: cx_rd_ptr_r = 6'd7; 185 | 8'd79: cx_rd_ptr_r = 6'd12; 186 | 8'd80: cx_rd_ptr_r = 6'd12; 187 | 8'd81: cx_rd_ptr_r = 6'd13; 188 | 8'd82: cx_rd_ptr_r = 6'd13; 189 | 8'd83: cx_rd_ptr_r = 6'd14; 190 | 8'd84: cx_rd_ptr_r = 6'd14; 191 | 8'd85: cx_rd_ptr_r = 6'd15; 192 | 8'd86: cx_rd_ptr_r = 6'd15; 193 | 8'd87: cx_rd_ptr_r = 6'd12; 194 | 8'd88: cx_rd_ptr_r = 6'd12; 195 | 8'd89: cx_rd_ptr_r = 6'd13; 196 | 8'd90: cx_rd_ptr_r = 6'd13; 197 | 8'd91: cx_rd_ptr_r = 6'd14; 198 | 8'd92: cx_rd_ptr_r = 6'd14; 199 | 8'd93: cx_rd_ptr_r = 6'd15; 200 | 8'd94: cx_rd_ptr_r = 6'd15; 201 | 8'd95: cx_rd_ptr_r = 6'd20; 202 | 8'd96: cx_rd_ptr_r = 6'd20; 203 | 8'd97: cx_rd_ptr_r = 6'd21; 204 | 8'd98: cx_rd_ptr_r = 6'd21; 205 | 8'd99: cx_rd_ptr_r = 6'd22; 206 | 8'd100: cx_rd_ptr_r = 6'd22; 207 | 8'd101: cx_rd_ptr_r = 6'd23; 208 | 8'd102: cx_rd_ptr_r = 6'd23; 209 | 8'd103: cx_rd_ptr_r = 6'd20; 210 | 8'd104: cx_rd_ptr_r = 6'd20; 211 | 8'd105: cx_rd_ptr_r = 6'd21; 212 | 8'd106: cx_rd_ptr_r = 6'd21; 213 | 8'd107: cx_rd_ptr_r = 6'd22; 214 | 8'd108: cx_rd_ptr_r = 6'd22; 215 | 8'd109: cx_rd_ptr_r = 6'd23; 216 | 8'd110: cx_rd_ptr_r = 6'd23; 217 | 8'd111: cx_rd_ptr_r = 6'd28; 218 | 8'd112: cx_rd_ptr_r = 6'd28; 219 | 8'd113: cx_rd_ptr_r = 6'd29; 220 | 8'd114: cx_rd_ptr_r = 6'd29; 221 | 8'd115: cx_rd_ptr_r = 6'd30; 222 | 8'd116: cx_rd_ptr_r = 6'd30; 223 | 8'd117: cx_rd_ptr_r = 6'd31; 224 | 8'd118: cx_rd_ptr_r = 6'd31; 225 | 8'd119: cx_rd_ptr_r = 6'd28; 226 | 8'd120: cx_rd_ptr_r = 6'd28; 227 | 8'd121: cx_rd_ptr_r = 6'd29; 228 | 8'd122: cx_rd_ptr_r = 6'd29; 229 | 8'd123: cx_rd_ptr_r = 6'd30; 230 | 8'd124: cx_rd_ptr_r = 6'd30; 231 | 8'd125: cx_rd_ptr_r = 6'd31; 232 | 8'd126: cx_rd_ptr_r = 6'd31; 233 | 8'd127: cx_rd_ptr_r = 6'd32; 234 | 8'd128: cx_rd_ptr_r = 6'd32; 235 | 8'd129: cx_rd_ptr_r = 6'd33; 236 | 8'd130: cx_rd_ptr_r = 6'd33; 237 | 8'd131: cx_rd_ptr_r = 6'd34; 238 | 8'd132: cx_rd_ptr_r = 6'd34; 239 | 8'd133: cx_rd_ptr_r = 6'd35; 240 | 8'd134: cx_rd_ptr_r = 6'd35; 241 | 8'd135: cx_rd_ptr_r = 6'd32; 242 | 8'd136: cx_rd_ptr_r = 6'd32; 243 | 8'd137: cx_rd_ptr_r = 6'd33; 244 | 8'd138: cx_rd_ptr_r = 6'd33; 245 | 8'd139: cx_rd_ptr_r = 6'd34; 246 | 8'd140: cx_rd_ptr_r = 6'd34; 247 | 8'd141: cx_rd_ptr_r = 6'd35; 248 | 8'd142: cx_rd_ptr_r = 6'd35; 249 | 8'd143: cx_rd_ptr_r = 6'd40; 250 | 8'd144: cx_rd_ptr_r = 6'd40; 251 | 8'd145: cx_rd_ptr_r = 6'd41; 252 | 8'd146: cx_rd_ptr_r = 6'd41; 253 | 8'd147: cx_rd_ptr_r = 6'd42; 254 | 8'd148: cx_rd_ptr_r = 6'd42; 255 | 8'd149: cx_rd_ptr_r = 6'd43; 256 | 8'd150: cx_rd_ptr_r = 6'd43; 257 | 8'd151: cx_rd_ptr_r = 6'd40; 258 | 8'd152: cx_rd_ptr_r = 6'd40; 259 | 8'd153: cx_rd_ptr_r = 6'd41; 260 | 8'd154: cx_rd_ptr_r = 6'd41; 261 | 8'd155: cx_rd_ptr_r = 6'd42; 262 | 8'd156: cx_rd_ptr_r = 6'd42; 263 | 8'd157: cx_rd_ptr_r = 6'd43; 264 | 8'd158: cx_rd_ptr_r = 6'd43; 265 | 8'd159: cx_rd_ptr_r = 6'd48; 266 | 8'd160: cx_rd_ptr_r = 6'd48; 267 | 8'd161: cx_rd_ptr_r = 6'd49; 268 | 8'd162: cx_rd_ptr_r = 6'd49; 269 | 8'd163: cx_rd_ptr_r = 6'd50; 270 | 8'd164: cx_rd_ptr_r = 6'd50; 271 | 8'd165: cx_rd_ptr_r = 6'd51; 272 | 8'd166: cx_rd_ptr_r = 6'd51; 273 | 8'd167: cx_rd_ptr_r = 6'd48; 274 | 8'd168: cx_rd_ptr_r = 6'd48; 275 | 8'd169: cx_rd_ptr_r = 6'd49; 276 | 8'd170: cx_rd_ptr_r = 6'd49; 277 | 8'd171: cx_rd_ptr_r = 6'd50; 278 | 8'd172: cx_rd_ptr_r = 6'd50; 279 | 8'd173: cx_rd_ptr_r = 6'd51; 280 | 8'd174: cx_rd_ptr_r = 6'd51; 281 | 8'd175: cx_rd_ptr_r = 6'd56; 282 | 8'd176: cx_rd_ptr_r = 6'd56; 283 | 8'd177: cx_rd_ptr_r = 6'd57; 284 | 8'd178: cx_rd_ptr_r = 6'd57; 285 | 8'd179: cx_rd_ptr_r = 6'd58; 286 | 8'd180: cx_rd_ptr_r = 6'd58; 287 | 8'd181: cx_rd_ptr_r = 6'd59; 288 | 8'd182: cx_rd_ptr_r = 6'd59; 289 | 8'd183: cx_rd_ptr_r = 6'd56; 290 | 8'd184: cx_rd_ptr_r = 6'd56; 291 | 8'd185: cx_rd_ptr_r = 6'd57; 292 | 8'd186: cx_rd_ptr_r = 6'd57; 293 | 8'd187: cx_rd_ptr_r = 6'd58; 294 | 8'd188: cx_rd_ptr_r = 6'd58; 295 | 8'd189: cx_rd_ptr_r = 6'd59; 296 | 8'd190: cx_rd_ptr_r = 6'd59; 297 | 8'd191: cx_rd_ptr_r = 6'd36; 298 | 8'd192: cx_rd_ptr_r = 6'd36; 299 | 8'd193: cx_rd_ptr_r = 6'd37; 300 | 8'd194: cx_rd_ptr_r = 6'd37; 301 | 8'd195: cx_rd_ptr_r = 6'd38; 302 | 8'd196: cx_rd_ptr_r = 6'd38; 303 | 8'd197: cx_rd_ptr_r = 6'd39; 304 | 8'd198: cx_rd_ptr_r = 6'd39; 305 | 8'd199: cx_rd_ptr_r = 6'd36; 306 | 8'd200: cx_rd_ptr_r = 6'd36; 307 | 8'd201: cx_rd_ptr_r = 6'd37; 308 | 8'd202: cx_rd_ptr_r = 6'd37; 309 | 8'd203: cx_rd_ptr_r = 6'd38; 310 | 8'd204: cx_rd_ptr_r = 6'd38; 311 | 8'd205: cx_rd_ptr_r = 6'd39; 312 | 8'd206: cx_rd_ptr_r = 6'd39; 313 | 8'd207: cx_rd_ptr_r = 6'd44; 314 | 8'd208: cx_rd_ptr_r = 6'd44; 315 | 8'd209: cx_rd_ptr_r = 6'd45; 316 | 8'd210: cx_rd_ptr_r = 6'd45; 317 | 8'd211: cx_rd_ptr_r = 6'd46; 318 | 8'd212: cx_rd_ptr_r = 6'd46; 319 | 8'd213: cx_rd_ptr_r = 6'd47; 320 | 8'd214: cx_rd_ptr_r = 6'd47; 321 | 8'd215: cx_rd_ptr_r = 6'd44; 322 | 8'd216: cx_rd_ptr_r = 6'd44; 323 | 8'd217: cx_rd_ptr_r = 6'd45; 324 | 8'd218: cx_rd_ptr_r = 6'd45; 325 | 8'd219: cx_rd_ptr_r = 6'd46; 326 | 8'd220: cx_rd_ptr_r = 6'd46; 327 | 8'd221: cx_rd_ptr_r = 6'd47; 328 | 8'd222: cx_rd_ptr_r = 6'd47; 329 | 8'd223: cx_rd_ptr_r = 6'd52; 330 | 8'd224: cx_rd_ptr_r = 6'd52; 331 | 8'd225: cx_rd_ptr_r = 6'd53; 332 | 8'd226: cx_rd_ptr_r = 6'd53; 333 | 8'd227: cx_rd_ptr_r = 6'd54; 334 | 8'd228: cx_rd_ptr_r = 6'd54; 335 | 8'd229: cx_rd_ptr_r = 6'd55; 336 | 8'd230: cx_rd_ptr_r = 6'd55; 337 | 8'd231: cx_rd_ptr_r = 6'd52; 338 | 8'd232: cx_rd_ptr_r = 6'd52; 339 | 8'd233: cx_rd_ptr_r = 6'd53; 340 | 8'd234: cx_rd_ptr_r = 6'd53; 341 | 8'd235: cx_rd_ptr_r = 6'd54; 342 | 8'd236: cx_rd_ptr_r = 6'd54; 343 | 8'd237: cx_rd_ptr_r = 6'd55; 344 | 8'd238: cx_rd_ptr_r = 6'd55; 345 | 8'd239: cx_rd_ptr_r = 6'd60; 346 | 8'd240: cx_rd_ptr_r = 6'd60; 347 | 8'd241: cx_rd_ptr_r = 6'd61; 348 | 8'd242: cx_rd_ptr_r = 6'd61; 349 | 8'd243: cx_rd_ptr_r = 6'd62; 350 | 8'd244: cx_rd_ptr_r = 6'd62; 351 | 8'd245: cx_rd_ptr_r = 6'd63; 352 | 8'd246: cx_rd_ptr_r = 6'd63; 353 | 8'd247: cx_rd_ptr_r = 6'd60; 354 | 8'd248: cx_rd_ptr_r = 6'd60; 355 | 8'd249: cx_rd_ptr_r = 6'd61; 356 | 8'd250: cx_rd_ptr_r = 6'd61; 357 | 8'd251: cx_rd_ptr_r = 6'd62; 358 | 8'd252: cx_rd_ptr_r = 6'd62; 359 | 8'd253: cx_rd_ptr_r = 6'd63; 360 | 8'd254: cx_rd_ptr_r = 6'd63; 361 | default: cx_rd_ptr_r = 6'd0; 362 | endcase 363 | end 364 | 365 | always @ (posedge clk_i ) 366 | if (rst_i) 367 | cx_idx_q <= 8'b0; 368 | else if (flush_i) 369 | cx_idx_q <= 8'b0; 370 | else if (read_ok_w && ((!valid_o) || (valid_o && pop_i))) 371 | cx_idx_q <= cx_idx_q + 8'd1; 372 | 373 | reg [1:0] cx_half_q; 374 | 375 | always @ (posedge clk_i ) 376 | if (rst_i) 377 | cx_half_q <= 2'b0; 378 | else if (flush_i) 379 | cx_half_q <= 2'b0; 380 | else if (read_ok_w && ((!valid_o) || (valid_o && pop_i)) && cx_idx_q == 8'd255) 381 | cx_half_q <= cx_half_q + 2'd1; 382 | 383 | reg [5:0] cx_rd_ptr_q; 384 | 385 | always @ (posedge clk_i ) 386 | if (rst_i) 387 | cx_rd_ptr_q <= 6'b0; 388 | else if (read_ok_w && ((!valid_o) || (valid_o && pop_i))) 389 | cx_rd_ptr_q <= cx_rd_ptr_r; 390 | 391 | wire [7:0] rd_addr_w = mode420_i ? {cx_half_q, cx_rd_ptr_q} : rd_ptr_q; 392 | 393 | //------------------------------------------------------------------- 394 | // Read Skid Buffer 395 | //------------------------------------------------------------------- 396 | reg rd_skid_q; 397 | reg [31:0] rd_skid_data_q; 398 | 399 | always @ (posedge clk_i ) 400 | if (rst_i) 401 | begin 402 | rd_skid_q <= 1'b0; 403 | rd_skid_data_q <= 32'b0; 404 | end 405 | else if (flush_i) 406 | begin 407 | rd_skid_q <= 1'b0; 408 | rd_skid_data_q <= 32'b0; 409 | end 410 | else if (valid_o && !pop_i) 411 | begin 412 | rd_skid_q <= 1'b1; 413 | rd_skid_data_q <= data_out_o; 414 | end 415 | else 416 | begin 417 | rd_skid_q <= 1'b0; 418 | rd_skid_data_q <= 32'b0; 419 | end 420 | 421 | //------------------------------------------------------------------- 422 | // Combinatorial 423 | //------------------------------------------------------------------- 424 | assign valid_o = rd_skid_q | rd_q; 425 | 426 | //------------------------------------------------------------------- 427 | // Dual port RAM 428 | //------------------------------------------------------------------- 429 | wire [31:0] data_out_w; 430 | 431 | jpeg_output_cx_ram_ram_dp_256_8 432 | u_ram 433 | ( 434 | // Inputs 435 | .clk0_i(clk_i), 436 | .rst0_i(rst_i), 437 | .clk1_i(clk_i), 438 | .rst1_i(rst_i), 439 | 440 | // Write side 441 | .addr0_i({wr_ptr_q[7:6], wr_idx_i}), 442 | .wr0_i(push_i), 443 | .data0_i(data_in_i), 444 | .data0_o(), 445 | 446 | // Read side 447 | .addr1_i(rd_addr_w), 448 | .data1_i(32'b0), 449 | .wr1_i(1'b0), 450 | .data1_o(data_out_w) 451 | ); 452 | 453 | assign data_out_o = rd_skid_q ? rd_skid_data_q : data_out_w; 454 | 455 | 456 | //------------------------------------------------------------------- 457 | // Level 458 | //------------------------------------------------------------------- 459 | reg [31:0] count_q; 460 | reg [31:0] count_r; 461 | 462 | always @ * 463 | begin 464 | count_r = count_q; 465 | 466 | if (pop_i && valid_o) 467 | count_r = count_r - 32'd1; 468 | 469 | if (push_i) 470 | count_r = count_r + (mode420_i ? 32'd4 : 32'd1); 471 | end 472 | 473 | always @ (posedge clk_i ) 474 | if (rst_i) 475 | count_q <= 32'b0; 476 | else if (flush_i) 477 | count_q <= 32'b0; 478 | else 479 | count_q <= count_r; 480 | 481 | assign level_o = count_q; 482 | 483 | endmodule 484 | 485 | //------------------------------------------------------------------- 486 | // Dual port RAM 487 | //------------------------------------------------------------------- 488 | module jpeg_output_cx_ram_ram_dp_256_8 489 | ( 490 | // Inputs 491 | input clk0_i 492 | ,input rst0_i 493 | ,input [ 7:0] addr0_i 494 | ,input [ 31:0] data0_i 495 | ,input wr0_i 496 | ,input clk1_i 497 | ,input rst1_i 498 | ,input [ 7:0] addr1_i 499 | ,input [ 31:0] data1_i 500 | ,input wr1_i 501 | 502 | // Outputs 503 | ,output [ 31:0] data0_o 504 | ,output [ 31:0] data1_o 505 | ); 506 | 507 | /* verilator lint_off MULTIDRIVEN */ 508 | reg [31:0] ram [255:0] /*verilator public*/; 509 | /* verilator lint_on MULTIDRIVEN */ 510 | 511 | reg [31:0] ram_read0_q; 512 | reg [31:0] ram_read1_q; 513 | 514 | // Synchronous write 515 | always @ (posedge clk0_i) 516 | begin 517 | if (wr0_i) 518 | ram[addr0_i] <= data0_i; 519 | 520 | ram_read0_q <= ram[addr0_i]; 521 | end 522 | 523 | always @ (posedge clk1_i) 524 | begin 525 | if (wr1_i) 526 | ram[addr1_i] <= data1_i; 527 | 528 | ram_read1_q <= ram[addr1_i]; 529 | end 530 | 531 | assign data0_o = ram_read0_q; 532 | assign data1_o = ram_read1_q; 533 | 534 | 535 | 536 | endmodule 537 | -------------------------------------------------------------------------------- /src_v/jpeg_output_fifo.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_output_fifo 33 | //----------------------------------------------------------------- 34 | // Params 35 | //----------------------------------------------------------------- 36 | #( 37 | parameter WIDTH = 8 38 | ,parameter DEPTH = 4 39 | ,parameter ADDR_W = 2 40 | ) 41 | //----------------------------------------------------------------- 42 | // Ports 43 | //----------------------------------------------------------------- 44 | ( 45 | // Inputs 46 | input clk_i 47 | ,input rst_i 48 | ,input [WIDTH-1:0] data_in_i 49 | ,input push_i 50 | ,input pop_i 51 | ,input flush_i 52 | 53 | // Outputs 54 | ,output [WIDTH-1:0] data_out_o 55 | ,output accept_o 56 | ,output valid_o 57 | ); 58 | 59 | 60 | 61 | //----------------------------------------------------------------- 62 | // Local Params 63 | //----------------------------------------------------------------- 64 | localparam COUNT_W = ADDR_W + 1; 65 | 66 | //----------------------------------------------------------------- 67 | // Registers 68 | //----------------------------------------------------------------- 69 | reg [WIDTH-1:0] ram_q[DEPTH-1:0]; 70 | reg [ADDR_W-1:0] rd_ptr_q; 71 | reg [ADDR_W-1:0] wr_ptr_q; 72 | reg [COUNT_W-1:0] count_q; 73 | 74 | //----------------------------------------------------------------- 75 | // Sequential 76 | //----------------------------------------------------------------- 77 | always @ (posedge clk_i or posedge rst_i) 78 | if (rst_i) 79 | begin 80 | count_q <= {(COUNT_W) {1'b0}}; 81 | rd_ptr_q <= {(ADDR_W) {1'b0}}; 82 | wr_ptr_q <= {(ADDR_W) {1'b0}}; 83 | end 84 | else if (flush_i) 85 | begin 86 | count_q <= {(COUNT_W) {1'b0}}; 87 | rd_ptr_q <= {(ADDR_W) {1'b0}}; 88 | wr_ptr_q <= {(ADDR_W) {1'b0}}; 89 | end 90 | else 91 | begin 92 | // Push 93 | if (push_i & accept_o) 94 | begin 95 | ram_q[wr_ptr_q] <= data_in_i; 96 | wr_ptr_q <= wr_ptr_q + 1; 97 | end 98 | 99 | // Pop 100 | if (pop_i & valid_o) 101 | rd_ptr_q <= rd_ptr_q + 1; 102 | 103 | // Count up 104 | if ((push_i & accept_o) & ~(pop_i & valid_o)) 105 | count_q <= count_q + 1; 106 | // Count down 107 | else if (~(push_i & accept_o) & (pop_i & valid_o)) 108 | count_q <= count_q - 1; 109 | end 110 | 111 | //------------------------------------------------------------------- 112 | // Combinatorial 113 | //------------------------------------------------------------------- 114 | /* verilator lint_off WIDTH */ 115 | assign valid_o = (count_q != 0); 116 | assign accept_o = (count_q != DEPTH); 117 | /* verilator lint_on WIDTH */ 118 | 119 | assign data_out_o = ram_q[rd_ptr_q]; 120 | 121 | 122 | 123 | endmodule 124 | -------------------------------------------------------------------------------- /src_v/jpeg_output_y_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // Baseline JPEG Decoder 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // admin@ultra-embedded.com 8 | //----------------------------------------------------------------- 9 | // License: Apache 2.0 10 | // This IP can be freely used in commercial projects, however you may 11 | // want access to unreleased materials such as verification environments, 12 | // or test vectors, as well as changes to the IP for integration purposes. 13 | // If this is the case, contact the above address. 14 | // I am interested to hear how and where this IP is used, so please get 15 | // in touch! 16 | //----------------------------------------------------------------- 17 | // Copyright 2020 Ultra-Embedded.com 18 | // 19 | // Licensed under the Apache License, Version 2.0 (the "License"); 20 | // you may not use this file except in compliance with the License. 21 | // You may obtain a copy of the License at 22 | // 23 | // http://www.apache.org/licenses/LICENSE-2.0 24 | // 25 | // Unless required by applicable law or agreed to in writing, software 26 | // distributed under the License is distributed on an "AS IS" BASIS, 27 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | // See the License for the specific language governing permissions and 29 | // limitations under the License. 30 | //----------------------------------------------------------------- 31 | 32 | module jpeg_output_y_ram 33 | ( 34 | // Inputs 35 | input clk_i 36 | ,input rst_i 37 | ,input [ 5:0] wr_idx_i 38 | ,input [ 31:0] data_in_i 39 | ,input push_i 40 | ,input pop_i 41 | ,input flush_i 42 | 43 | // Outputs 44 | ,output [ 31:0] data_out_o 45 | ,output valid_o 46 | ,output [ 31:0] level_o 47 | ); 48 | 49 | 50 | 51 | //----------------------------------------------------------------- 52 | // Registers 53 | //----------------------------------------------------------------- 54 | reg [8:0] rd_ptr_q; 55 | reg [8:0] wr_ptr_q; 56 | 57 | //----------------------------------------------------------------- 58 | // Write Side 59 | //----------------------------------------------------------------- 60 | wire [8:0] write_next_w = wr_ptr_q + 9'd1; 61 | 62 | always @ (posedge clk_i ) 63 | if (rst_i) 64 | wr_ptr_q <= 9'b0; 65 | else if (flush_i) 66 | wr_ptr_q <= 9'b0; 67 | // Push 68 | else if (push_i) 69 | wr_ptr_q <= write_next_w; 70 | 71 | //----------------------------------------------------------------- 72 | // Read Side 73 | //----------------------------------------------------------------- 74 | wire read_ok_w = (wr_ptr_q != rd_ptr_q); 75 | reg rd_q; 76 | 77 | always @ (posedge clk_i ) 78 | if (rst_i) 79 | rd_q <= 1'b0; 80 | else if (flush_i) 81 | rd_q <= 1'b0; 82 | else 83 | rd_q <= read_ok_w; 84 | 85 | wire [8:0] rd_ptr_next_w = rd_ptr_q + 9'd1; 86 | 87 | always @ (posedge clk_i ) 88 | if (rst_i) 89 | rd_ptr_q <= 9'b0; 90 | else if (flush_i) 91 | rd_ptr_q <= 9'b0; 92 | else if (read_ok_w && ((!valid_o) || (valid_o && pop_i))) 93 | rd_ptr_q <= rd_ptr_next_w; 94 | 95 | wire [8:0] rd_addr_w = rd_ptr_q; 96 | 97 | //------------------------------------------------------------------- 98 | // Read Skid Buffer 99 | //------------------------------------------------------------------- 100 | reg rd_skid_q; 101 | reg [31:0] rd_skid_data_q; 102 | 103 | always @ (posedge clk_i ) 104 | if (rst_i) 105 | begin 106 | rd_skid_q <= 1'b0; 107 | rd_skid_data_q <= 32'b0; 108 | end 109 | else if (flush_i) 110 | begin 111 | rd_skid_q <= 1'b0; 112 | rd_skid_data_q <= 32'b0; 113 | end 114 | else if (valid_o && !pop_i) 115 | begin 116 | rd_skid_q <= 1'b1; 117 | rd_skid_data_q <= data_out_o; 118 | end 119 | else 120 | begin 121 | rd_skid_q <= 1'b0; 122 | rd_skid_data_q <= 32'b0; 123 | end 124 | 125 | //------------------------------------------------------------------- 126 | // Combinatorial 127 | //------------------------------------------------------------------- 128 | assign valid_o = rd_skid_q | rd_q; 129 | 130 | //------------------------------------------------------------------- 131 | // Dual port RAM 132 | //------------------------------------------------------------------- 133 | wire [31:0] data_out_w; 134 | 135 | jpeg_output_y_ram_ram_dp_512_9 136 | u_ram 137 | ( 138 | // Inputs 139 | .clk0_i(clk_i), 140 | .rst0_i(rst_i), 141 | .clk1_i(clk_i), 142 | .rst1_i(rst_i), 143 | 144 | // Write side 145 | .addr0_i({wr_ptr_q[8:6], wr_idx_i}), 146 | .wr0_i(push_i), 147 | .data0_i(data_in_i), 148 | .data0_o(), 149 | 150 | // Read side 151 | .addr1_i(rd_addr_w), 152 | .data1_i(32'b0), 153 | .wr1_i(1'b0), 154 | .data1_o(data_out_w) 155 | ); 156 | 157 | assign data_out_o = rd_skid_q ? rd_skid_data_q : data_out_w; 158 | 159 | 160 | //------------------------------------------------------------------- 161 | // Level 162 | //------------------------------------------------------------------- 163 | reg [31:0] count_q; 164 | reg [31:0] count_r; 165 | 166 | always @ * 167 | begin 168 | count_r = count_q; 169 | 170 | if (pop_i && valid_o) 171 | count_r = count_r - 32'd1; 172 | 173 | if (push_i) 174 | count_r = count_r + 32'd1; 175 | end 176 | 177 | always @ (posedge clk_i ) 178 | if (rst_i) 179 | count_q <= 32'b0; 180 | else if (flush_i) 181 | count_q <= 32'b0; 182 | else 183 | count_q <= count_r; 184 | 185 | assign level_o = count_q; 186 | 187 | endmodule 188 | 189 | //------------------------------------------------------------------- 190 | // Dual port RAM 191 | //------------------------------------------------------------------- 192 | module jpeg_output_y_ram_ram_dp_512_9 193 | ( 194 | // Inputs 195 | input clk0_i 196 | ,input rst0_i 197 | ,input [ 8:0] addr0_i 198 | ,input [ 31:0] data0_i 199 | ,input wr0_i 200 | ,input clk1_i 201 | ,input rst1_i 202 | ,input [ 8:0] addr1_i 203 | ,input [ 31:0] data1_i 204 | ,input wr1_i 205 | 206 | // Outputs 207 | ,output [ 31:0] data0_o 208 | ,output [ 31:0] data1_o 209 | ); 210 | 211 | /* verilator lint_off MULTIDRIVEN */ 212 | reg [31:0] ram [511:0] /*verilator public*/; 213 | /* verilator lint_on MULTIDRIVEN */ 214 | 215 | reg [31:0] ram_read0_q; 216 | reg [31:0] ram_read1_q; 217 | 218 | // Synchronous write 219 | always @ (posedge clk0_i) 220 | begin 221 | if (wr0_i) 222 | ram[addr0_i] <= data0_i; 223 | 224 | ram_read0_q <= ram[addr0_i]; 225 | end 226 | 227 | always @ (posedge clk1_i) 228 | begin 229 | if (wr1_i) 230 | ram[addr1_i] <= data1_i; 231 | 232 | ram_read1_q <= ram[addr1_i]; 233 | end 234 | 235 | assign data0_o = ram_read0_q; 236 | assign data1_o = ram_read1_q; 237 | 238 | 239 | 240 | endmodule 241 | --------------------------------------------------------------------------------