mcntrl_linear_rw.v 43.9 KB
Newer Older
1 2 3 4 5 6 7
/*!
 * <b>Module:</b>mcntrl_linear_rw
 * @file mcntrl_linear_rw.v
 * @date 2015-01-29  
 * @author Andrey Filippov     
 *
 * @brief Organize paged R/W from DDR3 memory in scan-line order
8 9
 * with window support
 *
10 11 12 13
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
 *
14 15 16 17 18 19 20 21 22 23 24 25
 * mcntrl_linear_rw.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.
 *
 *  mcntrl_linear_rw.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/> .
26 27 28 29 30 31
 *
 * 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"
32
 * files and/or simulating the code, the copyright holders of this Program give
33 34
 * 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
Andrey Filippov's avatar
Andrey Filippov committed
35
 * charge, and there is no dependence on any encrypted modules for simulating of
36 37 38
 * 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.
39
 */
40
`timescale 1ns/1ps
41
// TODO: ADD MCNTRL_SCANLINE_FRAME_PAGE_RESET to caller
42
`define REPORT_FRAME_NUMBER 1
43
`undef DEBUG_MCNTRL_LINEAR_EXTRA_STATUS 
44 45 46 47 48
module  mcntrl_linear_rw #(
    parameter ADDRESS_NUMBER=                   15,
    parameter COLADDR_NUMBER=                   10,
    parameter NUM_XFER_BITS=                     6,    // number of bits to specify transfer length
    parameter FRAME_WIDTH_BITS=                 13,    // Maximal frame width - 8-word (16 bytes) bursts 
49
    parameter FRAME_HEIGHT_BITS=                16,    // Maximal frame height
50
    parameter LAST_FRAME_BITS=                  16,     // number of bits in frame counter (before rolls over)
51
    parameter MCNTRL_SCANLINE_ADDR=            'h120,
52
    parameter MCNTRL_SCANLINE_MASK=            'h7f0, // both channels 0 and 1
53
    parameter MCNTRL_SCANLINE_MODE=            'h0,   // set mode register: {repet,single,rst_frame,na[2:0],extra_pages[1:0],write_mode,enable,!reset}
54 55
    parameter MCNTRL_SCANLINE_STATUS_CNTRL=    'h1,   // control status reporting
    parameter MCNTRL_SCANLINE_STARTADDR=       'h2,   // 22-bit frame start address (3 CA LSBs==0. BA==0)
56 57 58 59 60 61
    parameter MCNTRL_SCANLINE_FRAME_SIZE=      'h3,   // 22-bit frame start address increment (3 CA LSBs==0. BA==0)
    parameter MCNTRL_SCANLINE_FRAME_LAST=      'h4,   // 16-bit last frame number in the buffer
    parameter MCNTRL_SCANLINE_FRAME_FULL_WIDTH='h5,   // Padded line length (8-row increment), in 8-bursts (16 bytes)
    parameter MCNTRL_SCANLINE_WINDOW_WH=       'h6,   // low word - 13-bit window width (0->'h4000), high word - 16-bit frame height (0->'h10000)
    parameter MCNTRL_SCANLINE_WINDOW_X0Y0=     'h7,   // low word - 13-bit window left, high word - 16-bit window top
    parameter MCNTRL_SCANLINE_WINDOW_STARTXY=  'h8,   // low word - 13-bit start X (relative to window), high word - 16-bit start y
62 63
                                                      // Start XY can be used when read command to start from the middle
                                                      // TODO: Add number of blocks to R/W? (blocks can be different) - total length?
64
                                                      // Read back current address (for debugging)?
65
    parameter MCNTRL_SCANLINE_START_DELAY =    'ha,      // Set start delay (to accommodate for the command sequencer                                                       
66
    parameter MCNTRL_SCANLINE_STATUS_REG_ADDR= 'h4,
67
    parameter MCNTRL_SCANLINE_PENDING_CNTR_BITS=2,     // Number of bits to count pending trasfers, currently 2 is enough, but may increase
68 69 70
                                                      // if memory controller will allow programming several sequences in advance to
                                                      // spread long-programming (tiled) over fast-programming (linear) requests.
                                                      // But that should not be too big to maintain 2-level priorities
71 72 73 74 75 76 77 78 79
    parameter MCNTRL_SCANLINE_FRAME_PAGE_RESET =1'b0, // reset internal page number to zero at the frame start (false - only when hard/soft reset)
    // bits in mode control word
    parameter MCONTR_LINTILE_NRESET =           0, // reset if 0
    parameter MCONTR_LINTILE_EN =               1, // enable requests 
    parameter MCONTR_LINTILE_WRITE =            2, // write to memory mode
    parameter MCONTR_LINTILE_EXTRAPG =          3, // extra pages (over 1) needed by the client simultaneously
    parameter MCONTR_LINTILE_EXTRAPG_BITS =     2, // number of bits to use for extra pages
    parameter MCONTR_LINTILE_RST_FRAME =        8, // reset frame number 
    parameter MCONTR_LINTILE_SINGLE =           9, // read/write a single page 
80 81
    parameter MCONTR_LINTILE_REPEAT =          10, // read/write pages until disabled 
    parameter MCONTR_LINTILE_DIS_NEED =        11, // disable 'need' request 
82
    parameter MCONTR_LINTILE_SKIP_LATE =       12, // skip actual R/W operation when it is too late, advance pointers
83
    parameter MCONTR_LINTILE_ABORT_LATE =      14,  // abort frame if not finished by the new frame sync (wait pending memory)
84 85 86 87
    
// TODO NC393: This delay may be too long for serail sensors. Make them always start to fill the
// first buffer page, waiting for the request from mcntrl_linear during that first page. And if it will arrive - 
// just continue.    
88
    parameter MCNTRL_SCANLINE_DLY_WIDTH =      12,  // delay start pulse by 1..64 mclk
89
    parameter MCNTRL_SCANLINE_DLY_DEFAULT =  1024  // initial delay value for start pulse
90
)(
Andrey Filippov's avatar
Andrey Filippov committed
91
    input                          mrst,
92 93 94 95 96
    input                          mclk,
// programming interface
    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
    
97 98
    output                   [7:0] status_ad,      // byte-wide address/data
    output                         status_rq,      // request to send downstream (last byte with rq==0)
99 100 101
    input                          status_start,   // acknowledge of address (first byte) from downsteram   

    input                          frame_start,   // resets page, x,y, and initiates transfer requests (in write mode will wait for next_page)
102
    output                         frame_run,     // @mclk - enable pixels from sensor to memory buffer
103 104 105
    input                          next_page,     // page was read/written from/to 4*1kB on-chip buffer
//    output                         page_ready,    // == xfer_done, connect externally | Single-cycle pulse indicating that a page was read/written from/to DDR3 memory
    output                         frame_done,    // single-cycle pulse when the full frame (window) was transferred to/from DDR3 memory
106
    output                         frame_finished,// turns on and stays on after frame_done
107
// optional I/O for channel synchronization
108 109
// after the last tile in a frame, before starting a new frame line_unfinished will point to non-existent (too high) line in the same frame
    output [FRAME_HEIGHT_BITS-1:0] line_unfinished, // number of the current (unfinished ) line, RELATIVE TO FRAME, NOT WINDOW?. 
110
    input                          suspend,       // suspend transfers (from external line number comparator)
111
    output   [LAST_FRAME_BITS-1:0] frame_number,  // current frame number (for multi-frame ranges)
112
    output                         frame_set,     // frame number is just set to a new value (can be used by slave to sync)
113 114 115
    output                         xfer_want,     // "want" data transfer
    output                         xfer_need,     // "need" - really need a transfer (only 1 page/ room for 1 page left in a buffer), want should still be set.
    input                          xfer_grant,    // sequencer programming access granted, deassert wait/need 
116
    output                         xfer_reject,   // reject granted access (when skipping)
117 118
    output                         xfer_start_rd, // initiate a transfer (next cycle after xfer_grant)
    output                         xfer_start_wr, // initiate a transfer (next cycle after xfer_grant)
119 120 121 122
    output                   [2:0] xfer_bank,     // bank address
    output    [ADDRESS_NUMBER-1:0] xfer_row,      // memory row
    output    [COLADDR_NUMBER-4:0] xfer_col,      // start memory column in 8-bursts
    output     [NUM_XFER_BITS-1:0] xfer_num128,   // number of 128-bit words to transfer (8*16 bits) - full bursts of 8 ( 0 - maximal length, 64)
123
    output                         xfer_partial,  // partial tile (first of 2) , sequencer will not generate page_next at the end of block   
124
    input                          xfer_done,     // transfer to/from the buffer finished
125
    output                         xfer_page_rst_wr, // reset buffer internal page - at each frame start or when specifically reset (write to memory channel), @posedge
126
    output                         xfer_page_rst_rd, // reset buffer internal page - at each frame start or when specifically reset (read memory channel), @negedge
127
    output reg                     xfer_skipped,
128
    output                         cmd_wrmem
129 130 131 132 133 134 135

`ifdef DEBUG_SENS_MEM_PAGES
    ,input                 [1 : 0] dbg_rpage
    ,input                 [1 : 0] dbg_wpage
