/*******************************************************************************
 * Module: jp_channel
 * Date:2015-06-10  
 * Author: Andrey Filippov     
 * Description: Top module of JPEG/JP4 compressor channel
 *
 * Copyright (c) 2015 Elphel, Inc.
 * jp_channel.v 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.
 *
 *  jp_channel.v 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 <http://www.gnu.org/licenses/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  jp_channel#(
        parameter CMPRS_NUMBER =             0,
        parameter CMPRS_GROUP_ADDR =         'h600,
        parameter CMPRS_BASE_INC =           'h10,
        parameter CMPRS_STATUS_REG_BASE=     'h10,
        parameter CMPRS_HIFREQ_REG_BASE=     'h14, 
        parameter CMPRS_STATUS_REG_INC=       1,
        parameter CMPRS_HIFREQ_REG_INC=       1,
        parameter CMPRS_MASK=                'h7f8,
        parameter CMPRS_CONTROL_REG=          0,
        parameter CMPRS_STATUS_CNTRL=         1,
        parameter CMPRS_FORMAT=               2,
        parameter CMPRS_COLOR_SATURATION=     3,
        parameter CMPRS_CORING_MODE=          4,
        parameter CMPRS_TABLES=               6, // 6(data)..7(address)

        parameter FRAME_HEIGHT_BITS=          16, // Maximal frame height 
        parameter LAST_FRAME_BITS=            16, // number of bits in frame counter (before rolls over)
        // Bit-fields in compressor control word
        parameter CMPRS_CBIT_RUN =            2, // bit # to control compressor run modes
        parameter CMPRS_CBIT_RUN_BITS =       2, // number of bits to control compressor run modes
        parameter CMPRS_CBIT_QBANK =          6, // bit # to control quantization table page
        parameter CMPRS_CBIT_QBANK_BITS =     3, // number of bits to control quantization table page
        parameter CMPRS_CBIT_DCSUB =          8, // bit # to control extracting DC components bypassing DCT
        parameter CMPRS_CBIT_DCSUB_BITS =     1, // bit # to control extracting DC components bypassing DCT
        parameter CMPRS_CBIT_CMODE =         13, // bit # to control compressor color modes
        parameter CMPRS_CBIT_CMODE_BITS =     4, // number of bits to control compressor color modes
        parameter CMPRS_CBIT_FRAMES =        15, // bit # to control compressor multi/single frame buffer modes
        parameter CMPRS_CBIT_FRAMES_BITS =    1, // number of bits to control compressor multi/single frame buffer modes
        parameter CMPRS_CBIT_BAYER =         20, // bit # to control compressor Bayer shift mode
        parameter CMPRS_CBIT_BAYER_BITS =     2, // number of bits to control compressor Bayer shift mode
        parameter CMPRS_CBIT_FOCUS =         23, // bit # to control compressor focus display mode
        parameter CMPRS_CBIT_FOCUS_BITS =     2, // number of bits to control compressor focus display mode
        // compressor bit-fields decode
        parameter CMPRS_CBIT_RUN_RST =        2'h0, // reset compressor, stop immediately
//      parameter CMPRS_CBIT_RUN_DISABLE =    2'h1, // disable compression of the new frames, finish any already started
        parameter CMPRS_CBIT_RUN_STANDALONE = 2'h2, // enable compressor, compress single frame from memory (async)
        parameter CMPRS_CBIT_RUN_ENABLE =     2'h3, // enable compressor, enable synchronous compression mode
        parameter CMPRS_CBIT_CMODE_JPEG18 =   4'h0, // color 4:2:0
        parameter CMPRS_CBIT_CMODE_MONO6 =    4'h1, // mono 4:2:0 (6 blocks)
        parameter CMPRS_CBIT_CMODE_JP46 =     4'h2, // jp4, 6 blocks, original
        parameter CMPRS_CBIT_CMODE_JP46DC =   4'h3, // jp4, 6 blocks, dc -improved
        parameter CMPRS_CBIT_CMODE_JPEG20 =   4'h4, // mono, 4 blocks (but still not actual monochrome JPEG as the blocks are scanned in 2x2 macroblocks)
        parameter CMPRS_CBIT_CMODE_JP4 =      4'h5, // jp4,  4 blocks, dc-improved
        parameter CMPRS_CBIT_CMODE_JP4DC =    4'h6, // jp4,  4 blocks, dc-improved
        parameter CMPRS_CBIT_CMODE_JP4DIFF =  4'h7, // jp4,  4 blocks, differential
        parameter CMPRS_CBIT_CMODE_JP4DIFFHDR =  4'h8, // jp4,  4 blocks, differential, hdr
        parameter CMPRS_CBIT_CMODE_JP4DIFFDIV2 = 4'h9, // jp4,  4 blocks, differential, divide by 2
        parameter CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 = 4'ha, // jp4,  4 blocks, differential, hdr,divide by 2
        parameter CMPRS_CBIT_CMODE_MONO1 =    4'hb, // mono JPEG (not yet implemented)
        parameter CMPRS_CBIT_CMODE_MONO4 =    4'he, // mono 4 blocks
        parameter CMPRS_CBIT_FRAMES_SINGLE =  0, //1, // use a single-frame buffer for images

        parameter CMPRS_COLOR18 =           0, // JPEG 4:2:0 with 18x18 overlapping tiles for de-bayer
        parameter CMPRS_COLOR20 =           1, // JPEG 4:2:0 with 18x18 overlapping tiles for de-bayer (not implemented)
        parameter CMPRS_MONO16 =            2, // JPEG 4:2:0 with 16x16 non-overlapping tiles, color components zeroed
        parameter CMPRS_JP4 =               3, // JP4 mode with 16x16 macroblocks
        parameter CMPRS_JP4DIFF =           4, // JP4DIFF mode TODO: see if correct
        parameter CMPRS_MONO8 =             7,  // Regular JPEG monochrome with 8x8 macroblocks (not yet implemented)
        
        parameter CMPRS_FRMT_MBCM1 =           0, // bit # of number of macroblock columns minus 1 field in format word
        parameter CMPRS_FRMT_MBCM1_BITS =     13, // number of bits in number of macroblock columns minus 1 field in format word
        parameter CMPRS_FRMT_MBRM1 =          13, // bit # of number of macroblock rows minus 1 field in format word
        parameter CMPRS_FRMT_MBRM1_BITS =     13, // number of bits in number of macroblock rows minus 1 field in format word
        parameter CMPRS_FRMT_LMARG =          26, // bit # of left margin field in format word
        parameter CMPRS_FRMT_LMARG_BITS =      5, // number of bits in left margin field in format word
        parameter CMPRS_CSAT_CB =              0, // bit # of number of blue scale field in color saturation word
        parameter CMPRS_CSAT_CB_BITS =        10, // number of bits in blue scale field in color saturation word
        parameter CMPRS_CSAT_CR =             12, // bit # of number of red scale field in color saturation word
        parameter CMPRS_CSAT_CR_BITS =        10, // number of bits in red scale field in color saturation word
        parameter CMPRS_CORING_BITS =          3,  // number of bits in coring mode
        
        parameter CMPRS_TIMEOUT_BITS=              12,
        parameter CMPRS_TIMEOUT=                   1000   // mclk cycles
`ifdef DEBUG_RING
        ,parameter DEBUG_CMD_LATENCY = 2 //SuppressThisWarning VEditor - not used
`endif        
        
)(
//    input                         rst,    // global reset
    input                         xclk,   // global clock input, compressor single clock rate
    input                         xclk2x, // global clock input, compressor double clock rate, nominally rising edge aligned
    input                         mrst,      // @posedge mclk, sync reset
    input                         xrst,      // @posedge xclk, sync reset
    input                         hrst,      // @posedge xclk, sync reset
    
    // programming interface
    input                         mclk,     // global system/memory clock
    input                   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input                         cmd_stb,     // strobe (with first byte) for the command a/d
    output                  [7:0] status_ad,   // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
    output                        status_rq,   // input request to send status downstream
    input                         status_start, // Acknowledge of the first status packet byte (address)
    
    // Buffer interface (buffer to be a part of the memory controller - it is connected there by a 64-bit data, here - by an 9-bit one
    input                         xfer_reset_page_rd, // from mcntrl_tiled_rw (

    input                         buf_wpage_nxt, // advance to next page memory interface writes to
    input                         buf_we,       // @!mclk write buffer from memory, increment write
    input                  [63:0] buf_din,      // data out 

//    output                 [11:0] buf_ra,
//    output                        buf_ren,
//    output                        buf_regen,
//    input                  [ 7:0] buf_di, 
    
    input                         page_ready_chn,     // single mclk (posedge)
    output                        next_page_chn,      // single mclk (posedge): Done with the page in the  buffer, memory controller may read more data 
// Master(sensor)/slave(compressor) synchronization signals
    output                        frame_start_dst,    // @mclk - trigger receive (tiledc) memory channel (it will take care of single/repetitive
                                                      // these output either follows vsync_late (reclocks it) or generated in non-bonded mode
                                                      // (compress from memory)
    input [FRAME_HEIGHT_BITS-1:0] line_unfinished_src,// number of the current (unfinished ) line, in the source (sensor) channel (RELATIVE TO FRAME, NOT WINDOW?)
    input   [LAST_FRAME_BITS-1:0] frame_number_src,   // current frame number (for multi-frame ranges) in the source (sensor) channel
    input                         frame_done_src,     // single-cycle pulse when the full frame (window) was transferred to/from DDR3 memory 
                                                      // frame_done_src is later than line_unfinished_src/ frame_number_src changes
                                                      // Used withe a single-frame buffers
     
    input [FRAME_HEIGHT_BITS-1:0] line_unfinished_dst,// number of the current (unfinished ) line in this (compressor) channel
    input   [LAST_FRAME_BITS-1:0] frame_number_dst,   // current frame number (for multi-frame ranges) in this (compressor channel
    input                         frame_done_dst,     // single-cycle pulse when the full frame (window) was transferred to/from DDR3 memory
                                                      // use as 'eot_real' in 353 
    output                        suspend,            // suspend reading data for this channel - waiting for the source data

// statistics data was not used in late nc353    
    input                         dccout,         //enable output of DC and HF components for brightness/color/focus adjustments
    input                   [2:0] hfc_sel,        // [2:0] (for autofocus) only components with both spacial frequencies higher than specified will be added
    output                        statistics_dv,
    output                 [15:0] statistics_do,

// Timestamp messages (@mclk)    
    input                         ts_pre_stb,  // @mclk - 1 cycle before receiving 8 bytes of timestamp data
    input                   [7:0] ts_data,     // timestamp data (s0,s1,s2,s3,us0,us1,us2,us3==0)
    
    output                        eof_written_mclk,
    output                        stuffer_done_mclk,
    
//    output                 [31:0] hifreq,             //  accumulated high frequency components in a frame sub-window
    input                         vsync_late,         // delayed start of frame, @mclk. In 353 it was 16 lines after VACT active
                                                      // source channel should already start, some delay give time for sequencer commands
                                                      // that should arrive before it
    
    // Output interface to the AFI mux
    input                         hclk,
    input                         fifo_rst,      // reset FIFO (set read address to write, reset count)
    input                         fifo_ren,
    output                 [63:0] fifo_rdata,
    output                        fifo_eof,      // single rclk pulse signalling EOF
    input                         eof_written,   // confirm frame written ofer AFI to the system memory (single rclk pulse)
    output                        fifo_flush,    // EOF, need to output all what is in FIFO (Stays active until enough data chunks are read)
    output                        flush_hclk,    // output before writing last chunk - use it to suspend AFI to have
                                                 // last burst marked as the last one (otherwise last may be empty if frame had %4==0 chunks) 
    output                 [7:0]  fifo_count     // number of 32-byte chunks in FIFO
`ifdef DEBUG_RING       
    ,output                       debug_do, // output to the debug ring
     input                        debug_sl, // 0 - idle, (1,0) - shift, (1,1) - load // SuppressThisWarning VEditor - not used
     input                        debug_di  // input from the debug ring
`endif         
);
//`ifdef DEBUG_RING
//     assign  debug_do = debug_di; // just temporarily to short-circuit the ring
//`endif        

    localparam CMPRS_ADDR = CMPRS_GROUP_ADDR + CMPRS_NUMBER * CMPRS_BASE_INC;
    localparam CMPRS_STATUS_REG_ADDR = CMPRS_STATUS_REG_BASE + CMPRS_NUMBER *  CMPRS_STATUS_REG_INC;
    localparam CMPRS_HIFREQ_REG_ADDR = CMPRS_HIFREQ_REG_BASE + CMPRS_NUMBER *  CMPRS_HIFREQ_REG_INC;
    wire                      [31:0] hifreq;   //  accumulated high frequency components in a frame sub-window was output, now - with status
    
    // Control signals to be defined
    wire                             frame_en;           // if 0 - will reset logic immediately (but not page number)
    wire                             frame_start_xclk;   // re-clocked, parameters are copied at this pulse
    wire                             stuffer_en;         //  extended enable to allow stuffer to gracefully finish 
    
    wire                             frame_go=frame_en;  // start frame: if idle, will start reading data (if available),
                                      // if running - will not restart a new frame if 0.
    wire [CMPRS_FRMT_LMARG_BITS-1:0] left_marg;          // left margin (for not-yet-implemented) mono JPEG (8 lines tile row) can need 7 bits (mod 32 - tile)
    wire [CMPRS_FRMT_MBCM1_BITS-1:0] n_blocks_in_row_m1; // number of macroblocks in a macroblock row minus 1
    wire [CMPRS_FRMT_MBRM1_BITS-1:0] n_block_rows_m1;    // number of macroblock rows in a frame minus 1
    wire                             ignore_color;       // zero Cb/Cr components (TODO: maybe include into converter_type?)
    wire                      [ 1:0] bayer_phase;        // [1:0])  bayer color filter phase 0:(GR/BG), 1:(RG/GB), 2: (BG/GR), 3: (GB/RG)
//    wire                             four_blocks;        // use only 6 blocks for the output, not 6
    wire                             jp4_dc_improved;    // in JP4 mode, compare DC coefficients to the same color ones
//    wire   [ 1:0] tile_margin;        // margins around 16x16 tiles (0/1/2)
//    wire   [ 2:0] tile_shift;         // tile shift from top left corner
    wire                      [ 2:0] converter_type;     // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff, 7 - mono8 (not yet implemented)
    wire                             scale_diff;         // divide differences by 2 (to fit in 8-bit range)
    wire                             hdr;                // second green absolute, not difference
    wire                             subtract_dc;        // subtract/restore DC components
    wire    [CMPRS_CSAT_CB_BITS-1:0] m_cb;               // [9:0] scale for CB - default 0.564 (10'h90)
    wire    [CMPRS_CSAT_CR_BITS-1:0] m_cr;               // [9:0] scale for CR - default 0.713 (10'hb6)

    wire   [ 1:0] cmprs_fmode;        // focusing/overlay mode

    //TODO: assign next 5 values from converter_type[2:0]
    wire   [ 5:0] mb_w_m1;            // macroblock width minus 1
    wire   [ 5:0] mb_h_m1;            // macroblock height -1
    wire   [ 4:0] mb_hper;            // macroblock horizontal period (8/16) // 3 LSB not used
    wire   [ 1:0] tile_width;         // memory tile width (can be 128 for monochrome JPEG)   Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
    wire          tile_col_width;     // 0 - 16 pixels,  1 -32 pixels
    
    
    // signals connecting modules: cmprs_macroblock_buf_iface_i and cmprs_pixel_buf_iface_i:
    wire          mb_pre_end;         // from cmprs_pixel_buf_iface - just in time to start a new macroblock w/o gaps
    wire          mb_release_buf;     // send required "next_page" pulses to buffer. Having rather long minimal latency in the memory
                                      // controller this can just be the same as mb_pre_end_in        
    wire          mb_pre_start;       // 1 clock cycle before stream of addresses to the buffer
    wire   [ 1:0] start_page;         // page to read next tile from (or first of several pages)
    wire   [ 6:0] macroblock_x;       // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
    
    // signals connecting modules: cmprs_macroblock_buf_iface_i and cmprs_buf_average:
    
     wire         first_mb;           // output reg 
     wire         last_mb;            // output
    
    // signals connecting modules: cmprs_pixel_buf_iface_i and chn_rd_buf_i:
//    wire   [ 7:0] buf_di;             // data from the buffer
//    wire   [11:0] buf_ra;             // buffer read address (2 MSB - page number)
    wire   [ 1:0] buf_rd;             // buf {regen, re}
    wire   [ 7:0] buf_pxd;            // 8-bit pixel data from the memory buffer
    wire   [11:0] buf_ra;             // Memory buffer read address
    // signals connecting modules: chn_rd_buf_i and ???:
    wire   [ 7:0] mb_data_out;       // Macroblock data out in scanline order 
    wire          mb_pre_first_out;  // Macroblock data out strobe - 1 cycle just before data valid
//    wire          mb_data_valid;     // Macroblock data out valid
    
    wire           limit_diff     = 1'b1;  // as in the prototype - just a constant 1
    
    // signals connecting modules: csconvert and cmprs_buf_average:
    
 
    wire   [8:0]  signed_y; // was y_in
    wire   [8:0]  signed_c; // was c_in
    wire   [7:0]  yaddrw; 
    wire          ywe; 
    wire   [7:0]  caddrw; 
    wire          cwe; 
    wire          yc_pre_first_out; // pre first output from color converter (was  pre_first_out) - last cycle of writing (may inc wpage
    // How they are used? Can it be average instead?  
    wire   [7:0]  n000;  // number of all 0 in macroblock (255 for 256), valid only for color JPEG 
    wire   [7:0]  n255;  // number of all 255 in macroblock (255 for 256), valid only for color JPEG 
    
    // signals connecting modules: cmprs_buf_average and ???:

    wire   [ 9:0] yc_nodc;         // [9:0] data out (4:2:0) (signed, average=0)
    wire   [ 8:0] yc_avr;          // [8:0]    DC (average value) - RAM output, no register. For Y components 9'h080..9'h07f, for C - 9'h100..9'h0ff!
//    wire          yc_nodc_dv;         // out data valid (will go high for at least 64 cycles)
    wire          dct_start;         // single-cycle mark of the first_r pixel in a 64 (8x8) - pixel block
    wire   [ 2:0] color_tn;   // [2:0] tile number 0..3 - Y, 4 - Cb, 5 - Cr (valid with start)
    wire          color_first;      // sending first_r MCU (valid @ ds)
    wire          color_last;       // sending last_r MCU (valid @ ds)
// below signals valid at ds ( 1 later than tn, first_r, last_r)
    wire    [2:0] component_num;    //[2:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift) 4 - don't use
    wire          component_color;  // use color quantization table (YCbCR, jp4diff)
    wire          component_first;  // first this component in a frame (DC absolute, otherwise - difference to previous)
    
    wire          component_lastinmb; // last_r component in a macroblock;


// control signals valid @ mclk
    wire          cmprs_en_extend;  // extend cmprs_en_xclk to include flushing
    wire          cmprs_en_mclk;    // resets immediately
    wire          cmprs_run_mclk;   // enable propagation of vsync_late to frame_start_dst in bonded(sync to src) mode
    wire          cmprs_standalone; // single-cycle: generate a single frame_start_dst in unbonded (not synchronized) mode. cmprs_run should be off
    wire          sigle_frame_buf;  // input - memory controller uses a single frame buffer (frame_number_* == 0), use other sync



    wire          force_flush_long; 
///    wire          enc_last; not used
    wire   [15:0] enc_do; 
    wire          enc_dv;

//TODO: use next signals for status
//    wire          eof_written_mclk;
//    wire          stuffer_done_mclk;
    wire          stuffer_running_mclk;
    wire          reading_frame;
    
///    wire          last_block; //huffman393
///    wire          test_lbw; 


    wire          stuffer_rdy; // receiver (bit stuffer) is ready to accept data;
    wire   [15:0] huff_do;     // output[15:0] reg 
    wire    [3:0] huff_dl;     // output[3:0] reg 
    wire          huff_dv;     // output reg 
    wire          flush;       // output reg @ negedge xclk2x
    


    wire   [31:0] cmd_data;       // 32-bit data to write to tables and registers(LSB first) - from cmd_deser
    wire          cmd_we;         // control register write enable
    wire   [2:0]  cmd_a;          // control register write enable
    
    wire          set_ctrl_reg_w;
    wire          set_status_w;
    wire          set_format_w;
    wire          set_color_saturation_w;
    wire          set_coring_w;
    wire          set_tables_w;
    
    wire          stuffer_running;   // @negedge xclk2x from registering timestamp until done
    
    wire   [12:0] quant_do; 
    wire          quant_ds;
    wire   [15:0] quant_dc_tdo;// MSB aligned coefficient for the DC component (used in focus module)
    wire   [ 2:0] cmprs_qpage;
    wire   [ 2:0] coring_num;
    reg           dcc_en;

    wire   [15:0] dccdata; // was not used in late nc353
    wire          dccvld;  // was not used in late nc353
    
    assign set_ctrl_reg_w =          cmd_we && (cmd_a==       CMPRS_CONTROL_REG);
    assign set_status_w =            cmd_we && (cmd_a==       CMPRS_STATUS_CNTRL);
    assign set_format_w =            cmd_we && (cmd_a==       CMPRS_FORMAT);
    assign set_color_saturation_w =  cmd_we && (cmd_a==       CMPRS_COLOR_SATURATION);
    assign set_coring_w =            cmd_we && (cmd_a==       CMPRS_CORING_MODE);
    assign set_tables_w =            cmd_we && ((cmd_a & 6)== CMPRS_TABLES);
    
//    assign buf_ren =   buf_rd[0];
//    assign buf_regen = buf_rd[1];

`ifdef DEBUG_RING
    reg [15:0] debug_fifo_in;
    reg [15:0] debug_fifo_out;
    always @ (posedge ~xclk2x) begin
        if      (xrst2xn)    debug_fifo_in <= 0;
        else if (stuffer_dv) debug_fifo_in <= debug_fifo_in + 1;
    end
    always @ (posedge hclk) begin
        if      (hrst)     debug_fifo_out <= 0;
        else if (fifo_rst) debug_fifo_out <= debug_fifo_in;
        else if (fifo_ren) debug_fifo_out <= debug_fifo_out + 1;
    end

    debug_slave #(
        .SHIFT_WIDTH       (128),
        .READ_WIDTH        (128),
        .WRITE_WIDTH       (32),
        .DEBUG_CMD_LATENCY (DEBUG_CMD_LATENCY)
    ) debug_slave_i (
        .mclk       (mclk),          // input
        .mrst       (mrst),          // input
        .debug_di   (debug_di), // input
        .debug_sl   (debug_sl),      // input
        .debug_do   (debug_do), // output
        .rd_data   ({
        debug_fifo_out[15:0],
        debug_fifo_in[15:0],
        16'b0,
        fifo_count[7:0],
        6'b0, sigle_frame_buf, suspend,
        frame_number_dst[15:0],
        line_unfinished_dst[15:0],
        frame_number_src[15:0],
        line_unfinished_src[15:0]
        }), // input[31:0]
        .wr_data    (), // output[31:0]  - not used
        .stb        () // output  - not used
    );
`endif    

    cmd_deser #(
        .ADDR       (CMPRS_ADDR),
        .ADDR_MASK  (CMPRS_MASK),
        .NUM_CYCLES (6),
        .ADDR_WIDTH (3),
        .DATA_WIDTH (32)
    ) cmd_deser_32bit_i (
        .rst        (1'b0), //rst),      // input
        .clk        (mclk),     // input
        .srst       (mrst),      // input
        .ad         (cmd_ad),   // input[7:0] 
        .stb        (cmd_stb),  // input
        .addr       (cmd_a),    // output[3:0] 
        .data       (cmd_data), // output[31:0] 
        .we         (cmd_we)    // output
    );
    wire [2:0] status_data; 
    cmprs_status cmprs_status_i (
        .mclk            (mclk),                 // input
        .eof_written     (eof_written_mclk),     // input
        .stuffer_running (stuffer_running_mclk), // input
        .reading_frame   (reading_frame),        // input
        .status          (status_data)           // output[2:0] 
    );

    status_generate #(
        .STATUS_REG_ADDR  (CMPRS_STATUS_REG_ADDR),
        .PAYLOAD_BITS     (3),
        .EXTRA_WORDS      (1),
        .EXTRA_REG_ADDR   (CMPRS_HIFREQ_REG_ADDR)
        
    ) status_generate_i (
        .rst              (1'b0),                 //rst),      // input
        .clk              (mclk),                 // input
        .srst             (mrst),                 // input
        .we               (set_status_w),         // input
        .wd               (cmd_data[7:0]),        // input[7:0] 
        .status           ({hifreq,status_data}), // input[2:0] 
        .ad               (status_ad),            // output[7:0] 
        .rq               (status_rq),            // output
        .start            (status_start)          // input
    );
//hifreq
// Port buffer - TODO: Move to memory controller
    mcntrl_buf_rd #(
        .LOG2WIDTH_RD(3) // 64 bit external interface
    ) chn_rd_buf_i (
        .ext_clk      (xclk), // input
        .ext_raddr    (buf_ra), // input[11:0] 
        .ext_rd       (buf_rd[0]), // input
        .ext_regen    (buf_rd[1]), // input
        .ext_data_out (buf_pxd), // output[7:0] 
        .wclk         (!mclk), // input
        .wpage_in     (2'b0), // input[1:0] 
        .wpage_set    (xfer_reset_page_rd), // input  TODO: Generate @ negedge mclk on frame start
        .page_next    (buf_wpage_nxt), // input
        .page         (), // output[1:0]
        .we           (buf_we), // input
        .data_in      (buf_din) // input[63:0] 
    );
    
    cmprs_cmd_decode #(
        .CMPRS_CBIT_RUN                  (CMPRS_CBIT_RUN),
        .CMPRS_CBIT_RUN_BITS             (CMPRS_CBIT_RUN_BITS),
        .CMPRS_CBIT_QBANK                (CMPRS_CBIT_QBANK),
        .CMPRS_CBIT_QBANK_BITS           (CMPRS_CBIT_QBANK_BITS),
        .CMPRS_CBIT_DCSUB                (CMPRS_CBIT_DCSUB),
        .CMPRS_CBIT_DCSUB_BITS           (CMPRS_CBIT_DCSUB_BITS),
        .CMPRS_CBIT_CMODE                (CMPRS_CBIT_CMODE),
        .CMPRS_CBIT_CMODE_BITS           (CMPRS_CBIT_CMODE_BITS),
        .CMPRS_CBIT_FRAMES               (CMPRS_CBIT_FRAMES),
        .CMPRS_CBIT_FRAMES_BITS          (CMPRS_CBIT_FRAMES_BITS),
        .CMPRS_CBIT_BAYER                (CMPRS_CBIT_BAYER),
        .CMPRS_CBIT_BAYER_BITS           (CMPRS_CBIT_BAYER_BITS),
        .CMPRS_CBIT_FOCUS                (CMPRS_CBIT_FOCUS),
        .CMPRS_CBIT_FOCUS_BITS           (CMPRS_CBIT_FOCUS_BITS),
        .CMPRS_CBIT_RUN_RST              (CMPRS_CBIT_RUN_RST),
        .CMPRS_CBIT_RUN_STANDALONE       (CMPRS_CBIT_RUN_STANDALONE),
        .CMPRS_CBIT_RUN_ENABLE           (CMPRS_CBIT_RUN_ENABLE),
        .CMPRS_CBIT_CMODE_JPEG18         (CMPRS_CBIT_CMODE_JPEG18),
        .CMPRS_CBIT_CMODE_MONO6          (CMPRS_CBIT_CMODE_MONO6),
        .CMPRS_CBIT_CMODE_JP46           (CMPRS_CBIT_CMODE_JP46),
        .CMPRS_CBIT_CMODE_JP46DC         (CMPRS_CBIT_CMODE_JP46DC),
        .CMPRS_CBIT_CMODE_JPEG20         (CMPRS_CBIT_CMODE_JPEG20),
        .CMPRS_CBIT_CMODE_JP4            (CMPRS_CBIT_CMODE_JP4),
        .CMPRS_CBIT_CMODE_JP4DC          (CMPRS_CBIT_CMODE_JP4DC),
        .CMPRS_CBIT_CMODE_JP4DIFF        (CMPRS_CBIT_CMODE_JP4DIFF),
        .CMPRS_CBIT_CMODE_JP4DIFFHDR     (CMPRS_CBIT_CMODE_JP4DIFFHDR),
        .CMPRS_CBIT_CMODE_JP4DIFFDIV2    (CMPRS_CBIT_CMODE_JP4DIFFDIV2),
        .CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 (CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2),
        .CMPRS_CBIT_CMODE_MONO1          (CMPRS_CBIT_CMODE_MONO1),
        .CMPRS_CBIT_CMODE_MONO4          (CMPRS_CBIT_CMODE_MONO4),
        .CMPRS_CBIT_FRAMES_SINGLE        (CMPRS_CBIT_FRAMES_SINGLE),
        .CMPRS_COLOR18                   (CMPRS_COLOR18),
        .CMPRS_COLOR20                   (CMPRS_COLOR20),
        .CMPRS_MONO16                    (CMPRS_MONO16),
        .CMPRS_JP4                       (CMPRS_JP4),
        .CMPRS_JP4DIFF                   (CMPRS_JP4DIFF),
        .CMPRS_MONO8                     (CMPRS_MONO8),
        .CMPRS_FRMT_MBCM1                (CMPRS_FRMT_MBCM1),
        .CMPRS_FRMT_MBCM1_BITS           (CMPRS_FRMT_MBCM1_BITS),
        .CMPRS_FRMT_MBRM1                (CMPRS_FRMT_MBRM1),
        .CMPRS_FRMT_MBRM1_BITS           (CMPRS_FRMT_MBRM1_BITS),
        .CMPRS_FRMT_LMARG                (CMPRS_FRMT_LMARG),
        .CMPRS_FRMT_LMARG_BITS           (CMPRS_FRMT_LMARG_BITS),
        .CMPRS_CSAT_CB                   (CMPRS_CSAT_CB),
        .CMPRS_CSAT_CB_BITS              (CMPRS_CSAT_CB_BITS),
        .CMPRS_CSAT_CR                   (CMPRS_CSAT_CR),
        .CMPRS_CSAT_CR_BITS              (CMPRS_CSAT_CR_BITS),
        .CMPRS_CORING_BITS               (CMPRS_CORING_BITS)
    ) cmprs_cmd_decode_i (
//        .rst                (rst),                 // input
        .xclk               (xclk),                // input - global clock input, compressor single clock rate
        .mclk               (mclk),                // input - global system/memory clock
        .mrst               (mrst),                // input
        .ctrl_we            (set_ctrl_reg_w),      // input - control register write enable
        .format_we          (set_format_w),        // input - write number of tiles and left margin
        .color_sat_we       (set_color_saturation_w), // input - write color saturation values
        .coring_we          (set_coring_w),        // input - write color saturation values
        .di                 (cmd_data),            // input[31:0] - 32-bit data to write to control register (24LSB are used)
        .frame_start        (frame_start_dst),     // input @mclk
        .frame_start_xclk   (frame_start_xclk),    // re-clocked, parameters are copied during this pulse
        .cmprs_en_mclk      (cmprs_en_mclk),       // output
        .cmprs_en_extend    (cmprs_en_extend),     // input
        .cmprs_run_mclk     (cmprs_run_mclk),      // output reg 
        .cmprs_standalone   (cmprs_standalone),    // output reg 
        .sigle_frame_buf    (sigle_frame_buf),     // output reg 
        .cmprs_en_xclk      (frame_en),            // output reg
        .cmprs_en_late_xclk (stuffer_en),          // output reg - extended enable to allow stuffer to gracefully finish 
        .cmprs_qpage        (cmprs_qpage),         // output[2:0] reg 
        .cmprs_dcsub        (subtract_dc),         // output reg 
        .cmprs_fmode        (cmprs_fmode),         // output[1:0] reg 
        .bayer_shift        (bayer_phase),         // output[1:0] reg 
        .ignore_color       (ignore_color),        // output reg 
//      .four_blocks        (four_blocks),         // output reg Not used?
        .four_blocks        (),                    // output reg Not used?
        .jp4_dc_improved    (jp4_dc_improved),     // output reg 
        .converter_type     (converter_type),      // output[2:0] reg 
        .scale_diff         (scale_diff),          // output reg 
        .hdr                (hdr),                 // output reg 
        .left_marg          (left_marg),           // output[4:0] reg 
        .n_blocks_in_row_m1 (n_blocks_in_row_m1),  // output[12:0] reg 
        .n_block_rows_m1    (n_block_rows_m1),     // output[12:0] reg 
        .color_sat_cb       (m_cb),                // output[9:0] reg 
        .color_sat_cr       (m_cr),                // output[9:0] reg 
        .coring             (coring_num)           // output[2:0] reg 
    );

// set derived parameters from converter_type
//    wire   [ 2:0] converter_type;    // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff, 7 - mono8 (not yet implemented)
    cmprs_tile_mode_decode #( // fully combinatorial
        .CMPRS_COLOR18   (CMPRS_COLOR18),
        .CMPRS_COLOR20   (CMPRS_COLOR20),
        .CMPRS_MONO16    (CMPRS_MONO16),
        .CMPRS_JP4       (CMPRS_JP4),
        .CMPRS_JP4DIFF   (CMPRS_JP4DIFF),
        .CMPRS_MONO8     (CMPRS_MONO8)
    ) cmprs_tile_mode_decode_i (
        .converter_type  (converter_type), // input[2:0] 
        .mb_w_m1         (mb_w_m1),        // output[5:0] reg 
        .mb_h_m1         (mb_h_m1),        // output[5:0] reg 
        .mb_hper         (mb_hper),        // output[4:0] reg 
        .tile_width      (tile_width),     // output[1:0] reg 
        .tile_col_width  (tile_col_width)  // output reg 
    );


    cmprs_frame_sync #(
        .FRAME_HEIGHT_BITS  (FRAME_HEIGHT_BITS),
        .LAST_FRAME_BITS    (LAST_FRAME_BITS),
        .CMPRS_TIMEOUT_BITS (CMPRS_TIMEOUT_BITS),
        .CMPRS_TIMEOUT      (CMPRS_TIMEOUT)
    ) cmprs_frame_sync_i (
//        .rst                (rst),                 // input
        .xclk               (xclk),                // input - global clock input, compressor single clock rate
        .mclk               (mclk),                // input - global system/memory clock
        .mrst               (mrst),                // input
        .xrst               (xrst),                // input
        .cmprs_en           (cmprs_en_mclk),       // input - @mclk 0 resets immediately
        .cmprs_en_extend    (cmprs_en_extend), // output
        .cmprs_run          (cmprs_run_mclk),      // input - @mclk enable propagation of vsync_late to frame_start_dst in bonded(sync to src) mode
        .cmprs_standalone   (cmprs_standalone),    // input - @mclk single-cycle: generate a single frame_start_dst in unbonded (not synchronized) mode.
                                                   // cmprs_run should be off
        .sigle_frame_buf    (sigle_frame_buf),     // input - memory controller uses a single frame buffer (frame_number_* == 0), use other sync
        .vsync_late         (vsync_late),          // input - @mclk delayed start of frame, @xclk. In 353 it was 16 lines after VACT active
                                                   // source channel should already start, some delay give time for sequencer commands
                                                   // that should arrive before it
        .frame_started      (first_mb && mb_pre_start), // @xclk started first macroblock (checking for broken frames)
        .frame_start_dst    (frame_start_dst),     // output reg @mclk - trigger receive (tiled) memory channel (it will take care of
                                                   // single/repetitive modes itself this output either follows vsync_late (reclocks it)
                                                   // or generated in non-bonded mode (compress from memory once)
        .line_unfinished_src(line_unfinished_src), // input[15:0] - number of the current (unfinished ) line, in the source (sensor) channel
        .frame_number_src   (frame_number_src),    // input[15:0] - current frame number (for multi-frame ranges) in the source (sensor) channel
        .frame_done_src     (frame_done_src),      // input - single-cycle pulse when the full frame (window) was transferred to/from DDR3 memory 
                                                   // frame_done_src is later than line_unfinished_src/ frame_number_src changes
                                                   // Used withe a single-frame buffers
        .line_unfinished    (line_unfinished_dst), // input[15:0] - number of the current (unfinished ) line in this (compressor) channel
        .frame_number       (frame_number_dst),    // input[15:0] - current frame number (for multi-frame ranges) in this (compressor channel
        .frame_done         (frame_done_dst),      // input - single-cycle pulse when the full frame (window) was transferred to/from DDR3 memory 
        .suspend            (suspend),             // output reg - suspend reading data for this channel - waiting for the source data
        .stuffer_running    (stuffer_running), // input
        .force_flush_long   (force_flush_long),         // output reg - @ mclk tried to start frame compression before the previous one was finished
        .stuffer_running_mclk(stuffer_running_mclk), // output
        .reading_frame      (reading_frame) // output
        
    );

    cmprs_macroblock_buf_iface cmprs_macroblock_buf_iface_i (
//        .rst                (rst), // input
        .xclk               (xclk),               // input
        .mclk               (mclk),               // input
        .mrst               (mrst),               // input
        .xrst               (xrst),               // input
        .xfer_reset_page_rd (xfer_reset_page_rd), // input
        .page_ready_chn     (page_ready_chn),     // input
        .next_page_chn      (next_page_chn),      // output
        .frame_en           (frame_en),           // input
        .frame_start_xclk   (frame_start_xclk),   // input@posedge xclk - parameters are copied @ this pulse
        .frame_go           (frame_go),           // input - do not use - assign to frame_en? Running frames can be controlled by other means
        .left_marg          (left_marg),          // input[4:0] 
        .n_blocks_in_row_m1 (n_blocks_in_row_m1), // input[12:0] 
        .n_block_rows_m1    (n_block_rows_m1),    // input[12:0] 
        .mb_w_m1            (mb_w_m1),            // input[5:0]   // macroblock width minus 1 // 3 LSB not used here
        .mb_hper            (mb_hper),            // input[4:0]   // macroblock horizontal period (8/16) // 3 LSB not used (set them 0)
        .tile_width         (tile_width),         // input[1:0]   // memory tile width. Can be 32/64/128: 0 - 16, 1 - 32, 2 - 64, 3 - 128
        .mb_pre_end_in      (mb_pre_end),         // input
        .mb_release_buf     (mb_release_buf),     // input
        .mb_pre_start_out   (mb_pre_start),       // output
        .start_page         (start_page),         // output[1:0] 
        .macroblock_x       (macroblock_x),       // output[6:0] 
        .first_mb           (first_mb),           // output reg 
        .last_mb            (last_mb)             // output
        
    );

    cmprs_pixel_buf_iface #(
        .CMPRS_PREEND_EARLY      (6), // TODO:Check / Adjust
        .CMPRS_RELEASE_EARLY     (16),
        .CMPRS_BUF_EXTRA_LATENCY (0),
        .CMPRS_COLOR18           (CMPRS_COLOR18),
        .CMPRS_COLOR20           (CMPRS_COLOR20),
        .CMPRS_MONO16            (CMPRS_MONO16),
        .CMPRS_JP4               (CMPRS_JP4),
        .CMPRS_JP4DIFF           (CMPRS_JP4DIFF),
        .CMPRS_MONO8             (CMPRS_MONO8)
         
    ) cmprs_pixel_buf_iface_i (
        .xclk               (xclk),             // input
        .frame_en           (frame_en),         // input
        .buf_di             (buf_pxd),          // input[7:0] 
        .buf_ra             (buf_ra),           // output[11:0] 
        .buf_rd             (buf_rd),           // output[1:0] 
        .converter_type     (converter_type),   // input[2:0] 
        .mb_w_m1            (mb_w_m1),          // input[5:0] 
        .mb_h_m1            (mb_h_m1),          // input[5:0] 
        .tile_width         (tile_width),       // input[1:0] 
        .tile_col_width     (tile_col_width),   // input
        .mb_pre_end         (mb_pre_end),       // output
        .mb_release_buf     (mb_release_buf),   // output
        .mb_pre_start       (mb_pre_start),     // input
        .start_page         (start_page),       // input[1:0] 
        .macroblock_x       (macroblock_x),     // input[6:0] 
        .data_out           (mb_data_out),      // output[7:0] // Macroblock data out in scanline order
        .pre_first_out      (mb_pre_first_out), // output // Macroblock data out strobe - 1 cycle just before data valid  == old pre_first_pixel?
//        .data_valid         (mb_data_valid) // output     // Macroblock data out valid
        .data_valid         () // output        // Macroblock data out valid Unused
    );

    csconvert #(
        .CMPRS_COLOR18   (CMPRS_COLOR18),
        .CMPRS_COLOR20   (CMPRS_COLOR20),
        .CMPRS_MONO16    (CMPRS_MONO16),
        .CMPRS_JP4       (CMPRS_JP4),
        .CMPRS_JP4DIFF   (CMPRS_JP4DIFF),
        .CMPRS_MONO8     (CMPRS_MONO8)
    ) csconvert_i (
        .xclk           (xclk),             // input
        .frame_en       (frame_en),         // input
        .converter_type (converter_type),   // input[2:0] 
        .ignore_color   (ignore_color),     // input
        .scale_diff     (scale_diff),       // input
        .hdr            (hdr),              // input
        .limit_diff     (limit_diff),       // input
        .m_cb           (m_cb),             // input[9:0] 
        .m_cr           (m_cr),             // input[9:0] 
        .mb_din         (mb_data_out),      // input[7:0] 
        .bayer_phase    (bayer_phase),      // input[1:0] 
        .pre_first_in   (mb_pre_first_out), // input
        .signed_y       (signed_y),         // output[8:0] reg 
        .signed_c       (signed_c),         // output[8:0] reg 
        .yaddrw         (yaddrw),           // output[7:0] reg 
        .ywe            (ywe),              // output reg 
        .caddrw         (caddrw),           // output[7:0] reg 
        .cwe            (cwe),              // output reg 
        .pre_first_out  (yc_pre_first_out), // output reg 
        .n000           (n000),             // output[7:0] reg 
        .n255           (n255)              // output[7:0] reg 
    );


    cmprs_buf_average #(
        .CMPRS_COLOR18   (CMPRS_COLOR18),
        .CMPRS_COLOR20   (CMPRS_COLOR20),
        .CMPRS_MONO16    (CMPRS_MONO16),
        .CMPRS_JP4       (CMPRS_JP4),
        .CMPRS_JP4DIFF   (CMPRS_JP4DIFF),
        .CMPRS_MONO8     (CMPRS_MONO8)
    ) cmprs_buf_average_i (
        .xclk               (xclk),             // input
        .frame_en           (frame_en),         // input
        .converter_type     (converter_type),   // input[2:0] 
        .pre_first_in       (mb_pre_first_out), // input
        .yc_pre_first_out   (yc_pre_first_out), // input
        .bayer_phase        (bayer_phase),      // input[1:0] 
        .jp4_dc_improved    (jp4_dc_improved),  // input
        .hdr                (hdr),              // input
        .subtract_dc_in     (subtract_dc),      // input
        .first_mb_in        (first_mb),         // input - calculate in cmprs_macroblock_buf_iface 
        .last_mb_in         (last_mb),          // input - calculate in cmprs_macroblock_buf_iface
        .yaddrw             (yaddrw),           // input[7:0] 
        .ywe                (ywe),              // input
        .signed_y           (signed_y),         // input[8:0] 
        .caddrw             (caddrw),           // input[7:0] 
        .cwe                (cwe),              // input
        .signed_c           (signed_c),         // input[8:0] 
        .do                 (yc_nodc),          // output[9:0] 
        .avr                (yc_avr),           // output[8:0] 
//        .dv                 (yc_nodc_dv),       // output
        .dv                 (),                 // output unused?
        .ds                 (dct_start),        // output
        .tn                 (color_tn),         // output[2:0] 
        .first              (color_first),      // output reg 
        .last               (color_last),       // output reg 
        .component_num      (component_num),    // output[2:0] 
        .component_color    (component_color),  // output
        .component_first    (component_first),  // output
        .component_lastinmb (component_lastinmb)// output reg 
    );
//  wire   [ 9:0] yc_nodc;         // [9:0] data out (4:2:0) (signed, average=0)


///TODO: Replace always@ with a module?

    wire          dct_last_in;
    wire          dct_pre_first_out;
//    wire          dct_dv;
    wire   [12:0] dct_out;
    
    
 //propagation of first block through compressor pipeline
 
    wire          first_block_color=(color_tn[2:0]==3'h0) && color_first;        // while color conversion,
    reg           first_block_color_after;  // after color conversion,
    reg           first_block_dct;          // after DCT
    wire          first_block_quant;        // after quantizer
    always @ (posedge xclk) begin
        if (dct_start)   first_block_color_after <= first_block_color;
        if (dct_last_in) first_block_dct   <= first_block_color_after;
    end
    
    
    
    
    xdct393 xdct393_i (
        .clk                (xclk),                // input
        .en                 (frame_en),            // input  if zero will reset transpose memory page numbers
        .start              (dct_start),           // input  single-cycle start pulse that goes with the first pixel data. Other 63 should follow
        .xin                (yc_nodc),             // input[9:0] 
        .last_in            (dct_last_in),         // output reg  output high during input of the last of 64 pixels in a 8x8 block //
        .pre_first_out      (dct_pre_first_out),   // outpu 1 cycle ahead of the first output in a 64 block
///        .dv                 (dct_dv),           // output data output valid. Will go high on the 94-th cycle after the start (now - on 95-th?)
        .dv                 (),  // not used: output data output valid. Will go high on the 94-th cycle after the start (now - on 95-th?)
        .d_out              (dct_out)              // output[12:0] 
    );
    wire          quant_start;
    dly_16 #(.WIDTH(1)) i_quant_start (.clk(xclk),.rst(1'b0), .dly(4'd0), .din(dct_pre_first_out), .dout(quant_start));    // dly=0+1
 
    
    always @ (posedge xclk) begin
        if (!dccout) dcc_en <=1'b0;
        else if (dct_start && color_first && (color_tn[2:0]==3'b001)) dcc_en <=1'b1; // 3'b001 - closer to the first "start" in quantizator
    end
    
    
//    wire          table_a_not_d; // writing table address /not data (a[0] from cmd_deser)
//  wire          table_we;      // writing to tables               (decoded stb from cmd_deser)
    wire          tser_a_not_d;  // address/not data distributed to submodules
    wire   [ 7:0] tser_d;        // byte-wide serialized tables address/data to submodules
    wire          tser_qe;       // write serialized table data to quantizer
    wire          tser_ce;       // write serialized table data to coring
    wire          tser_fe;       // write serialized table data to focusing
    wire          tser_he;       // write serialized table data to Huffman
    
    table_ad_transmit #(
        .NUM_CHANNELS(4),
        .ADDR_BITS(3)
    ) table_ad_transmit_i (
        .clk             (mclk),                  // input @posedge
        .a_not_d_in      (cmd_a[0]),              // input writing table address /not data (a[0] from cmd_deser)
        .we              (set_tables_w),          // input writing to tables               (decoded stb from cmd_deser)
        .din             (cmd_data),              // input[31:0] 32-bit data to serialize/write to tables (LSB first) - from cmd_deser
        .ser_d           (tser_d),                // output[7:0] byte-wide serialized tables address/data to submodules
        .a_not_d         (tser_a_not_d),          // output reg address/not data distributed to submodules
        .chn_en          ({tser_he,tser_fe,tser_ce,tser_qe}) // output[0:0] reg - table 1-hot select outputs
    );
    
    
    
    quantizer393 quantizer393_i (
        .clk                (xclk),                   // input
        .en                 (frame_en),               // input 
        .mclk               (mclk),                   // input system clock, twqe, twce, ta,tdi - valid @posedge (ra, tdi - 2 cycles ahead (was negedge)
        .tser_qe            (tser_qe),                // input - write to a quantization table
        .tser_ce            (tser_ce),                // input - write to a coring table
        .tser_a_not_d       (tser_a_not_d),           // input - address/not data to tables
        .tser_d             (tser_d),                 // input[7:0] - byte-wide data to tables
        .ctypei             (component_color),        // input component type input (Y/C)
        .dci                (yc_avr),                 // input[8:0] - average value in a block - subtracted before DCT. now normal signed number
        .first_stb          (first_block_color),      // input - this is first stb pulse in a frame
        .stb                (dct_start),              // input - strobe that writes ctypei, dci
        .tsi                (cmprs_qpage[2:0]),       // input[2:0] - table (quality) select [2:0]
        .pre_start          (dct_pre_first_out),      // input - marks first input pixel (one before)
        .first_in           (first_block_dct),        // input - first block in (valid @ start)
        .first_out          (first_block_quant),      // output reg - valid @ ds
        .di                 (dct_out[12:0]),          // input[12:0] -  pixel data in (signed)
        .do                 (quant_do[12:0]),         // output[12:0] - pixel data out (AC is only 9 bits long?) - changed to 10
        .dv                 (),                       // output reg - data out valid
        .ds                 (quant_ds),               // output reg - data out strobe (one ahead of the start of dv)
        .dc_tdo             (quant_dc_tdo[15:0]),     // output[15:0] reg -  MSB aligned coefficient for the DC component (used in focus module)
        .dcc_en             (dcc_en),                 // input - enable dcc (sync to beginning of a new frame)
        .hfc_sel            (hfc_sel),                // input[2:0] - hight frequency components select [2:0] (includes components with both numbers >=hfc_sel
        .color_first        (color_first),            // input - first MCU in a frame
        .coring_num         (coring_num),             // input[2:0] - coring table pair number (0..7)
        .dcc_vld            (dccvld),                 // output reg  - single cycle when dcc_data is valid
        .dcc_data           (dccdata[15:0]),          // output[15:0] - dc component data out (for reading by software) 
        .n000               (n000),                   // input[7:0] - number of zero pixels (255 if 256) - to be multiplexed with dcc
        .n255               (n255)                    // input[7:0] - number of 0xff pixels (255 if 256) - to be multiplexed with dcc
    );

    // focus sharp module calculates amount of high-frequency components and optioanlly overlays/replaces actual image
    wire   [12:0] focus_do;     // output[12:0] reg  pixel data out, make timing ignore (valid 1.5 clk earlier that Quantizer output)
    wire          focus_ds;     // output reg data out strobe (one ahead of the start of dv)
    // TODO: Verify focus_sharp393: quantizer output (with strobes) is now 2 cycles later than in 353 (relative to xdct out). Seems to be OK.
    focus_sharp393 focus_sharp393_i (
        .clk                (xclk),                   // input - pixel clock
        .clk2x              (xclk2x),                 // input 2x pixel clock
        .en                 (frame_en),               // input 

        .mclk               (mclk),                   // input system clock to write tables
        .tser_we            (tser_fe),                // input - write to a quantization table
        .tser_a_not_d       (tser_a_not_d),           // input - address/not data to tables
        .tser_d             (tser_d),                 // input[7:0] - byte-wide data to tables
        
        .mode               (cmprs_fmode[1:0]),  // input[1:0] focus mode (combine image with focus info) - 0 - none, 1 - replace, 2 - combine all,  3 - combine woi
        .firsti             (color_first),            // input first macroblock
        .lasti              (color_last),             // input last macroblock
        .tni                (color_tn[2:0]),          // input[2:0] block number in a macronblock - 0..3 - Y, >=4 - color (sync to stb)
        .stb                (dct_start),              // input strobe that writes ctypei, dci
        .start              (quant_start),            // input marks first input pixel (needs 1 cycle delay from previous DCT stage)
        .di                 (dct_out),                // input[12:0] pixel data in (signed)
        .quant_ds           (quant_ds),               // input quantizator ds
        .quant_d            (quant_do[12:0]),         // input[12:0] quantizator data output
        .quant_dc_tdo       (quant_dc_tdo),           // input[15:0] MSB aligned coefficient for the DC component (used in focus module)
        .do                 (focus_do[12:0]),         // output[12:0] reg  pixel data out, make timing ignore (valid 1.5 clk earlier that Quantizer output)
        .ds                 (focus_ds),               // output reg data out strobe (one ahead of the start of dv)
        .hifreq             (hifreq[31:0])            // output[31:0] reg accumulated high frequency components in a frame sub-window
    );

    // Format DC components to be output as a mini-frame. Was not used in the late NC353 as the dma1 channel was use3d for IMU instead of dcc
    wire          finish_dcc;
    wire   [15:0] stuffer_do;
    wire          stuffer_dv;
    wire          stuffer_done;
    wire          eof_written_xclk2xn;
    
    // re-sync to posedge xclk2x
    reg           xrst2xn;
    always @ (negedge xclk2x) xrst2xn <= xrst;
    
    pulse_cross_clock finish_dcc_i (.rst(xrst2xn), .src_clk(~xclk2x), .dst_clk(xclk2x), .in_pulse(stuffer_done), .out_pulse(finish_dcc),.busy());
    
    dcc_sync393 dcc_sync393_i (
        .sclk               (xclk2x),                // input
        .dcc_en             (dcc_en),                // input xclk rising, sync with start of the frame
        .finish_dcc         (finish_dcc),            // input @ sclk rising
        .dcc_vld            (dccvld),                // input xclk rising
        .dcc_data           (dccdata[15:0]),         // input[15:0] @clk rising
        .statistics_dv      (statistics_dv),         // output reg 
        .statistics_do      (statistics_do[15:0])    // output[15:0] reg @ sclk
    );
    

// generate DC data/strobe for the direct output (re) using sdram channel3 buffering
// encoderDCAC is updated to handle 13-bit signed data instead of the 12-bit. It will limit the values on ot's own
    encoderDCAC393 encoderDCAC393_i (
        .clk                (xclk),                   // input
        .en                 (frame_en),               // input 
        .lasti              (color_last),             // input - was "last MCU in a frame" (@ stb)
        .first_blocki       (first_block_color),      // input - first block in frame - save fifo write address (@ stb)
        .comp_numberi       (component_num[2:0]),     // input[2:0] - component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use (@ stb)
        .comp_firsti        (component_first),        // input - first this component in a frame (reset DC) (@ stb)
        .comp_colori        (component_color),        // input - use color - huffman? (@ stb)
        .comp_lastinmbi     (component_lastinmb),     // input - last component in a macroblock (@ stb) is it needed?
        .stb                (dct_start),              // input - strobe that writes firsti, lasti, tni,average
        .zdi                (focus_do[12:0]),         // input[12:0] - zigzag-reordered data input
        .first_blockz       (first_block_quant),      // input - first block input (@zds)
        .zds                (focus_ds),               // input - strobe - one ahead of the DC component output
///        .last               (enc_last),               // output reg 
        .last               (),                       // output reg - not used
        .do                 (enc_do[15:0]),           // output[15:0] reg 
        .dv                 (enc_dv)                  // output reg 
    );


    huffman393 i_huffman (
        .xclk               (xclk),                   // input
        .xclk2x             (xclk2x),                 // input
        .en                 (frame_en),               // input
        .mclk               (mclk),                   // input system clock to write tables
        .tser_we            (tser_he),                // input - write to a quantization table
        .tser_a_not_d       (tser_a_not_d),           // input - address/not data to tables
        .tser_d             (tser_d),                 // input[7:0] - byte-wide data to tables
        .di                 (enc_do[15:0]),           // input[15:0] - specially RLL prepared 16-bit data (to FIFO)
        .ds                 (enc_dv),                 // input -  di valid strobe
        .rdy                (stuffer_rdy),            // input - receiver (bit stuffer) is ready to accept data
        .do                 (huff_do[15:0]),          // output[15:0] reg 
        .dl                 (huff_dl[3:0]),           // output[3:0] reg 
        .dv                 (huff_dv),                // output reg 
        .flush              (flush),                  // output reg 
///        .last_block(last_block), // output reg 
        .last_block         (), // output reg unused
        .test_lbw           (), // output reg ??
///        .gotLastBlock(test_lbw) // output ??
        .gotLastBlock       (), // output ?? - unused (was for debug)
        .clk_flush          (hclk), // input
        .flush_clk          (flush_hclk) // output
        
    );
    

    stuffer393 stuffer393_i (
//        .rst                 (rst),                    // input
        .mclk                (mclk),                   // input
        .mrst                (mrst),                    // input
        .xrst                (xrst),                    // input
        
        .ts_pre_stb          (ts_pre_stb),             // input      1 cycle before timestamp data, @mclk
        .ts_data             (ts_data),                // input[7:0] 8-byte timestamp data (s0,s1,s2,s3,us0,us1,us2,us3==0)
        .color_first         (color_first),            // input valid @xclk - only for sec/usec
        .fradv_clk           (xclk),                   // input
        .clk                 (xclk2x),                 // input clock - uses negedge inside
        .en_in               (stuffer_en),             // 
        .flush               (flush),                  // input - flush output data (fill byte with 0, long word with FFs)
        .abort               (force_flush_long),       // @ any, extracts 0->1 and flushes
        .stb                 (huff_dv),                // input
        .dl                  (huff_dl),                // input[3:0] number of bits to send (0 - 16) (0-16??)
        .d                   (huff_do),                // input[15:0] data to shift (only lower huff_dl bits are valid)
        // outputs valid @negedge xclk2x 
        .rdy                 (stuffer_rdy),            // output - enable huffman encoder to proceed. Used as CE for many huffman encoder registers
        .q                   (stuffer_do),             // output[15:0] reg - output data
        .qv                  (stuffer_dv),             // output reg - output data valid
        .done                (stuffer_done),           // output 
        .flushing            (),                       // output reg Not used?
        .running             (stuffer_running)         // from registering timestamp until done
        
`ifdef debug_stuffer
       ,.etrax_dma_r(tst_stuf_etrax[3:0]) // [3:0] just for testing
       ,.test_cntr(test_cntr[3:0])
       ,.test_cntr1(test_cntr1[7:0])
`endif
    );
    
    pulse_cross_clock stuffer_done_mclk_i (.rst(xrst2xn), .src_clk(~xclk2x), .dst_clk(mclk), .in_pulse(stuffer_done), .out_pulse(stuffer_done_mclk),.busy());
    cmprs_out_fifo cmprs_out_fifo_i (
//        .rst                 (rst),            // input mostly for simulation
        // source (stuffer) clock domain
        .wclk                (~xclk2x),        // input source clock (2x pixel clock, inverted) - same as stuffer out
        .wrst                (xrst2xn),         // input mostly for simulation
        
        .we                  (stuffer_dv),     // @ posedge(~xclk2x) input write data from stuffer
        .wdata               (stuffer_do),     // input[15:0] data from stuffer module;
        .wa_rst              (!stuffer_en),    // input reset low address bits when stuffer is disabled (to make sure it is multiple of 32 bytes
        .wlast               (stuffer_done),   // input - written last 32 bytes of a frame (flush FIFO) - stuffer_done (has to be later than we)
        .eof_written_wclk    (eof_written_xclk2xn),    // output - AFI had transferred frame data to the system memory
        // AFI clock domain
        .rclk                (hclk),           // @posedge(hclk) input - AFI clock
        .rrst                (hrst),           // input - AFI clock
        .rst_fifo            (fifo_rst),       // input - reset FIFO (set read address to write, reset count)
        .ren                 (fifo_ren),       // input - fifo read from AFI channel mux
        .rdata               (fifo_rdata),     // output[63:0] - data to AFI channel mux (latency == 2 from fifo_ren)
        .eof                 (fifo_eof),       // output single hclk pulse signalling EOF
        .eof_written         (eof_written),    // input single hclk pulse confirming frame data is written to the system memory
        .flush_fifo          (fifo_flush),     // output level signalling that FIFO has data from the current frame (use short AXI burst if needed)
        .fifo_count          (fifo_count)      // output[7:0] - number of 32-byte chunks available in FIFO
    );
    pulse_cross_clock eof_written_mclk_i (.rst(xrst2xn), .src_clk(~xclk2x), .dst_clk(mclk), .in_pulse(eof_written_xclk2xn), .out_pulse(eof_written_mclk),.busy());

// TODO: Add status module to combine/FF, re-clock status signals


endmodule

