cmprs_raw_buf_iface.v 12.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/*!
 * <b>Module:</b>cmprs_raw_buf_iface
 * @file cmprs_raw_buf_iface.v
 * @date 2015-06-11  
 * @author Andrey Filippov     
 *
 * @brief Communicates with compressor memory buffer in raw (uncompressed) mode
 *
 * @copyright Copyright (c) 2019 Elphel, Inc.
 *
 * <b>License:</b>
 *
 * cmprs_raw_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_raw_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/> .
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
 * files and/or simulating the code, the copyright holders of this Program give
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
 * charge, and there is no dependence on any encrypted modules for simulating of
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
 */
`timescale 1ns/1ps

module  cmprs_raw_buf_iface #(
//    parameter DCT_PIPELINE_PAUSE = 48, // TODO: find really required value (minimal), adjust counter bits (now 6)
//                                      // 48 seems to be OK (may be less)
    parameter FRAME_QUEUE_WIDTH = 2
)(
    input         xclk,               // global clock input, compressor single clock rate
    input         mclk,               // global clock for commands (posedge) and write side of the memory buffer (negedge)
    input         mrst,      // @posedge mclk, sync reset
    input         xrst,      // @posedge xclk, sync reset

// Page is limited by 1kB or end of line
    // 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 
     
// will be externally combined with "uncompressed"  
    input         frame_en,           // if 0 - will reset logic immediately (but not the page number)
    input         frame_start_xclk,   // frame parameters are valid after this pulse (re-clocked from the memory controller)
    input         frame_go,           // start frame: if idle, will start reading data (if available),
                                      // if running - will not restart a new frame if 0.
    input         cmprs_run_mclk,     // 0 - off or stopping, reset frame_pre_run
//    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             stuffer_running, // @xclk, active while bit stuffer or trailer are running
    input             raw_be16,           // 0: bytes 0-1-2-3-4-5..., 1: bytes 1-0-3-2-5-4...
    output     [11:0] buf_ra,             // buffer read address (2 MSB - page number)
    output     [ 1:0] buf_rd,             // buf {regen, re}
    output            raw_start,          // was color_first leading edge
    output            raw_prefb,   // input
    output            raw_ts_copy, // input
    output            raw_flush   // input
);

// TODO:

    wire          reset_page_rd; // xfer_reset_page_rd @ xclk
    wire          page_ready;    // page_ready_chn @ xclk

    wire          frame_en_w;
    reg           frame_en_r;
    wire          frame_pre_start_w; // start sequence for a new frame
    reg           frame_pre_start_r; 
    reg           frame_start_xclk_r; // next cycle after frame_start_xclk
    reg           cmprs_run_xclk;
    reg           frame_pre_run;
    reg [FRAME_QUEUE_WIDTH:0] frame_que_cntr; // width+1
89
    reg     [3:0] frame_finish_r; // active after last macroblock in a frame
90 91 92 93 94 95 96 97 98

    reg    [ 2:0] next_valid;     // number of next valid page (only 2 LSB are actual page number)
    reg    [ 2:0] needed_page;    // calculate at MB start
    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    [14:0] quads_left;  // number of quad bytes left in a row (after this)    
    reg    [16:0] rows_left;   // number of rows left (after this)
    reg     [1:0] rows_last;
99
    reg           page_run; // on after page_start, off after quad_r[2], so during last quad_r[3] shold be off
100 101 102 103 104 105 106 107 108
    reg     [3:0] quad_r;
    reg           quad_last;   // last quad byte in a row should be valid @quad_r[2]
    wire          page_start;
    wire          page_end_w;
    
    wire          release_buf;     // send required "next_page" pulses to buffer. Having rather long minimal latency in the memory
    wire          frame_finish_w;
    wire          frames_pending;
    reg           starting; // from frame_start_r to first page start
109 110 111
    reg           mode_valid;//  after parameters are valid, invalid whe mode is reset
    reg           page_end_r;
    reg           frame_done;
112 113 114 115 116 117 118 119 120 121
    
    assign frame_en_w = frame_en && frame_go; // both are inputs
    // one extra at the end of frame is needed (sequence will be short)  ???
////    assign mb_pre_start_w =     mb_pre_end_in ||              (frame_start_xclk_r && !frame_pre_run); //  && !starting);
// repeated start (if some are pending) and for the first frame     
    assign frame_pre_start_w =  (frames_pending && frame_finish_w) || (frame_start_xclk_r && !frame_pre_run && !starting);

    assign buf_diff = needed_page - next_valid;
    assign buf_ready_w = buf_diff[2];

122 123
//    assign page_start = !page_run && buf_ready_w && ((frame_pre_run && starting && stuffer_running) || !frame_done);  // frame_pre_run should deassert  in time with frame end
    assign page_start = !page_run && buf_ready_w && frame_pre_run && ((starting && stuffer_running) || !frame_done);  // frame_pre_run should deassert  in time with frame end
124
   
125
//    reg page_restart_r;
126 127
     
    assign raw_start = frame_pre_start_r; // for JP - leading edge of color_first
128 129
//  assign page_end_w = frame_en && quad_r[2] && (&bufa_r[9:2] || quad_last);
    assign page_end_w = frame_en && quad_r[1] && (&bufa_r[9:2] || quad_last);
130
    
131 132
//    assign release_buf = page_end_w;
    assign release_buf = page_end_r;
133
    
134
    assign frame_finish_w = frame_finish_r[1]  && !frame_finish_r[0]; // now just single-cycle, no need for frame_finish_r[0]
135 136 137 138
    assign frames_pending = !frame_que_cntr[FRAME_QUEUE_WIDTH] && (|frame_que_cntr[FRAME_QUEUE_WIDTH-1:0]);
    
    assign frame_en_w = frame_en && frame_go;
    
139 140
//    assign raw_prefb = buf_rd_r[0]; // delay if memory registered more. TODO Add parameter if it already used    
    assign raw_prefb = quad_r[1]; // delay if memory registered more. TODO Add parameter if it already used    
141 142 143 144 145 146
    
    assign raw_ts_copy = frame_en_r && rows_last[0] && !rows_last[1];

    reg    [11:0]   bufa_r;             // buffer read address (2 MSB - page number)
    reg     [1:0] buf_rd_r;

147
    assign raw_flush = frame_finish_r[3]; // frame_finish_w;
148 149 150 151 152 153 154 155 156
    
    assign buf_ra = bufa_r;
    
    assign buf_rd = buf_rd_r[1:0];
    always @(posedge xclk) begin
        // 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;
    
157 158 159 160 161 162 163
        if      (!frame_en)         mode_valid <= 0;
//        else if (frame_start_xclk) mode_valid <= frame_start_xclk;
        else if (frame_pre_start_r) mode_valid <= 1; // frame_pre_start_r sets remaining quads, rows
        
   
    
    
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        cmprs_run_xclk <=     cmprs_run_mclk;
            
        frame_pre_start_r <= frame_pre_start_w; // same time as mb_pre_start
    
        if (!frame_en) frame_start_xclk_r <= 0;
        else           frame_start_xclk_r <= frame_start_xclk;
        
        if      (!frame_en)         starting <= 1'b0;
        else if (frame_pre_start_w) starting <= 1'b1;
        else if (page_start)        starting <= 1'b0;
    
        if (!frame_en) frame_en_r <= 0;
        else           frame_en_r <= frame_en_w; // stays on?

        if      (!cmprs_run_xclk)                           frame_que_cntr <= 0;
        else if ( frame_start_xclk_r && !frame_pre_start_r) frame_que_cntr <= frame_que_cntr + 1;
        else if (!frame_start_xclk_r && frame_pre_start_r)  frame_que_cntr <= frame_que_cntr - 1;
        
        if (reset_page_rd) needed_page[2:0] <=  0; // together with next_valid, next_invalid
        else if (release_buf) begin
            needed_page <= needed_page + 1;
        end
        
        page_end_r <= page_end_w; // quad_r[2] && (&bufa_r[9:2] || quad_last);
        
        // page_run
        if      (!frame_pre_run)          page_run <= 0;
        else if (page_start)              page_run <= 1;
192 193
//        else if (quad_r[2] && page_end_r) page_run <= 0;        
        else if (page_end_r)              page_run <= 0;        
194 195 196 197 198 199 200
        
        if      (!frame_pre_run)          quad_r <=    0;
        else                              quad_r <= {quad_r[2:0], page_start | (quad_r[3] & page_run)}; 
        
        buf_rd_r <= {buf_rd_r[0], page_start | (|quad_r[2:0] | (quad_r[3] & page_run))}; 

        if   (!frame_en) frame_finish_r <= 0;
201
        else             frame_finish_r <= {frame_finish_r[2:0], quad_r[2] & quad_last & rows_last[0]};
202 203 204 205 206

//quads_left        
        if      (frame_pre_start_r || (quad_r[2] && quad_last)) quads_left <= {n_blocks_in_row_m1, 2'b11};
        else if (quad_r[2])                                     quads_left <= quads_left - 1;
        
207
        quad_last <= mode_valid && !(|quads_left); // valid from 2 after frame_pre_start_r or after quad_r[3]
208 209 210 211

        if      (frame_pre_start_r)                             rows_left <=  {n_block_rows_m1, 4'b1111};
        else if ((quad_r[2] && quad_last))                      rows_left <=  rows_left - 1;
        
212 213 214 215
        rows_last <= {rows_last[0], mode_valid & ~(|rows_left)};
        
//        if (frame_pre_start_r) bufa_r[11:10] <= needed_page[1:0];
        if (page_start) bufa_r[11:10] <= needed_page[1:0];
216 217
        
        
218 219 220
//        if (frame_pre_start_r)           bufa_r[9:1] <= 0;
        if      (page_start)             bufa_r[9:1] <= 0;
        else if (quad_r[1] | quad_r[3])  bufa_r[9:1] <= bufa_r[9:1] + 1;
221 222 223 224 225 226 227
        
        if (frame_pre_start_r) bufa_r[0] <=  raw_be16;
        else if (buf_rd_r[0])  bufa_r[0] <= ~bufa_r[0];

        if      (!frame_en || (!frames_pending && frame_finish_w)) frame_pre_run <= 0;
        else if (frame_pre_start_w)                                frame_pre_run <= 1;
        
228 229 230
        if      (!frame_en || frame_pre_start_r)      frame_done <= 0;
        else if (quad_r[2] && quad_last && rows_last) frame_done <= 1; // valid @ quad_r[3], when page_run is already == 0 
        
231 232 233 234 235 236 237 238 239 240 241 242 243 244
    end
    
    reg nmrst;
    always @(negedge mclk) nmrst <= mrst;
    // synchronization between mclk and xclk clock domains
    // negedge mclk -> xclk (verify clock inversion is absorbed)
    pulse_cross_clock  reset_page_rd_i (.rst(nmrst), .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(mrst), .src_clk(mclk),  .dst_clk(xclk), .in_pulse(page_ready_chn),     .out_pulse(page_ready),    .busy());
    // xclk -> mclk
    pulse_cross_clock next_page_chn_i  (.rst(xrst), .src_clk(xclk),  .dst_clk(mclk), .in_pulse(page_end_r),         .out_pulse(next_page_chn), .busy());

endmodule