`endif
    
    
136 137 138
);
    localparam NUM_RC_BURST_BITS=ADDRESS_NUMBER+COLADDR_NUMBER-3;  //to spcify row and col8 == 22
    localparam MPY_WIDTH=        NUM_RC_BURST_BITS; // 22
Andrey Filippov's avatar
Andrey Filippov committed
139
    localparam PAR_MOD_LATENCY=  9; // TODO: Find actual worst-case latency for:
140 141 142
    reg    [FRAME_WIDTH_BITS-1:0] curr_x;         // (calculated) start of transfer x (relative to window left)
    reg   [FRAME_HEIGHT_BITS-1:0] curr_y;         // (calculated) start of transfer y (relative to window top)
    reg     [FRAME_HEIGHT_BITS:0] next_y;         // (calculated) next row number
Andrey Filippov's avatar
Andrey Filippov committed
143
    reg   [NUM_RC_BURST_BITS-1:0] line_start_addr;// (calculated) Line start (in {row,col8} in burst8
144
 // calculating full width from the frame width
145 146 147
// WARNING: [Synth 8-3936] Found unconnected internal register 'frame_y_reg' and it is trimmed from '16' to '3' bits. [memctrl/mcntrl_linear_rw.v:268]
// Throblem seems to be that frame_y8_r_reg (load of trimmed bits of the frame_y_reg) is (as intended) absorbed into DSP48. The lower 3 bits are used
// outside of the DSP 48.  "dont_touch" seems to work here
148 149 150 151
`ifndef IGNORE_ATTR
    (* keep = "true" *)
