Commit 8b1599eb authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Working on compressors interaction with external memory buffer

parent 72dc592d
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -49,7 +49,7 @@ module membridge#(
    // mcntrl_linear_rw.v interface
    // mcntrl_linear_rw.v interface
    output                        frame_start_chn, // input
    output                        frame_start_chn, // input
    output                        next_page_chn, // input
    output                        next_page_chn, // input
    input                         cmd_wrmem,      //
    input                         cmd_wrmem,      // @mclk - writing to DDR3 mode (0 - reading from DDR3)
    input                         page_ready_chn, // output single mclk
    input                         page_ready_chn, // output single mclk
    input                         frame_done_chn, // output single mclk
    input                         frame_done_chn, // output single mclk
    input [FRAME_HEIGHT_BITS-1:0] line_unfinished_chn1, // output[15:0] @SuppressThisWarning VEditor unused (yet)
    input [FRAME_HEIGHT_BITS-1:0] line_unfinished_chn1, // output[15:0] @SuppressThisWarning VEditor unused (yet)
+213 −0
Original line number Original line Diff line number Diff line
/*******************************************************************************
 * Module: cmprs_macroblock_buf_iface
 * Date:2015-06-11  
 * Author: andrey     
 * Description: Communicates with compressor memory buffer, generates pixel
 * stream matching selected color mode, accommodates for the buffer latency,
 * acts as a pacemaker for the whole compressor (next stages are able to keep up).
 *
 * Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
 * cmprs_macroblock_buf_iface.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.
 *
 *  cmprs_macroblock_buf_iface.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  cmprs_macroblock_buf_iface #(

    )(
    input         rst,
    input         xclk,               // global clock input, compressor single clock rate
    
    input         mclk,               // global clock for commands (posedge) and write side of the memory buffer (negedge)
    // buffer interface, DDR3 memory read
    input         xfer_reset_page_rd, // @ negedge mclk - reset ddr3 memory buffer. Use it to reset the read buffer too
    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 
     
    input         frame_en,           // if 0 - will reset logic immediately (but not page number)
    input         frame_go,           // start frame: if idle, will start reading data (if available),
                                      // if running - will not restart a new frame if 0.
    input  [ 4:0] left_marg,          // left margin (for not-yet-implemented) mono JPEG (8 lines tile row) can need 7 bits (mod 32 - tile)
    input  [12:0] n_blocks_in_row_m1, // number of macroblocks in a macroblock row minus 1
    input  [12:0] n_block_rows_m1,    // number of macroblock rows in a frame minus 1
    input  [ 5:0] mb_w_m1,            // macroblock width minus 1 // 3 LSB not used
    input  [ 4:0] mb_hper,            // macroblock horizontal period (8/16) // 3 LSB not used
    input  [ 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
    
    input         mb_pre_end_in,      // from cmprs_pixel_buf_iface - just in time to start a new macroblock w/o gaps
    input         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        
    output        mb_pre_start_out,   // 1 clock cycle before stream of addresses to the buffer
    output [ 1:0] start_page,         // page to read next tile from (or first of several pages)
    output [ 6:0] macroblock_x        // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
    
);

    wire          reset_page_rd;
    wire          page_ready;
    
    wire          frame_en_w;
    reg           frame_en_r;
    
    reg    [12:0] mb_cols_left;   // number of a macroblocks left in a row (after this)    
    reg    [12:0] mb_rows_left;   // number of a rows left in a row (after this)
    wire   [ 6:0] mbl_x;          // macroblock left pixel x relative to a tile (page) Maximal page - 128 bytes wide
    reg    [ 6:3] mbl_x_r;        // macroblock left pixel x relative to a tile (page) (3 low don't change)
    reg    [ 6:3] mbl_x_next_r;   // macroblock left pixel x relative to a tile (page), not valid for first column (3 low don't change)    
    reg    [ 7:3] mbl_x_inc_r;    // intermediate register for calculating mbl_x_next_r and add_invalid
    reg    [ 7:3] mbl_x_last_r;   // intermediate register for calculating needed_page

    reg    [1:0]  pre_advance_tiles; // advance tiles by this for same row of macroblocks

    wire          mb_pre_start_w; // start sequence for a macroblock
    wire          frame_pre_start_w; // start sequence for a new frame
    reg           frame_pre_start_r; 
    reg    [ 8:0] mb_pre_start;   // 1-hot macroblock pre start calcualtions - TODO: adjust width
    wire   [ 2:0] buf_diff;       // difference between page needed and next valid - should be negative to have it ready
    wire          buf_ready_w;    // External memory buffer has all the pages needed
       
    reg           mb_first_in_row;
    reg           mb_last_in_row;
    reg           mb_last_row;
    wire          mb_last;
    reg    [ 2:0] next_valid;     // number of next valid page (only 2 LSB are actual page number)
    reg    [ 2:0] next_invalid;   // oldest valid page
    reg    [ 1:0] add_invalid;    // advance next_invalid pointer by this value, send next_page pulses
    reg    [ 2:0] used_pages;     // number of pages simultaneously used for the last macroblock
    reg    [ 2:0] needed_page;    // calculate at MB start
    wire          starting;
    reg frame_pre_run;

    assign frame_en_w = frame_en && frame_go;
    
    assign mbl_x={mbl_x_r[6:3], left_marg[2:0]};
    
    assign buf_diff = needed_page - next_valid;
    assign buf_ready_w = buf_diff[2];
    assign mb_pre_start_out=mb_pre_start[5]; // first after wait?
    assign macroblock_x = mbl_x;

    assign mb_last = mb_last_row && mb_last_in_row;
    assign starting = |mb_pre_start;

    assign mb_pre_start_w =  (mb_pre_end_in && (!mb_last || frame_en_w)) || (!frame_pre_run && frame_en_w && !frame_en_r && !starting);
    assign frame_pre_start_w =  frame_en_w && ((mb_pre_end_in && mb_last) || (!frame_pre_run && !frame_en_r && !starting));
    
    assign start_page = next_invalid[1:0]; // oldest page needed for this macroblock
    always @ (posedge xclk) begin
        if (!frame_en) frame_en_r <= 0;
        else           frame_en_r <= frame_en_w;
        
        frame_pre_start_r <= frame_pre_start_w; // same time as mb_pre_start
        
        if      (!frame_en)         mb_first_in_row <= 0;
        else if (frame_pre_start_r) mb_first_in_row <= 1;
        else if (mb_pre_start[0])   mb_first_in_row <= mb_last_in_row;
        
        
        if      (!frame_en)                frame_pre_run <= 0;
        else if (mb_pre_start_w)           frame_pre_run <= 1;
        else if (mb_pre_end_in && mb_last) frame_pre_run <= 0;
        
        if      (frame_pre_start_r)                                        mb_rows_left <= n_block_rows_m1;
        else if (mb_pre_start[0] && mb_last_in_row)                        mb_rows_left <= mb_rows_left - 1;        
        
        if      (frame_pre_start_r || (mb_pre_start[0] && mb_last_in_row)) mb_cols_left <= n_blocks_in_row_m1;
        else if (mb_pre_start[0])                                          mb_cols_left <= mb_cols_left - 1;
        
        if      (mb_pre_start[1])                                          mb_last_row <= (mb_rows_left == 0);
        
        if      (mb_pre_start[1])                                          mb_last_in_row <= (mb_cols_left == 0);
        
        // pages read from the external memory, previous one is the last in the buffer
        if   (reset_page_rd) next_valid <= 0;
        else if (page_ready) next_valid <=  next_valid + 1;
        
         
        // calculate before starting each macroblock (will wait if buffer is not ready) (TODO: align mb_pre_start[0] to mb_pre_end[2] - same)
        //mb_pre_start_w
        if      (mb_pre_start_w)                  mb_pre_start <= 1;
        else if (!mb_pre_start[4] || buf_ready_w) mb_pre_start <= mb_pre_start << 1;
        if (mb_pre_start[1]) mbl_x_r[6:3] <=      mb_first_in_row? {2'b0,left_marg[4:3]} : mbl_x_next_r[6:3];
        if (mb_pre_start[2]) mbl_x_last_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {2'b0,mb_w_m1[5:3]};
        if (mb_pre_start[3]) begin
            case (tile_width)
                2'b00: needed_page[2:0] <=  next_invalid[2:0]+{1'b0, mbl_x_last_r[5:4]}; 
                2'b01: needed_page[2:0] <=  next_invalid[2:0]+{1'b0, mbl_x_last_r[6:5]}; 
                2'b10: needed_page[2:0] <=  next_invalid[2:0]+{1'b0, mbl_x_last_r[7:6]}; 
                2'b11: needed_page[2:0] <=  next_invalid[2:0]+{2'b0, mbl_x_last_r[7]}; 
            endcase
        end

        // at the end of each macroblock - calculate start page increment (and after delay - advance invalidate_next)
        // changed to after started:
        
        // calculate next start X in page (regardless of emd of macroblock row - selection will be at macroblock start)
        
        if (mb_pre_start[5]) mbl_x_inc_r[7:3] <= {1'b0,mbl_x_r[6:3]} + {3'b0,mb_hper[4:3]};
        if  (mb_pre_start[6]) begin
            case (tile_width)
                2'b00:  begin
                            mbl_x_next_r[6:3] <=       {3'b0,mbl_x_inc_r[3]};
                            pre_advance_tiles[1:0]  <= mbl_x_inc_r[5:4]; 
                        end
                2'b01:  begin
                            mbl_x_next_r[6:3] <=       {2'b0,mbl_x_inc_r[4:3]};
                            pre_advance_tiles[1:0]  <= mbl_x_inc_r[6:5]; 
                        end
                2'b10:  begin
                            mbl_x_next_r[6:3] <=       {1'b0,mbl_x_inc_r[5:3]};
                            pre_advance_tiles[1:0]  <= mbl_x_inc_r[7:6]; 
                        end
                2'b11:  begin
                            mbl_x_next_r[6:3] <=       {     mbl_x_inc_r[6:3]};
                            pre_advance_tiles[1:0]  <= {1'b0, mbl_x_inc_r[7]}; 
                        end
            endcase
            used_pages <= needed_page - next_invalid +1;
        end
        if  (mb_pre_start[7]) begin // TODO: apply after delay, regardless last or not
            if (mb_last_in_row) add_invalid <= used_pages[1:0];
            else                add_invalid <= pre_advance_tiles;
        end
        // pages already processed by compressor - they can be reused for reading new tiles
        if      (reset_page_rd) next_invalid <= 0;
        else if (mb_pre_start[8]) next_invalid <= next_invalid + {1'b0, add_invalid}; // TODO: Send next_page after delay
        // "next_page_ pulses will be sent near the end of the macroblock


        
    
    end     

    // synchronization between mclk and xclk clock domains
    // negedge mclk -> xclk (verify clock inversion is absorbed)
    pulse_cross_clock  reset_page_rd_i (.rst(rst), .src_clk(~mclk),.dst_clk(xclk), .in_pulse(xfer_reset_page_rd), .out_pulse(reset_page_rd),.busy());
    // mclk -> xclk
    pulse_cross_clock page_ready_i     (.rst(rst), .src_clk(mclk), .dst_clk(xclk), .in_pulse(page_ready_chn), .out_pulse(page_ready),.busy());

    multipulse_cross_clock #(
        .WIDTH(3),
        .EXTRA_DLY(0)
    ) multipulse_cross_clock_i (
        .rst        (rst), // input
        .src_clk    (xclk), // input
        .dst_clk    (mclk), // input
        .num_pulses ({1'b0,add_invalid}), // input[0:0] 
        .we         (mb_release_buf), // input
        .out_pulse  (next_page_chn), // output
        .busy       () // output
    );

endmodule
+256 −0

File added.

Preview size limit exceeded, changes collapsed.

+16 −10
Original line number Original line Diff line number Diff line
@@ -27,7 +27,13 @@ module color_proc393 (
         input          en,         // Enable (0 will reset states)
         input          en,         // Enable (0 will reset states)
         input          en_sdc,     // enable subtracting of DC component
         input          en_sdc,     // enable subtracting of DC component
         input          go,         // pulse to star/restart (needed for each frame, repeat generated by the caller)
         input          go,         // pulse to star/restart (needed for each frame, repeat generated by the caller)
         // TODO: Remove
         input   [25:0] nblocks,    // ***** was [17:0] number of 16x16 blocks to read (valid @ "go" pulse)
         input   [25:0] nblocks,    // ***** was [17:0] number of 16x16 blocks to read (valid @ "go" pulse)
         // NEW: Now number of SDRAM blobks (tiles) is not equal to number of macroblocks
         input   [12:0] n_blocks_in_row,   // number of macroblocks in a macroblock row
         input   [12:0] n_block_rows,      // number of macroblock rows in a frame
//         input          reset_sdram_page,  // SDRAM buffer page may be reset (normally just increments for each new tile
         // end of NEW
         output         eot,            // single-cycle end of transfer pulse
         output         eot,            // single-cycle end of transfer pulse
         input   [ 9:0] m_cb,       // [9:0] scale for CB - default 0.564 (10'h90)
         input   [ 9:0] m_cb,       // [9:0] scale for CB - default 0.564 (10'h90)
         input   [ 9:0] m_cr,       // [9:0] scale for CB - default 0.713 (10'hb6)
         input   [ 9:0] m_cr,       // [9:0] scale for CB - default 0.713 (10'hb6)
@@ -114,7 +120,7 @@ module color_proc393 (
   reg    [2:0]   sdrama_line_inc; // increment amount when proceeding to next tile line
   reg    [2:0]   sdrama_line_inc; // increment amount when proceeding to next tile line
   reg    [1:0]   inc_sdrama_r;
   reg    [1:0]   inc_sdrama_r;
   reg            last_from_sdram; // reading last_r byte from SDRAM
   reg            last_from_sdram; // reading last_r byte from SDRAM
   reg            first_pixel; // reading first_r pixel to color converter (di will be evailable next cycle)
   reg            first_pixel; // reading first_r pixel to color converter (di will be available next cycle)
   reg            tim2next;
   reg            tim2next;
   reg    [8:0]   y_in, c_in;
   reg    [8:0]   y_in, c_in;
   reg    [7:0]   yaddrw, caddrw;
   reg    [7:0]   yaddrw, caddrw;
@@ -471,7 +477,7 @@ module color_proc393 (


wire limit_diff=1'b1;
wire limit_diff=1'b1;


 csconvert18    i_csconvert18 (
 csconvert18a    i_csconvert18 (
                         .RST           (!en_converters[0]),
                         .RST           (!en_converters[0]),
                         .CLK           (clk),
                         .CLK           (clk),
                         .mono          (ignore_color_r),
                         .mono          (ignore_color_r),
@@ -536,39 +542,39 @@ assign conv20_pre_first_out= conv18_pre_first_out;




// currently only 8 bits are used in the memories
// currently only 8 bits are used in the memories
    ramp_var_w_var_r #(
    ram18p_var_w_var_r #(
        .REGISTERS    (1), // will need to delay output strobe(s) by 1
        .REGISTERS    (1), // will need to delay output strobe(s) by 1
        .LOG2WIDTH_WR (3),
        .LOG2WIDTH_WR (3),
        .LOG2WIDTH_RD (3),
        .LOG2WIDTH_RD (3),
        .DUMMY        (0)
        .DUMMY        (0)
    ) i_y_buff (
    ) i_y_buff (
        .rclk         (clk),                           // input
        .rclk         (clk),                           // input
        .raddr        ({2'b0,rpage[1:0],raddr[7:0]}),  // input[11:0] 
        .raddr        ({1'b0,rpage[1:0],raddr[7:0]}),  // input[11:0] 
        .ren          (!raddr[8]),                     // input
        .ren          (!raddr[8]),                     // input
        .regen        (!raddr8_d),                     // input
        .regen        (!raddr8_d),                     // input
        .data_out     (y_out[8:0]),                    // output[8:0] 
        .data_out     (y_out[8:0]),                    // output[8:0] 
        .wclk         (clk),                           // input
        .wclk         (clk),                           // input
        .waddr        ({2'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0] 
        .waddr        ({1'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0] 
        .we           (ywe),                           // input
        .we           (ywe),                           // input
        .web          (8'hf),                          // input[7:0] 
        .web          (4'hf),                          // input[7:0] 
        .data_in      (y_in[8:0])                      // input[9:0] 
        .data_in      (y_in[8:0])                      // input[9:0] 
    );
    );


    ramp_var_w_var_r #(
    ram18p_var_w_var_r #(
        .REGISTERS    (1), // will need to delay output strobe(s) by 1
        .REGISTERS    (1), // will need to delay output strobe(s) by 1
        .LOG2WIDTH_WR (3),
        .LOG2WIDTH_WR (3),
        .LOG2WIDTH_RD (3),
        .LOG2WIDTH_RD (3),
        .DUMMY        (0)
        .DUMMY        (0)
    ) i_CrCb_buff (
    ) i_CrCb_buff (
        .rclk         (clk),                           // input
        .rclk         (clk),                           // input
        .raddr        ({2'b0,rpage[1:0],raddr[7:0]}),  // input[11:0] 
        .raddr        ({1'b0,rpage[1:0],raddr[7:0]}),  // input[11:0] 
        .ren          (raddr[8]),                      // input
        .ren          (raddr[8]),                      // input
        .regen        (raddr8_d),                      // input
        .regen        (raddr8_d),                      // input
        .data_out     (c_out[8:0]),                    // output[8:0] 
        .data_out     (c_out[8:0]),                    // output[8:0] 
        .wclk         (clk),                           // input
        .wclk         (clk),                           // input
        .waddr        ({2'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0] 
        .waddr        ({1'b0,wpage[1:0],yaddrw[7:0]}), // input[11:0] 
        .we           (ywe),                           // input
        .we           (ywe),                           // input
        .web          (8'hf),                          // input[7:0] 
        .web          (4'hf),                          // input[7:0] 
        .data_in      (y_in[8:0])                      // input[71:0] 
        .data_in      (y_in[8:0])                      // input[71:0] 
    );
    );


+64 −0
Original line number Original line Diff line number Diff line
/*******************************************************************************
 * Module: multipulse_cross_clock
 * Date:2015-04-27  
 * Author: andrey     
 * Description: Generate a train of pulses through clock domains boundary
 * Maximal duty cycle (with EXTRA_DLY=0 and Fdst << Fsrc) = 50%
 * same frequencies - ~1/3 (with EXTRA_DLY=0) and 1/5 (with EXTRA_DLY=1)
 * Lowering Fsrc reduces duty cycle proportianally as counter is in src_clk
 * domain.
 *
 * Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
 * multipulse_cross_clock.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.
 *
 *  multipulse_cross_clock.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  multipulse_cross_clock#(
    parameter WIDTH=1,          // width of the pulse counter (assign MSB of input to 0 to
                                // have more pending that possible input)
    parameter EXTRA_DLY=0)(     // 0 or 1 - output duty cycle control
    input              rst,
    input              src_clk,
    input              dst_clk,
    input  [WIDTH-1:0] num_pulses, // single-cycle positive pulse
    input              we,
    output             out_pulse,
    output             busy
);
    reg   [WIDTH-1:0] pend_cntr=0;
    wire              busy_single;
    wire              single_rq_w;
    reg               single_rq_r=0;

    assign busy = busy_single && (|pend_cntr);
    assign single_rq_w = busy_single && (|pend_cntr);
    
    always @(posedge src_clk) begin
        single_rq_r <= single_rq_w;
        pend_cntr <= pend_cntr + (we ? num_pulses : {WIDTH{1'b0}}) + (single_rq_r ? {WIDTH{1'b1}}:{WIDTH{1'b0}});
    end
    
    pulse_cross_clock #(
        .EXTRA_DLY(EXTRA_DLY)
    ) pulse_cross_clock_i (
        .rst       (rst), // input
        .src_clk   (src_clk), // input
        .dst_clk   (dst_clk), // input
        .in_pulse  (single_rq_w), // input
        .out_pulse (out_pulse), // output
        .busy      (busy_single) // output
    );
    
endmodule
Loading