/* ** -----------------------------------------------------------------------------** ** encoderDCAC393.v ** ** RLL encoder for JPEG compressor ** ** Copyright (C) 2002-2015 Elphel, Inc ** ** -----------------------------------------------------------------------------** ** encoderDCAC393.v is free software - hardware description language (HDL) code. ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** -----------------------------------------------------------------------------** ** */ // Accepts 13-bits signed data (only 12-bit can be ecoded), so DC difference (to be encoded) is limited (saturated) to 12 bits, not the value itself // AC - always limited to 800 .. 7ff module encoderDCAC393( input clk, // pixel clock, posedge input en, // enable (0 resets) input lasti, // was "last MCU in a frame" (@ stb) input first_blocki, // first block in frame - save fifo write address (@ stb) input [ 2:0] comp_numberi, // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use (@ stb) input comp_firsti, // first this component in a frame (reset DC) (@ stb) input comp_colori, // use color - huffman? (@ stb) input comp_lastinmbi, // last component in a macroblock (@ stb) is it needed? input stb, // strobe that writes firsti, lasti, tni,average input [12:0] zdi, // [11:0] zigzag-reordered data input input first_blockz, // first block input (@zds) input zds, // strobe - one ahead of the DC component output output reg last, // output reg [15:0] do, output reg dv, // just for debug output comp_lastinmbo, output [2:0] dbg_block_mem_ra, output [2:0] dbg_block_mem_wa, output [2:0] dbg_block_mem_wa_save ); // 8x13 DC storage memory reg [12:0] dc_mem[7:0]; reg [12:0] dc_diff0, dc_diff; wire [11:0] dc_diff_limited= (dc_diff[12]==dc_diff[11])? dc_diff[11:0] : {~dc_diff[11],{11{dc_diff[11]}}}; // difference (to be encoded) limited to fit 12 bits reg [12:0] dc_restored; // corrected DC value of the current block, compensated to fit difference to 12 bits reg [ 5:0] rll_cntr; reg [5:0] cntr; reg [11:0] ac_in; wire izero=(ac_in[11:0]==12'b0); reg [14:0] val_r; // DC diff/AC values to be sent out, registered reg DCACen; // enable DC/AC (2 cycles ahead of do wire rll_out; wire pre_dv; reg was_nonzero_AC; reg [12:0] zdi_d; reg [3:0] zds_d; wire DC_tosend= zds_d[2]; wire pre_DCACen= zds_d[1]; wire [2:0] comp_numbero; // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use wire comp_firsto; // first this component in a frame (reset DC) wire comp_coloro; // use color - huffman? // wire comp_lastinmbo; // last component in a macroblock wire lasto; // last macroblock in a frame reg [2:0] block_mem_ra; reg [2:0] block_mem_wa; reg [2:0] block_mem_wa_save; reg [6:0] block_mem_ram[0:7]; wire [6:0] block_mem_o=block_mem_ram[block_mem_ra[2:0]]; assign comp_numbero[2:0]= block_mem_o[2:0]; assign comp_firsto= block_mem_o[3]; assign comp_coloro= block_mem_o[4]; assign comp_lastinmbo= block_mem_o[5]; assign lasto= block_mem_o[6]; assign dbg_block_mem_ra = block_mem_ra; assign dbg_block_mem_wa = block_mem_wa; assign dbg_block_mem_wa_save = block_mem_wa_save; always @ (posedge clk) begin if (stb) block_mem_ram[block_mem_wa[2:0]] <= {lasti, comp_lastinmbi, comp_colori,comp_firsti,comp_numberi[2:0]}; if (!en) block_mem_wa[2:0] <= 3'h0; else if (stb) block_mem_wa[2:0] <= block_mem_wa[2:0] +1; if (stb && first_blocki) block_mem_wa_save[2:0] <= block_mem_wa[2:0]; if (!en) block_mem_ra[2:0] <= 3'h0; else if (zds) block_mem_ra[2:0] <= first_blockz?block_mem_wa_save[2:0]:(block_mem_ra[2:0] +1); end assign rll_out= ((val_r[12] && !val_r[14]) || (ac_in[11:0]!=12'b0)) && (rll_cntr[5:0]!=6'b0); assign pre_dv=rll_out || val_r[14] || was_nonzero_AC; always @ (posedge clk) begin val_r[14:0] <={ DC_tosend? {en, comp_coloro, comp_lastinmbo && lasto, // last component's in a frame DC coefficient dc_diff_limited[11:0]}: {2'b0, (cntr[5:0]==6'h3f), ac_in[11:0]}}; was_nonzero_AC <= en && (ac_in[11:0]!=12'b0) && DCACen; if (pre_dv) do <= rll_out? {3'b0,val_r[12],6'b0,rll_cntr[5:0]}:{1'b1,val_r[14:0]}; dv <= pre_dv; DCACen <= en && (pre_DCACen || (DCACen && (cntr[5:0]!=6'h3f))); // adjust if (!DCACen) cntr[5:0] <=6'b0; else cntr[5:0] <=cntr[5:0]+1; end always @ (posedge clk) begin zdi_d[12:0] <= zdi[12:0]; ac_in[11:0] <= (zdi_d[12]==zdi_d[11])? zdi_d[11:0]:{~zdi_d[11],{11{zdi_d[11]}}}; // always // delay + saturation if (DC_tosend || !izero || !DCACen) rll_cntr[5:0] <= 6'h0; else if (DCACen) rll_cntr[5:0] <= rll_cntr[5:0] +1 ; if (DC_tosend) last <= lasto; end // DC components always @ (posedge clk) begin zds_d[3:0] <= {zds_d[2:0], zds}; if (zds_d[0]) dc_diff0[12:0] <= comp_firsto?13'b0:dc_mem[comp_numbero[2:0]]; if (zds_d[1]) dc_diff [12:0] <= zdi_d[12:0]-dc_diff0[12:0]; if (zds_d[2]) dc_restored[12:0] <= dc_diff0[12:0] + {dc_diff_limited[11],dc_diff_limited[11:0]}; if (zds_d[3]) dc_mem[comp_numbero[2:0]] <= dc_restored[12:0]; end // Generate output stream to facilitate huffman encoding. The data will go to FIFO (16x) to compensate for possible long Huffman codes // and/or zero-byte insertions // format: // {2'b11, color,last block, dc[11:0]} - DC data // {2'b10, 1'b0, last coeff, ac[11:0]} - AC data (last coeff is set if it is last- 63-rd AC coefficient) // {2'h00, 2'b00, 6'b0,rll[ 5:0]} - RLL zeroes. // {2'h00, 2'b01, 6'b0,rll[ 5:0]} - end of block. lower 6 bits will have length that should be ignored endmodule