`endif    
    reg   [FRAME_HEIGHT_BITS-1:0] frame_y;     // current line number referenced to the frame top
152 153 154 155 156
    reg    [FRAME_WIDTH_BITS-1:0] frame_x;     // current column number referenced to the frame left
    reg   [FRAME_HEIGHT_BITS-4:0] frame_y8_r;  // (13 bits) current row with bank removed, latency2 (to be absorbed when inferred DSP multipler)
    reg      [FRAME_WIDTH_BITS:0] frame_full_width_r;  // (14 bit) register to be absorbed by MPY
    reg           [MPY_WIDTH-1:0] mul_rslt;
    reg   [NUM_RC_BURST_BITS-1:0] start_addr_r;   // 22 bit - to be absorbed by DSP
157 158
//    reg                     [2:0] bank_reg [2:0];
    reg             [3 * 3 - 1:0] bank_reg;
159 160 161 162
    wire [FRAME_WIDTH_BITS+FRAME_HEIGHT_BITS-3:0] mul_rslt_w;
    reg      [FRAME_WIDTH_BITS:0] row_left;   // number of 8-bursts left in the current row
    reg                           last_in_row;
    reg      [COLADDR_NUMBER-3:0] mem_page_left; // number of 8-bursts left in the pointed memory page
Andrey Filippov's avatar
Andrey Filippov committed
163
    reg      [COLADDR_NUMBER-4:0] line_start_page_left; // number of 8-burst left in the memory page from the start of the frame line
164
    reg         [NUM_XFER_BITS:0] lim_by_xfer;   // number of bursts left limited by the longest transfer (currently 64)
165 166 167 168 169 170 171
//    reg        [MAX_TILE_WIDTH:0] lim_by_tile_width;     // number of bursts left limited by the longest transfer (currently 64)
    wire     [COLADDR_NUMBER-3:0] remainder_in_xfer ;//remainder_tile_width;  // number of bursts postponed to the next partial tile (because of the page crossing) MSB-sign
    reg                           continued_xfer;   //continued_tile;        // this is a continued tile (caused by page crossing) - only once
    reg       [NUM_XFER_BITS-1:0] leftover; //[MAX_TILE_WIDTH-1:0] leftover_cols;         // valid with continued_tile, number of columns left
    
    
    
172
    reg         [NUM_XFER_BITS:0] xfer_num128_r;   // number of 128-bit words to transfer (8*16 bits) - full bursts of 8
173
//    reg       [NUM_XFER_BITS-1:0] xfer_num128_m1_r;   // number of 128-bit words to transfer minus 1 (8*16 bits) - full bursts of 8
174
    wire                          pgm_param_w;  // program one of the parameters, invalidate calculated results for PAR_MOD_LATENCY
175 176 177
    reg                     [2:0] xfer_start_r; // 1 hot started by xfer start only (not by parameter change)
    reg                           xfer_start_rd_r;
    reg                           xfer_start_wr_r;
178
    reg     [PAR_MOD_LATENCY-1:0] par_mod_r;
179
    reg     [PAR_MOD_LATENCY-1:0] recalc_r; // 1-hot CE for re-calculating registers
180
// SuppressWarnings VEditor unused 
181
    wire                          calc_valid;   // calculated registers have valid values   
182 183 184 185 186
    wire                          chn_en;       // enable requests by channel (continue ones in progress), enable frame_start_late inputs
    wire                          chn_rst;      // resets command, including fifo;
    reg                           chn_rst_d;    // delayed by 1 cycle do detect turning off
    wire                          abort_en;     // enable frame abort (mode register bit)
    reg                           aborting_r;   // waiting pending memory transactions at if the frame was not finished at frame sync
187 188 189 190 191
//    reg                           xfer_reset_page_r;
    reg                           xfer_page_rst_r=1;
    reg                           xfer_page_rst_pos=1;  
    reg                           xfer_page_rst_neg=1;  
    
192 193
    reg                     [2:0] page_cntr;
    
194
//    wire                          cmd_wrmem; //=MCNTRL_SCANLINE_WRITE_MODE; // 0: read from memory, 1:write to memory
195
    wire                    [1:0] cmd_extra_pages; // external module needs more than 1 page
196
    wire                          skip_too_late;
197
    wire                          disable_need; // do not assert need, only want
198 199 200 201
    wire                          repeat_frames; // mode bit
    wire                          single_frame_w; // pulse
    wire                          rst_frame_num_w;
    reg                           single_frame_r;  // pulse
202
    reg                     [1:0] rst_frame_num_r; // reset frame number/next start address
203 204
    reg                           frame_en;       // enable next frame
    
205 206
    reg                           busy_r;
    reg                           want_r;
207
    reg                           want_d; // want_r delayed (no gap to pending_xfers)
208 209
    reg                           need_r;
    reg                           frame_done_r;
210
    reg                           frame_finished_r;    
211 212
    wire                          last_in_row_w;
    wire                          last_row_w;
Andrey Filippov's avatar
Andrey Filippov committed
213
//    wire                          last_block_w;
214 215 216
    reg                           last_block;
    reg [MCNTRL_SCANLINE_PENDING_CNTR_BITS-1:0] pending_xfers; // number of requested,. but not finished block transfers      
    reg   [NUM_RC_BURST_BITS-1:0] row_col_r;
217 218 219 220
//    reg [2*FRAME_HEIGHT_BITS-1:0] line_unfinished_r;
    reg   [FRAME_HEIGHT_BITS-1:0] line_unfinished_relw_r;
    reg   [FRAME_HEIGHT_BITS-1:0] line_unfinished_r;
    
221
    wire                          pre_want;
222
    reg                           pre_want_r1;
223 224
`ifdef DEBUG_MCNTRL_LINEAR_EXTRA_STATUS    
    wire                   [11:0] status_data;
225 226 227 228
`else
  `ifdef REPORT_FRAME_NUMBER
    wire    [LAST_FRAME_BITS+1:0] status_data;
  `else        
229
    wire                    [1:0] status_data;
230 231
  `endif                                               
    
232
`endif    
233 234 235 236 237 238 239
    wire                    [3:0] cmd_a; 
    wire                   [31:0] cmd_data; 
    wire                          cmd_we;
    
    wire                          set_mode_w;
    wire                          set_status_w;
    wire                          set_start_addr_w;
240 241
    wire                          set_frame_size_w;
    wire                          set_last_frame_w;
242 243 244 245
    wire                          set_frame_width_w;
    wire                          set_window_wh_w;
    wire                          set_window_x0y0_w;
    wire                          set_window_start_w;
Andrey Filippov's avatar
Andrey Filippov committed
246 247
    wire                          lsw13_zero=!(|cmd_data[FRAME_WIDTH_BITS-1:0]); // LSW 13 (FRAME_WIDTH_BITS) low bits are all 0 - set carry bit  
    wire                          msw_zero=  !(|cmd_data[31:16]); // MSW all bits are 0 - set carry bit
248 249
      
    
250
    reg                    [14:0] mode_reg;//mode register: {dis_need,repet,single,rst_frame,na[2:0],extra_pages[1:0],write_mode,enable,!reset}
251 252 253 254
    
    reg   [NUM_RC_BURST_BITS-1:0] start_range_addr; // (programmed) First frame in range start (in {row,col8} in burst8, bank ==0
    reg   [NUM_RC_BURST_BITS-1:0] frame_size;       // (programmed) First frame in range start (in {row,col8} in burst8, bank ==0
    reg     [LAST_FRAME_BITS-1:0] last_frame_number; 
255
    reg   [NUM_RC_BURST_BITS-1:0] start_addr;     // (programmed) Frame start (in {row,col8} in burst8, bank ==0
256 257
    reg   [NUM_RC_BURST_BITS-1:0] next_frame_start_addr;
    reg     [LAST_FRAME_BITS-1:0] frame_number_cntr;
258 259
    reg     [LAST_FRAME_BITS-1:0] frame_number_current;
    
260
    reg                           is_last_frame;
261 262
//    reg                     [2:0] frame_start_r;
    reg                     [4:0] frame_start_r; // increased length to have time from line_unfinished to suspend (external)
263 264 265 266 267 268 269 270
    
    reg      [FRAME_WIDTH_BITS:0] frame_full_width;     // (programmed) increment combined row/col when moving to the next line
                                                  // frame_width rounded up to max transfer (half page) if frame_width> max transfer/2,
                                                  // otherwise (smaller widths) round up to the nearest power of 2
    reg      [FRAME_WIDTH_BITS:0] window_width;   // (programmed) 0- max
    reg     [FRAME_HEIGHT_BITS:0] window_height;  // (programmed) 0- max
    reg    [FRAME_WIDTH_BITS-1:0] window_x0;      // (programmed) window left
    reg   [FRAME_HEIGHT_BITS-1:0] window_y0;      // (programmed) window top
271 272
    reg    [FRAME_WIDTH_BITS-1:0] start_x;        // (programmed) normally 0, copied to curr_x on frame_start_late  
    reg   [FRAME_HEIGHT_BITS-1:0] start_y;        // (programmed) normally 0, copied to curr_y on frame_start_late 
273
    reg                           xfer_done_d;    // xfer_done delayed by 1 cycle (also includes xfer_skipped)
274
    reg [MCNTRL_SCANLINE_DLY_WIDTH-1:0] start_delay; // how much to delay frame start
275 276
    reg [MCNTRL_SCANLINE_DLY_WIDTH:0] start_delay_cntr = {MCNTRL_SCANLINE_DLY_WIDTH+1{1'b1}}; // start delay counter
    reg                           frame_start_late;
277
    wire                          set_start_delay_w; 
278 279
    reg                           buf_reset_pend;  // reset buffer page at next (late)frame sync (compressor should be disabled
                                                   // if total  number of pages in a frame is not multiple of 4 
280
    wire                          chn_dis_delayed = chn_rst || (!chn_en && !busy_r); // reset if real reset or disabled and frame finished 
281 282 283
`ifdef REPORT_FRAME_NUMBER
    reg     [LAST_FRAME_BITS-1:0] done_frame_number;
