/* ** -----------------------------------------------------------------------------** ** quantizator353.v ** ** Quantizer module for JPEG compressor ** ** Copyright (C) 2002-2015 Elphel, Inc ** ** -----------------------------------------------------------------------------** ** quantizer393.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 . ** -----------------------------------------------------------------------------** ** */ `include "system_defines.vh" `timescale 1ns/1ps // will add extracted DC (8 bits) to data from DCT here that will make data 12 bits (signed) long. // It will be possible to make a sequintial multiplier for DC - but I'll skip this now. module quantizer393( input clk, // pixel clock, posedge input en, // enable (0 resets counter) input mclk, // system clock to write tables input tser_qe, // enable write to a quantization table input tser_ce, // enable write to a coring table input tser_a_not_d, // address/not data distributed to submodules input [ 7:0] tser_d, // byte-wide serialized tables address/data to submodules input ctypei, // component type input (Y/C) input [ 8:0] dci, // [7:0] - average value in a block - subtracted before DCT. now normal signed number input first_stb, //this is first stb pulse in a frame input stb, // strobe that writes ctypei, dci input [ 2:0] tsi, // table (quality) select [2:0] input pre_start,// marks first input pixel (one before) input first_in, // first block in (valid @ start) output reg first_out, // valid @ ds input [12:0] di, // [11:0] pixel data in (signed) output reg [12:0] do, // [11:0] pixel data out (AC is only 9 bits long?) - changed to 10 output dv, // data out valid output ds, // data out strobe (one ahead of the start of dv) output reg [15:0] dc_tdo, //[15:0], MSB aligned coefficient for the DC component (used in focus module) input dcc_en, // enable dcc (sync to beginning of a new frame) input [ 2:0] hfc_sel, // hight frequency components select [2:0] (includes components with both numbers >=hfc_sel // hfc_sel == 3'h7 - now high frequency output - just 3 words - brightness and 2 color diffs input color_first, // first MCU in a frame input [ 2:0] coring_num, // coring table pair number (0..7) output reg dcc_vld, // single cycle when dcc_data is valid output [15:0] dcc_data, // [15:0] dc component data out (for reading by software) input [ 7:0] n000, // input [7:0] number of zero pixels (255 if 256) - to be multiplexed with dcc input [ 7:0] n255); // input [7:0] number of 0xff pixels (255 if 256) - to be multiplexed with dcc wire [3:0] tdco; // coring table output reg [3:0] tbac; // coring memory table number (LSB - color) reg coring_range; // input <16, use coring LUT wire [15:0] tdo; reg [ 9:0] tba; // table output (use) address wire [15:0] zigzag_q; reg wpage; reg rpage; wire [ 5:0] zwa; reg [ 5:0] zra; reg [12:0] qdo; reg [12:0] qdo0; reg zwe; reg [12:0] d1; reg [12:0] d2,d3; // registered data in, converted to sign+ absolute value wire [27:0] qmul; wire start_a; reg [15:0] tdor; reg [20:0] qmulr; // added 7 bits to total8 fractional for biasing/zero bin wire start_out; wire start_z; reg [ 8:0] dc1; // registered DC average - with restored sign // for fifo for ctype, dc wire ctype; wire [ 8:0] dc; // wire next_dv; // reg [ 2:0] last_dv; // last dv cycle (will turn of unless new ds) reg [ 2:0] ds_r; reg [ 3:0] ren; reg [ 5:0] start; wire dcc_stb; reg dcc_run; reg dcc_first; reg dcc_Y; reg [ 1:0] ctype_prev; reg [12:0] dcc_acc; reg [12:0] hfc_acc; wire hfc_en; reg hfc_copy; // copy hfc_acc to dcc_acc wire [10:0] d2_dct; // 11 bits enough, convetred to positive (before - 0 was in the middle - pixel value 128) - dcc only reg sel_satnum; // select saturation numbers - dcc only reg [15:0] pre_dc_tdo; wire copy_dc_tdo; reg first_interm; // valid @ ds wire [ 2:0] ts; wire [ 2:0] coring_sel; reg [ 2:0] block_mem_ra; reg [ 2:0] block_mem_wa; reg [ 2:0] block_mem_wa_save; reg [15:0] block_mem_ram[0:7]; wire [15:0] block_mem_o=block_mem_ram[block_mem_ra[2:0]]; assign dc[8:0] = block_mem_o[8:0]; assign ctype = block_mem_o[9]; assign ts[2:0] = block_mem_o[12:10]; assign coring_sel[2:0] = block_mem_o[15:13]; assign start_a = start[5]; assign start_z = start[4]; assign dcc_stb = start[2]; assign ds = ds_r[2]; assign dv = ren[3]; always @ (posedge clk) begin if (stb) block_mem_ram[block_mem_wa[2:0]] <= {coring_num[2:0],tsi[2:0], ctypei, dci[8: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_stb) block_mem_wa_save[2:0] <= block_mem_wa[2:0]; if (!en) block_mem_ra[2:0] <= 3'h0; else if (pre_start) block_mem_ra[2:0] <= first_in?block_mem_wa_save[2:0]:(block_mem_ra[2:0] +1); end assign d2_dct[10:0]={!d2[11] ^ ctype_prev[0], d2[9:0]}; assign dcc_data[15:0]=sel_satnum? {n255[7:0],n000[7:0]}: {dcc_first || (!dcc_Y && dcc_acc[12]) ,(!dcc_Y && dcc_acc[12]), (!dcc_Y && dcc_acc[12]), dcc_acc[12:0]}; // assign do[12:0]=zigzag_q[12:0]; assign qmul[27:0]=tdor[15:0]*d3[11:0]; assign start_out = zwe && (zwa[5:0]== 6'h3f); //adjust? assign copy_dc_tdo = zwe && (zwa[5:0]== 6'h37); // not critical // assign next_dv=en && (ds || (dv && (zra[5:0]!=6'h00))); always @ (posedge clk) begin d1[12:0] <= di[12:0]; //inv_sign dc1[8:0] <= start[0]?dc[8:0]:9'b0; // sync to d1[8:0]ctype valid at start, not later d2[12:0] <= {dc1[8],dc1[8:0],3'b0} + d1[12:0]; d3[12] <= d2[12]; d3[11:0] <= d2[12]? -d2[11:0]:d2[11:0]; if (start[0] || !en) tba[9:6] <= {ts[2:0],ctype}; /// TODO - make sure ctype switches at needed time (compensate if needed) ***************************************** if (start[3] || !en) tbac[3:0] <= {coring_sel[2:0],ctype}; // table number to use if (start[0]) tba[5:0] <= 6'b0; else if (tba[5:0]!=6'h3f) tba[5:0] <= tba[5:0]+1; tdor[15:0] <= tdo[15:0]; // registered table data out if (start[3]) pre_dc_tdo[15:0] <= tdor[15:0]; //16-bit q. tables) if (copy_dc_tdo) dc_tdo[15:0] <= pre_dc_tdo[15:0]; qmulr[19:0] <= qmul[27:8]; // absolute value qmulr[20] <= d3[12]; // sign qdo0[12] <= qmulr[20]; // sign // tdco[3:0] - same timing as qdo0; // use lookup table from 8 bits of absolute value (4.4 - 4 fractional) to calculate 4 bit coring output that would replace output // if input is less thahn 16. For larger values the true rounding will be used. // Absolute values here have quantization coefficients already applied, so we can use the same coring table for all DCT coefficients. // there are be 16 tables - 8 Y/C pairs to switch qdo0[11:0] <= qmulr[19:8] + qmulr[7]; // true rounding of the absolute value coring_range<= !(|qmulr[19:12]) && !(&qmulr[11:7]) ; // valid with qdo0 qdo[11:0] <= coring_range? (qdo0[12]?-{8'h0,tdco[3:0]}:{8'h0,tdco[3:0]}):(qdo0[12]?-qdo0[11:0]:qdo0[11:0]); qdo[12] <= qdo0[12] && (!coring_range || (tdco[3:0]!=4'h0)); if (start_out) rpage <= wpage; // last_dv <= {last_dv[1:0], en && (zra[5:0] == 6'h3f)}; if (start_out) zra[5:0] <= 6'b0; // else if (zra[5:0]!=6'h3f) zra[5:0] <= zra[5:0]+1; // conserving energy else if (ren[0]) zra[5:0] <= zra[5:0]+1; // conserving energy ds_r <= {ds_r[1:0], en && start_out}; if (!en) ren[0] <= 0; else if (start_out) ren[0] <= 1; else if ((zra[5:0] == 6'h3f)) ren[0] <= 0; if (!en) ren[3:1] <= 0; else ren[3:1] <= ren [2:0]; if (ren[2]) do[12:0] <= zigzag_q[12:0]; if (start_a) first_interm <= first_in; if (start_out) first_out <=first_interm; // zwe??? zwe <= en && (start_a || (zwe && (zwa[5:0]!=6'h3f))); if (!en) wpage <= 1'b0; else if (start_a) wpage <= ~wpage; end always @ (posedge clk) begin sel_satnum <= dcc_run && (start[0]? (ctype_prev[1:0]==2'b10): sel_satnum); hfc_copy <= dcc_run && (hfc_sel[2:0]!=3'h7) && (tba[5:0]==6'h1f) && ctype_prev[0] && ctype_prev[1]; start[5:0] <= {start[4:0], pre_start}; // needed? if (!dcc_en) dcc_run <= 1'b0; else if (start[0]) dcc_run <= 1'b1; if (!dcc_en) ctype_prev[1:0] <= 2'b11; else if (start[0]) ctype_prev[1:0] <= {ctype_prev[0],ctype && dcc_run}; if (dcc_stb || hfc_copy) dcc_acc[12:0] <= hfc_copy? hfc_acc[12:0]: {(d2_dct[10]&&ctype_prev[0]),(d2_dct[10]&&ctype_prev[0]),d2_dct[10:0]}+((ctype_prev[0] || ctype_prev[1])?13'h0:dcc_acc[12:0]); if (!dcc_run || hfc_copy) hfc_acc <=13'b0; else if (hfc_en) hfc_acc <= hfc_acc + {2'b0, d3[10:0]}; if (dcc_stb) dcc_first <= color_first && dcc_run && dcc_stb && ctype && !ctype_prev[0]; if (dcc_stb) dcc_Y <= dcc_run && dcc_stb && ctype && !ctype_prev[0]; dcc_vld <= (dcc_run && dcc_stb && (ctype || ctype_prev[0] || sel_satnum)) || hfc_copy; end wire twqe; wire twce; wire [15:0] tdi; wire [22:0] ta; table_ad_receive #( // here may be changed to 8-bit from 16-bit .MODE_16_BITS (1), .NUM_CHN (2) ) table_ad_receive_i ( .clk (mclk), // input .a_not_d (tser_a_not_d), // input .ser_d (tser_d), // input[7:0] .dv ({tser_ce,tser_qe}), // input[1:0] .ta (ta), // output[22:0] .td (tdi), // output[15:0] .twe ({twce,twqe}) // output[1:0] ); // SRL16 i_hfc_en (.Q(hfc_en), .A0(1'b1), .A1(1'b0), .A2(1'b0), .A3(1'b0), .CLK(clk), // .D(((tba[2:0]>hfc_sel[2:0]) || (tba[5:3]>hfc_sel[2:0])) && dcc_run && !ctype_prev[0])); // dly=1+1 dly_16 #(.WIDTH(1)) i_hfc_en ( .clk(clk), .rst(1'b0), .dly(4'd1), .din(((tba[2:0]>hfc_sel[2:0]) || (tba[5:3]>hfc_sel[2:0])) && dcc_run && !ctype_prev[0]), .dout(hfc_en)); // dly=1+1 zigzag393 i_zigzag( .clk(clk), .start(start_z), .q(zwa[5:0])); // All memories below are non-registered, see if they can be made registered ram18_var_w_var_r #( .REGISTERS (0), .LOG2WIDTH_WR (4), .LOG2WIDTH_RD (4), .DUMMY (0) `ifdef PRELOAD_BRAMS `include "includes/quantization_100.dat.vh" `endif ) i_quant_table ( .rclk (clk), // input .raddr ({tba[9:6],tba[2:0],tba[5:3]}), // input[8:0] .ren (1'b1), // input .regen (1'b1), // input .data_out (tdo[15:0]), // output[15:0] .wclk (mclk), // input .waddr (ta[9:0]), // input[8:0] .we (twqe), // input .web (4'hf), // input[3:0] .data_in (tdi[15:0]) // input[15:0] ); ram18_var_w_var_r #( .REGISTERS (0), .LOG2WIDTH_WR (4), .LOG2WIDTH_RD (2), .DUMMY (0) `ifdef PRELOAD_BRAMS `include "includes/coring.dat.vh" `endif ) i_coring_table ( .rclk (clk), // input .raddr ({tbac[3:0],qmulr[11:4]}), // input[10:0] .ren (1'b1), // input .regen (1'b1), // input .data_out (tdco[3:0]), // output[3:0] .wclk (mclk), // input .waddr (ta[9:0]), // input[9:0] .we (twce), // input .web (4'hf), // input[3:0] .data_in (tdi[15:0]) // input[15:0] ); ram18_var_w_var_r #( .REGISTERS (1), .LOG2WIDTH_WR (4), .LOG2WIDTH_RD (4), .DUMMY (0) ) i_zigzagbuf ( .rclk (clk), // input .raddr ({3'b0,rpage,zra[5:0]}), // input[9:0] .ren (ren[0]), // input .regen (ren[1]), // input .data_out (zigzag_q[15:0]), // output[15:0] .wclk (clk), // input .waddr ({3'b0,wpage,zwa[5:0]}), // input[9:0] .we (zwe), // input .web (4'hf), // input[3:0] .data_in ({3'b0,qdo[12:0]}) // input[15:0] ); endmodule module zigzag393 ( input clk, // system clock, posedge input start, output reg [5:0] q); reg [5:0] a; wire [ 4:0] rom_a; reg [ 5:0] rom_q; assign rom_a[4:0]=a[5]?(~a[4:0]):a[4:0]; always @ (posedge clk) begin if (start) a[5:0] <= 6'b0; else if (a[5:0]!=6'h3f) a[5:0] <= a[5:0]+1; end // ROM (combinatorial) always @(rom_a) case (rom_a) 5'h00: rom_q <= 6'h00; 5'h01: rom_q <= 6'h02; 5'h02: rom_q <= 6'h03; 5'h03: rom_q <= 6'h09; 5'h04: rom_q <= 6'h0a; 5'h05: rom_q <= 6'h14; 5'h06: rom_q <= 6'h15; 5'h07: rom_q <= 6'h23; 5'h08: rom_q <= 6'h01; 5'h09: rom_q <= 6'h04; 5'h0a: rom_q <= 6'h08; 5'h0b: rom_q <= 6'h0b; 5'h0c: rom_q <= 6'h13; 5'h0d: rom_q <= 6'h16; 5'h0e: rom_q <= 6'h22; 5'h0f: rom_q <= 6'h24; 5'h10: rom_q <= 6'h05; 5'h11: rom_q <= 6'h07; 5'h12: rom_q <= 6'h0c; 5'h13: rom_q <= 6'h12; 5'h14: rom_q <= 6'h17; 5'h15: rom_q <= 6'h21; 5'h16: rom_q <= 6'h25; 5'h17: rom_q <= 6'h30; 5'h18: rom_q <= 6'h06; 5'h19: rom_q <= 6'h0d; 5'h1a: rom_q <= 6'h11; 5'h1b: rom_q <= 6'h18; 5'h1c: rom_q <= 6'h20; 5'h1d: rom_q <= 6'h26; 5'h1e: rom_q <= 6'h2f; 5'h1f: rom_q <= 6'h31; endcase // add symmetrical part always @ (posedge clk) q[5:0] <= a[5]? (~rom_q[5:0]):rom_q[5:0]; endmodule