`endif                                               
284
//    wire                                                
285
    
286
    assign frame_number =       frame_number_current;
287
    
288 289 290
    assign set_mode_w =         cmd_we && (cmd_a== MCNTRL_SCANLINE_MODE);
    assign set_status_w =       cmd_we && (cmd_a== MCNTRL_SCANLINE_STATUS_CNTRL);
    assign set_start_addr_w =   cmd_we && (cmd_a== MCNTRL_SCANLINE_STARTADDR);
291 292
    assign set_frame_size_w =   cmd_we && (cmd_a== MCNTRL_SCANLINE_FRAME_SIZE);
    assign set_last_frame_w =   cmd_we && (cmd_a== MCNTRL_SCANLINE_FRAME_LAST);
293 294 295 296
    assign set_frame_width_w =  cmd_we && (cmd_a== MCNTRL_SCANLINE_FRAME_FULL_WIDTH);
    assign set_window_wh_w =    cmd_we && (cmd_a== MCNTRL_SCANLINE_WINDOW_WH);
    assign set_window_x0y0_w =  cmd_we && (cmd_a== MCNTRL_SCANLINE_WINDOW_X0Y0);
    assign set_window_start_w = cmd_we && (cmd_a== MCNTRL_SCANLINE_WINDOW_STARTXY);
297
    assign set_start_delay_w =  cmd_we && (cmd_a== MCNTRL_SCANLINE_START_DELAY);
298
    
299 300
    assign single_frame_w =  cmd_we && (cmd_a== MCNTRL_SCANLINE_MODE) && cmd_data[MCONTR_LINTILE_SINGLE];
    assign rst_frame_num_w = cmd_we && (cmd_a== MCNTRL_SCANLINE_MODE) && cmd_data[MCONTR_LINTILE_RST_FRAME];
301
    
302
    assign frame_run = busy_r;
303
    assign frame_set = frame_start_r[3];
304
    // Set parameter registers
Andrey Filippov's avatar
Andrey Filippov committed
305 306
    always @(posedge mclk) begin
        if      (mrst)               mode_reg <= 0;
307
        else if (set_mode_w)         mode_reg <= cmd_data[14:0]; // 4:0]; // [4:0];
308

Andrey Filippov's avatar
Andrey Filippov committed
309 310
        if (mrst) single_frame_r <= 0;
        else      single_frame_r <= single_frame_w;
311
        
Andrey Filippov's avatar
Andrey Filippov committed
312
        if (mrst) rst_frame_num_r <= 0;
313 314 315
        else      rst_frame_num_r <= {rst_frame_num_r[0], rst_frame_num_w }; // now only at specific command
/*
        |
316 317 318
                                     set_start_addr_w |
                                     set_last_frame_w |
                                     set_frame_size_w};
319
*/ 
Andrey Filippov's avatar
Andrey Filippov committed
320
        if      (mrst)               start_range_addr <= 0;
321 322
        else if (set_start_addr_w)   start_range_addr <= cmd_data[NUM_RC_BURST_BITS-1:0];

Andrey Filippov's avatar
Andrey Filippov committed
323
        if      (mrst)               frame_size <= 0;
324 325
        else if (set_start_addr_w)   frame_size <= 1; // default number of frames - just one
        else if (set_frame_size_w)   frame_size <= cmd_data[NUM_RC_BURST_BITS-1:0];
326

Andrey Filippov's avatar
Andrey Filippov committed
327
        if      (mrst)             last_frame_number <= 0;
328 329
        else if (set_last_frame_w) last_frame_number <= cmd_data[LAST_FRAME_BITS-1:0];
        
Andrey Filippov's avatar
Andrey Filippov committed
330
        if      (mrst)              frame_full_width <=  0;
Andrey Filippov's avatar
Andrey Filippov committed
331
        else if (set_frame_width_w) frame_full_width <= {lsw13_zero,cmd_data[FRAME_WIDTH_BITS-1:0]};
332
        
Andrey Filippov's avatar
Andrey Filippov committed
333
        if (mrst) is_last_frame <= 0;
334
//      else      is_last_frame <= frame_number_cntr == last_frame_number;
335 336 337 338 339 340
        else      is_last_frame <= frame_number_cntr >= last_frame_number; // trying to make it safe
        
`ifdef REPORT_FRAME_NUMBER
        if      (mrst)         done_frame_number <= 0;
        else if (frame_done_r) done_frame_number <= frame_number_cntr;
`endif                                               
341
        
342
//        if (mrst) frame_start_r <= 0;
343
//        else      frame_start_r <= {frame_start_r[3:0], frame_start_late & frame_en};
344

345 346
//        if      (mrst)                            frame_en <= 0;
        if      (!chn_en)                         frame_en <= 0;
347
        else if (single_frame_r || repeat_frames) frame_en <= 1;
348 349 350 351
        else if (frame_start_late)                frame_en <= 0;
        
        // will reset buffer page at next frame start
        if      (mrst ||frame_start_r[0])         buf_reset_pend <= 0;
352
        else if (rst_frame_num_r[0])              buf_reset_pend <= 1;
353
        
Andrey Filippov's avatar
Andrey Filippov committed
354
        if      (mrst)               frame_number_cntr <= 0;
355 356 357
        else if (rst_frame_num_r[0]) frame_number_cntr <= 0;
        else if (frame_start_r[2])   frame_number_cntr <= is_last_frame?{LAST_FRAME_BITS{1'b0}}:(frame_number_cntr+1);

Andrey Filippov's avatar
Andrey Filippov committed
358
        if      (mrst)               frame_number_current <= 0;
359 360 361
        else if (rst_frame_num_r[0]) frame_number_current <= 0;
        else if (frame_start_r[2])   frame_number_current <= frame_number_cntr;

Andrey Filippov's avatar
Andrey Filippov committed
362
        if      (mrst)               next_frame_start_addr <= start_range_addr; // just to use rst
363 364 365
        else if (rst_frame_num_r[1]) next_frame_start_addr <= start_range_addr;
        else if (frame_start_r[2])   next_frame_start_addr <= is_last_frame? start_range_addr : (start_addr+frame_size);

Andrey Filippov's avatar
Andrey Filippov committed
366
        if      (mrst)               start_addr <= start_range_addr; // just to use rst
367 368
        else if (frame_start_r[0])   start_addr <= next_frame_start_addr;
        
Andrey Filippov's avatar
Andrey Filippov committed
369
        if      (mrst) begin
370 371 372 373 374 375 376
               window_width <= 0; 
               window_height <=  0;
        end else if (set_window_wh_w)  begin
               window_width <= {lsw13_zero,cmd_data[FRAME_WIDTH_BITS-1:0]};
               window_height  <= {msw_zero,cmd_data[FRAME_HEIGHT_BITS+15:16]};
        end

Andrey Filippov's avatar
Andrey Filippov committed
377
        if      (mrst) begin
378 379 380 381 382 383 384
               window_x0 <= 0; 
               window_y0 <=  0;
        end else if (set_window_x0y0_w)  begin
               window_x0 <= cmd_data[FRAME_WIDTH_BITS-1:0];
               window_y0  <=cmd_data[FRAME_HEIGHT_BITS+15:16];
        end

Andrey Filippov's avatar
Andrey Filippov committed
385
        if      (mrst) begin
386 387 388 389
               start_x <= 0; 
               start_y <=  0;
        end else if (set_window_start_w)  begin
               start_x <= cmd_data[FRAME_WIDTH_BITS-1:0];
390
               start_y <= cmd_data[FRAME_HEIGHT_BITS+15:16];
391
        end
392 393 394 395
        
        if      (mrst)              start_delay <= MCNTRL_SCANLINE_DLY_DEFAULT;
        else if (set_start_delay_w) start_delay <= cmd_data[MCNTRL_SCANLINE_DLY_WIDTH-1:0];
        
396 397 398 399 400 401 402 403
        if      (mrst)                                         start_delay_cntr <= {MCNTRL_SCANLINE_DLY_WIDTH+1{1'b1}};
        else if (frame_start)                                  start_delay_cntr <= {1'b0, start_delay};
        else if (!start_delay_cntr[MCNTRL_SCANLINE_DLY_WIDTH]) start_delay_cntr <= start_delay_cntr - 1;
        
        frame_start_late <= start_delay_cntr == 0;
        
//        
        
404 405 406
    end
    assign mul_rslt_w=  frame_y8_r * frame_full_width_r; // 5 MSBs will be discarded
    assign xfer_num128= xfer_num128_r[NUM_XFER_BITS-1:0];
407 408
    assign xfer_start_rd=  xfer_start_rd_r;
    assign xfer_start_wr=  xfer_start_wr_r;
409
    assign calc_valid=  par_mod_r[PAR_MOD_LATENCY-1]; // MSB, longest 0
410 411 412
    assign xfer_page_rst_wr=  xfer_page_rst_r;
    assign xfer_page_rst_rd=  xfer_page_rst_neg;
    
413 414
    assign xfer_partial=      xfer_limited_by_mem_page_r;
    
415
    assign frame_done=  frame_done_r;
416 417
    assign frame_finished=  frame_finished_r;
    
418 419
//    assign pre_want=    chn_en && busy_r && !want_r && !xfer_start_r[0] && calc_valid && !last_block && !suspend && !(|frame_start_r);
    // accelerating pre_want:
420 421
//    assign pre_want= pre_want_r1 && !want_r && !xfer_start_r[0] && !suspend ;
    // last_block was too late to inclusde in pre_want_r1, moving it here
422
    
423
    assign pre_want= pre_want_r1 && !want_r && !xfer_start_r[0] && !suspend  && !last_block && !aborting_r;
424

425 426 427 428
    assign last_in_row_w=(row_left=={{(FRAME_WIDTH_BITS-NUM_XFER_BITS){1'b0}},xfer_num128_r});
    assign last_row_w=  next_y==window_height;
    assign xfer_want=   want_r;
    assign xfer_need=   need_r;
429
    assign xfer_bank=   bank_reg[3 * 2 +: 3]; // TODO: just a single reg layer
430 431
    assign xfer_row= row_col_r[NUM_RC_BURST_BITS-1:COLADDR_NUMBER-3] ;      // memory row
    assign xfer_col= row_col_r[COLADDR_NUMBER-4:0];    // start memory column in 8-bursts
432
    assign line_unfinished = line_unfinished_r; // [FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS];
433 434 435 436 437
    assign chn_en =         mode_reg[MCONTR_LINTILE_NRESET] & mode_reg[MCONTR_LINTILE_EN];   // enable requests by channel (continue ones in progress)
    assign chn_rst =        ~mode_reg[MCONTR_LINTILE_NRESET]; // resets command, including fifo;
    assign cmd_wrmem =       mode_reg[MCONTR_LINTILE_WRITE];// 0: read from memory, 1:write to memory
    assign cmd_extra_pages = mode_reg[MCONTR_LINTILE_EXTRAPG+:MCONTR_LINTILE_EXTRAPG_BITS]; // external module needs more than 1 page
    assign repeat_frames=    mode_reg[MCONTR_LINTILE_REPEAT];
438
    assign disable_need =    mode_reg[MCONTR_LINTILE_DIS_NEED];
439
    assign skip_too_late =   mode_reg[MCONTR_LINTILE_SKIP_LATE];
440 441
    assign abort_en =        mode_reg[MCONTR_LINTILE_ABORT_LATE];
    
442 443 444
`ifdef DEBUG_MCNTRL_LINEAR_EXTRA_STATUS    
    assign status_data=      {last_row_w, last_in_row,line_unfinished[7:0], frame_finished_r, busy_r}; 
`else
445 446 447
  `ifdef REPORT_FRAME_NUMBER
    assign status_data=      {done_frame_number, frame_finished_r, busy_r};     // TODO: Add second bit?
  `else
448
    assign status_data=      {frame_finished_r, busy_r};     // TODO: Add second bit?
449
  `endif
450
`endif    
451
    assign pgm_param_w=      cmd_we;
452 453
    localparam [COLADDR_NUMBER-3-NUM_XFER_BITS-1:0] EXTRA_BITS=0;
    assign remainder_in_xfer = {EXTRA_BITS, lim_by_xfer}-mem_page_left;
454 455
    
    integer i;
456
    wire xfer_limited_by_mem_page= mem_page_left < {EXTRA_BITS,lim_by_xfer};
457
    reg  xfer_limited_by_mem_page_r;
458 459 460 461 462
//  skipping pages that did not make it
//    reg    skip_tail; // skip end of frame if the next frame started (TBD)
// Now skip if write and >=4 or read and >=5 (read starts with 4 and may end with 4)
// Also if the next page signal is used by the source/dest of data, it should use reject pulse to advance external
// page counter 
463 464 465 466
    wire         start_skip_w;
    reg          start_skip_r;
    reg          skip_run = 0;    // run "skip" - advance addresses, but no actual read/write
    reg          xfer_reject_r;
467
    reg          frame_start_pending; // frame_start_late came before previous one was finished
468 469
    reg    [1:0] frame_start_pending_long;
    wire         xfer_done_skipped = xfer_skipped || xfer_done;
470
    
471
    wire         frame_start_delayed = frame_start_pending_long[1] && !frame_start_pending_long[0];
472
    wire         frame_start_mod = (frame_start_late && !busy_r) || frame_start_delayed; // when frame_start_delayed it will completely miss a frame_start_late
473 474 475
    assign xfer_reject = xfer_reject_r;
    assign  start_skip_w = skip_too_late && want_r && !xfer_grant && !skip_run &&
                          (((|page_cntr) && frame_start_pending) || ((page_cntr >= 4) && (cmd_wrmem || page_cntr[0]))); //&& busy_r && skip_run;
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    always @(posedge mclk) begin // Handling skip/reject
        if (mrst) xfer_reject_r <= 0;
        else      xfer_reject_r <= xfer_grant && !chn_rst && skip_run;

        if (mrst) xfer_start_r <= 0;
        else      xfer_start_r <= {xfer_start_r[1:0], (xfer_grant & ~chn_rst & ~skip_run) | start_skip_r};

        if (mrst) xfer_start_rd_r <= 0;
        else      xfer_start_rd_r <=  xfer_grant && !chn_rst && !cmd_wrmem && !skip_run;

        if (mrst) xfer_start_wr_r <= 0;
        else      xfer_start_wr_r <=  xfer_grant && !chn_rst && cmd_wrmem  && !skip_run;
        
        if (mrst || recalc_r[PAR_MOD_LATENCY-1]) skip_run <= 0;
        else if (start_skip_w)                   skip_run <= 1;
491

492 493 494
        if (mrst) start_skip_r <= 0;
        else      start_skip_r <= start_skip_w;
        
495 496
        if (mrst) xfer_skipped <= 0;
        else      xfer_skipped <= start_not_partial && skip_run;
497
            
498 499
//        if  (mrst || frame_start_delayed) frame_start_pending <= 0;
        if  (mrst) frame_start_pending <= 0;
500 501
//        else       frame_start_pending <= {frame_start_pending[0], busy_r && (frame_start_pending[0] | frame_start_late)};
        else       frame_start_pending <= busy_r && (frame_start_pending | frame_start_late);
502 503

        if  (mrst) frame_start_pending_long <= 0;
504
        else       frame_start_pending_long <= {frame_start_pending_long[0], (busy_r || skip_run) && (frame_start_pending_long[0] | frame_start_late)};
505 506

        if (mrst) frame_start_r <= 0;
507
//        else      frame_start_r <= {frame_start_r[3:0], frame_start_late & frame_en};
508 509 510 511 512 513
        else      frame_start_r <= {frame_start_r[3:0], frame_start_mod & frame_en};        

        if (mrst || disable_need)                         need_r <= 0;
        else if (chn_rst || xfer_grant || start_skip_r)   need_r <= 0;
        else if ((pre_want  || want_r) && (page_cntr>=3)) need_r <= 1; // may raise need if want was already set

514 515 516
        if (mrst)                                                  want_r <= 0;
        else if (chn_rst || xfer_grant || start_skip_r)            want_r <= 0;
        else if (pre_want && (page_cntr > {1'b0,cmd_extra_pages})) want_r <= 1;
517
        want_d <= want_r;        
518
        
519 520
    end    
    
521
/// Recalcualting just after starting request - preparing for the next one. Also happens after parameter change.
522
/// Should dppend only on the parameters updated separately (curr_x, curr_y)
523
    always @(posedge mclk) begin // TODO: Match latencies (is it needed?) Reduce consumption by CE?
524 525 526 527
        if (recalc_r[0]) begin // cycle 1
            frame_x <= curr_x + window_x0;
            frame_y <= curr_y + window_y0;
            next_y <= curr_y + 1;
Andrey Filippov's avatar
Andrey Filippov committed
528
            row_left <= window_width - curr_x; // 14 bits - 13 bits
529 530
        end
// registers to be absorbed in DSP block        
531 532 533 534 535
        frame_y8_r <= frame_y[FRAME_HEIGHT_BITS-1:3]; // lat=2
        frame_full_width_r <= frame_full_width;
        start_addr_r <= start_addr;
        mul_rslt <= mul_rslt_w[MPY_WIDTH-1:0]; // frame_y8_r * frame_width_r; // 7 bits will be discarded lat=3;
        line_start_addr <= start_addr_r+mul_rslt; // lat=4
Andrey Filippov's avatar
Andrey Filippov committed
536
        
537 538 539
// TODO: Verify MPY/register timing above        
        if (recalc_r[5]) begin // cycle 6
            row_col_r <= line_start_addr+frame_x;
Andrey Filippov's avatar
Andrey Filippov committed
540 541
//            line_start_page_left <= {COLADDR_NUMBER-3{1'b0}} - line_start_addr[COLADDR_NUMBER-4:0]; // 7 bits
            line_start_page_left <=  - line_start_addr[COLADDR_NUMBER-4:0]; // 7 bits
542
        end
543
        bank_reg[0 +:3]   <= frame_y[2:0]; //TODO: is it needed - a pipeline for the bank? - remove! 
544
        for (i=0;i<2; i = i+1)
545
            bank_reg[(i+1)*3 +:3] <= bank_reg[i * 3 +: 3];
546
            
Andrey Filippov's avatar
Andrey Filippov committed
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
            
        if (recalc_r[6]) begin // cycle 7
            mem_page_left <= {1'b1,line_start_page_left} - frame_x[COLADDR_NUMBER-4:0];
            
            lim_by_xfer <= (|row_left[FRAME_WIDTH_BITS:NUM_XFER_BITS])?
                (1<<NUM_XFER_BITS):
                row_left[NUM_XFER_BITS:0]; // 7 bits, max 'h40
        end
        if (recalc_r[7]) begin // cycle 8
            xfer_limited_by_mem_page_r <= xfer_limited_by_mem_page && !continued_xfer;     
            xfer_num128_r<= continued_xfer?
                {EXTRA_BITS,leftover}:
                (xfer_limited_by_mem_page?
                     mem_page_left[NUM_XFER_BITS:0]:
                     lim_by_xfer[NUM_XFER_BITS:0]);
            //xfer_num128_r depends on leftover only if continued_xfer (after first shortened actual xfer and will not change w/o xfers)
            // and (next) leftover is only set  if continued_xfer==0, so multiple runs without chnge of continued_xfer will not differ       
            if (!continued_xfer) leftover <= remainder_in_xfer[NUM_XFER_BITS-1:0]; //  {EXTRA_BITS, lim_by_xfer}-mem_page_left;
        end
        
        if (recalc_r[8]) begin // cycle 9
            last_in_row <= last_in_row_w; //(row_left=={{(FRAME_WIDTH_BITS-NUM_XFER_BITS){1'b0}},xfer_num128_r});
        end
            
            
572
    end
573
wire    start_not_partial= xfer_start_r[0] && !xfer_limited_by_mem_page_r;    
574 575
// now have row start address, bank and row_left ;
// calculate number to read (min of row_left, maximal xfer and what is left in the DDR3 page    
Andrey Filippov's avatar
Andrey Filippov committed
576
    always @(posedge mclk) begin
577
        // acceletaring pre_want
578 579 580
        
//        pre_want_r1 <= chn_en &&  !frame_done_r && busy_r && par_mod_r[PAR_MOD_LATENCY-2] && !(|frame_start_r[4:1]) && !last_block;
        //last_block is too late for pre_want_r1, moving upsteram
581 582
//        pre_want_r1 <= chn_en &&  !frame_done_r && busy_r && par_mod_r[PAR_MOD_LATENCY-2] && !(|frame_start_r[4:1]);
        pre_want_r1 <= !chn_rst &&  !frame_done_r && busy_r && par_mod_r[PAR_MOD_LATENCY-2] && !(|frame_start_r[4:1]);
Andrey Filippov's avatar
Andrey Filippov committed
583
        if      (mrst)                par_mod_r<=0;
584 585 586 587 588
        else if (pgm_param_w ||
                 xfer_start_r[0] ||
                 chn_rst ||
                 frame_start_r[0])    par_mod_r<=0;
        else                          par_mod_r <= {par_mod_r[PAR_MOD_LATENCY-2:0], 1'b1};
589

Andrey Filippov's avatar
Andrey Filippov committed
590
        if      (mrst)         chn_rst_d <= 0;
591 592
        else                   chn_rst_d <= chn_rst;

Andrey Filippov's avatar
Andrey Filippov committed
593
        if      (mrst)         recalc_r<=0;
594
        else if (chn_rst)      recalc_r<=0;
595
        else                   recalc_r <= {recalc_r[PAR_MOD_LATENCY-2:0],
596
             ((xfer_start_r[0] | frame_start_r[0]) & ~chn_rst) | pgm_param_w | (chn_rst_d & ~chn_rst)};
597
        
Andrey Filippov's avatar
Andrey Filippov committed
598
        if      (mrst)              busy_r <= 0;
599 600 601
        else if (chn_rst)           busy_r <= 0;
        else if (frame_start_r[0])  busy_r <= 1;
        else if (frame_done_r)      busy_r <= 0;
602
        
Andrey Filippov's avatar
Andrey Filippov committed
603
        if (mrst)         xfer_done_d <= 0;
604
        else              xfer_done_d <= xfer_done_skipped;
605
        
606
        
Andrey Filippov's avatar
Andrey Filippov committed
607
        if (mrst)                   continued_xfer <= 1'b0;
608 609 610
        else if (chn_rst)           continued_xfer <= 1'b0;
        else if (frame_start_r[0])  continued_xfer <= 1'b0;
        else if (xfer_start_r[0])   continued_xfer <= xfer_limited_by_mem_page_r; // only set after actual start if it was partial, not after parameter change
611

612
        // single cycle (sent out), will alos reset busy, set frame_finished, ...
Andrey Filippov's avatar
Andrey Filippov committed
613
        if (mrst)         frame_done_r <= 0;
614 615 616 617 618 619 620
//        else              frame_done_r <= busy_r && (last_block || aborting_r) && xfer_done_d && (pending_xfers==0);
        else              frame_done_r <= busy_r && (pending_xfers==0) &&
                                         ((last_block && xfer_done_d) || (aborting_r && !want_r && !want_d));
        
        if      (!busy_r)                           aborting_r <= 0;
        else if (abort_en && busy_r && frame_start) aborting_r <= 1; // Early frame start, not delayed
        
621
        // turns and stays on (used in status)
Andrey Filippov's avatar
Andrey Filippov committed
622
        if (mrst)                             frame_finished_r <= 0;
623 624
        else if (chn_rst || frame_start_r[0]) frame_finished_r <= 0;
        else if (frame_done_r)                frame_finished_r <= 1;
625
        
626
        
627 628 629
//        if (mrst || disable_need)                         need_r <= 0;
//        else if (chn_rst || xfer_grant || start_skip_r)   need_r <= 0;
//        else if ((pre_want  || want_r) && (page_cntr>=3)) need_r <= 1; // may raise need if want was already set
630

631 632 633
//        if (mrst)                                                want_r <= 0;
//        else if (chn_rst || xfer_grant || start_skip_r)          want_r <= 0;
//        else if (pre_want && (page_cntr>{1'b0,cmd_extra_pages})) want_r <= 1;
634
        
Andrey Filippov's avatar
Andrey Filippov committed
635
        if (mrst)                                  page_cntr <= 0;
636
        else if (frame_start_r[0])                 page_cntr <= cmd_wrmem?0:4; // What about last pages (like if only 1 page is needed)? Early frame end?
637 638
        else if ( start_not_partial && !next_page) page_cntr <= page_cntr - 1;     
        else if (!start_not_partial &&  next_page) page_cntr <= page_cntr + 1;
639
        
Andrey Filippov's avatar
Andrey Filippov committed
640
        if (mrst) xfer_page_rst_r <= 1;
641
        else      xfer_page_rst_r <= chn_rst || (buf_reset_pend && (MCNTRL_SCANLINE_FRAME_PAGE_RESET ? (frame_start_r[0] & cmd_wrmem):1'b0));
642

Andrey Filippov's avatar
Andrey Filippov committed
643
        if (mrst) xfer_page_rst_pos <= 1;
644
        else      xfer_page_rst_pos <= chn_rst || (buf_reset_pend && (MCNTRL_SCANLINE_FRAME_PAGE_RESET ? (frame_start_r[0] & ~cmd_wrmem):1'b0));
645

646 647
        
// increment x,y (two cycles)
648
        if (mrst)                                 curr_x <= 0;
649
        else if (chn_rst || frame_start_r[0])     curr_x <= start_x;
650 651
        else if (xfer_start_r[0])                 curr_x <= last_in_row?0: curr_x + xfer_num128_r;
        
652
        if (mrst)                                 curr_y <= 0;
653
        else if (chn_rst || frame_start_r[0])     curr_y <= start_y;
654 655
        else if (xfer_start_r[0] && last_in_row)  curr_y <= next_y[FRAME_HEIGHT_BITS-1:0];
               
656 657 658
        if      (mrst)                            last_block <= 0;
        else if (chn_rst || !busy_r)              last_block <= 0;
        else if (xfer_start_r[0])                 last_block <= last_row_w && last_in_row_w;
659
        
660 661 662 663
        if      (mrst)                                   pending_xfers <= 0;
        else if (chn_rst || !busy_r)                     pending_xfers <= 0;
        else if ( xfer_start_r[0] && !xfer_done_skipped) pending_xfers <= pending_xfers + 1;     
        else if (!xfer_start_r[0] &&  xfer_done_skipped) pending_xfers <= pending_xfers - 1;
664
        
665 666
        if (recalc_r[0]) line_unfinished_relw_r <= curr_y + (cmd_wrmem ? 0: 1);
        
667
//        if (mrst || (frame_start_late || !chn_en))  line_unfinished_r <= {FRAME_HEIGHT_BITS{~cmd_wrmem}}; // lowest/highest value until valid
668 669
        if (mrst || (frame_start_mod || chn_dis_delayed))  line_unfinished_r <= {FRAME_HEIGHT_BITS{~cmd_wrmem}}; // lowest/highest value until valid
        else if (recalc_r[2])                              line_unfinished_r <= line_unfinished_relw_r + window_y0;
670 671


672
    end
673 674 675
    always @ (negedge mclk) begin
        xfer_page_rst_neg <= xfer_page_rst_pos;
    end
676 677 678 679 680 681 682
    cmd_deser #(
        .ADDR       (MCNTRL_SCANLINE_ADDR),
        .ADDR_MASK  (MCNTRL_SCANLINE_MASK),
        .NUM_CYCLES (6),
        .ADDR_WIDTH (4),
        .DATA_WIDTH (32)
    ) cmd_deser_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
683 684 685 686 687 688 689 690
        .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[15:0] 
        .data       (cmd_data),  // output[31:0] 
        .we         (cmd_we)     // output
691
    );
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  `ifdef DEBUG_SENS_MEM_PAGES   
      reg [1:0] dbg_cnt_snp;
      reg [1:0] dbg_nxt_page;
      reg       dbg_busy_r2;
      reg       dbg_pre_want_r1;
      reg [1:0] dbg_busy; // busy is toggling
      reg [1:0] dbg_prewant; // pre_want_r1 is toggling
      
      //        else if (!start_not_partial &&  next_page) page_cntr <= page_cntr + 1;
      always @ (posedge mclk) begin
        if      (mrst)              dbg_cnt_snp <= 0;
        else if (start_not_partial) dbg_cnt_snp <= dbg_cnt_snp + 1;

        if      (mrst)              dbg_nxt_page <= 0;
        else if (next_page)         dbg_nxt_page <= dbg_nxt_page + 1;
707

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
        if      (mrst)              dbg_nxt_page <= 0;
        else if (next_page)         dbg_nxt_page <= dbg_nxt_page + 1;
        
        dbg_busy_r2 <= busy_r;
        dbg_pre_want_r1 <=pre_want_r1;
        
        if      (mrst)                   dbg_busy <= 0;
        else if (busy_r && !dbg_busy_r2) dbg_busy <=  dbg_busy + 1;

        if      (mrst)                            dbg_prewant <= 0;
        else if (pre_want_r1 && !dbg_pre_want_r1) dbg_prewant <=  dbg_prewant + 1;
      end
      
  `endif
    
723 724
    status_generate #(
        .STATUS_REG_ADDR  (MCNTRL_SCANLINE_STATUS_REG_ADDR),
725 726 727
  `ifdef DEBUG_SENS_MEM_PAGES   
        .PAYLOAD_BITS     (2 + 2 +2 + 2 + 2 + 2 +2 + 3 + 3 + MCNTRL_SCANLINE_PENDING_CNTR_BITS)
  `else   
728 729
    `ifdef DEBUG_MCNTRL_LINEAR_EXTRA_STATUS    
        .PAYLOAD_BITS     (12)
730 731 732 733
    `else
      `ifdef REPORT_FRAME_NUMBER
        .PAYLOAD_BITS     (2 + LAST_FRAME_BITS)
      `else
734
        .PAYLOAD_BITS     (2)
735
      `endif  
736
    `endif    
737
  `endif   
738
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
739 740 741 742
        .rst              (1'b0),          //rst), // input
        .clk              (mclk),          // input
        .srst             (mrst),          // input
        .we               (set_status_w),  // input
743
        .wd               (cmd_data[7:0]), // input[7:0] 
744 745 746 747 748 749 750 751
  `ifdef DEBUG_SENS_MEM_PAGES   
        .status           ({frame_en,        page_cntr[2:0],   
                           dbg_prewant[1:0], dbg_busy[1:0],
                           single_frame_r, repeat_frames, dbg_cnt_snp[1:0],
                           dbg_nxt_page[1:0], pending_xfers[1:0],
                           dbg_wpage[1:0], dbg_rpage[1:0],
                           status_data}),   // input[25:0] 
  `else   
Andrey Filippov's avatar
Andrey Filippov committed
752
        .status           (status_data),   // input[25:0] 
753
  `endif   
Andrey Filippov's avatar
Andrey Filippov committed
754 755 756
        .ad               (status_ad),     // output[7:0] 
        .rq               (status_rq),     // output
        .start            (status_start)   // input
757 758 759
    );
endmodule