mcntrl_linear_rw.v 36.7 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: mcntrl_linear_rw
 * Date:2015-01-29  
4
 * Author: Andrey Filippov     
5 6 7
 * Description: Organize paged R/W from DDR3 memory in scan-line order
 * with window support
 *
8
 * Copyright (c) 2015 Elphel, Inc.
9 10 11 12 13 14 15 16 17 18 19 20
 * 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/> .
21 22 23 24 25 26
 *
 * 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"
27
 * files and/or simulating the code, the copyright holders of this Program give
28 29
 * 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
30
 * charge, and there is no dependence on any encrypted modules for simulating of
31 32 33
 * 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.
34 35
 *******************************************************************************/
`timescale 1ns/1ps
36
// TODO: ADD MCNTRL_SCANLINE_FRAME_PAGE_RESET to caller
37 38 39 40 41
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 
42
    parameter FRAME_HEIGHT_BITS=                16,    // Maximal frame height
43
    parameter LAST_FRAME_BITS=                  16,     // number of bits in frame counter (before rolls over)
44
    parameter MCNTRL_SCANLINE_ADDR=            'h120,
45
    parameter MCNTRL_SCANLINE_MASK=            'h7f0, // both channels 0 and 1
46
    parameter MCNTRL_SCANLINE_MODE=            'h0,   // set mode register: {repet,single,rst_frame,na[2:0],extra_pages[1:0],write_mode,enable,!reset}
47 48
    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)
49 50 51 52 53 54
    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
55 56
                                                      // 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?
57
                                                      // Read back current address (for debugging)?
58
    parameter MCNTRL_SCANLINE_STATUS_REG_ADDR= 'h4,
59
    parameter MCNTRL_SCANLINE_PENDING_CNTR_BITS=2,     // Number of bits to count pending trasfers, currently 2 is enough, but may increase
60 61 62
                                                      // 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
63 64 65 66 67 68 69 70 71
    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 
72 73 74
    parameter MCONTR_LINTILE_REPEAT =          10, // read/write pages until disabled 
    parameter MCONTR_LINTILE_DIS_NEED =        11, // disable 'need' request 
    parameter MCONTR_LINTILE_SKIP_LATE =       12  // skip actual R/W operation when it is too late, advance pointers
75
)(
Andrey Filippov's avatar
Andrey Filippov committed
76
    input                          mrst,
77 78 79 80 81 82 83 84 85 86 87 88 89
    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
    
    output                   [7:0] status_ad,     // byte-wide address/data
    output                         status_rq,     // request to send downstream (last byte with rq==0)
    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)
    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
90
    output                         frame_finished,// turns on and stays on after frame_done
91
// optional I/O for channel synchronization
92 93
// 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?. 
94
    input                          suspend,       // suspend transfers (from external line number comparator)
95
    output   [LAST_FRAME_BITS-1:0] frame_number,  // current frame number (for multi-frame ranges)
96 97 98
    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 
99
    output                         xfer_reject,   // reject granted access (when skipping)
100 101
    output                         xfer_start_rd, // initiate a transfer (next cycle after xfer_grant)
    output                         xfer_start_wr, // initiate a transfer (next cycle after xfer_grant)
102 103 104 105
    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)
106
    output                         xfer_partial,  // partial tile (first of 2) , sequencer will not generate page_next at the end of block   
107
    input                          xfer_done,     // transfer to/from the buffer finished
108
    output                         xfer_page_rst_wr, // reset buffer internal page - at each frame start or when specifically reset (write to memory channel), @posedge
109
    output                         xfer_page_rst_rd, // reset buffer internal page - at each frame start or when specifically reset (read memory channel), @negedge
110
    output reg                     xfer_skipped,
111
    output                         cmd_wrmem
112 113 114
);
    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
115
    localparam PAR_MOD_LATENCY=  9; // TODO: Find actual worst-case latency for:
116 117 118
    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
119
    reg   [NUM_RC_BURST_BITS-1:0] line_start_addr;// (calculated) Line start (in {row,col8} in burst8
120
 // calculating full width from the frame width
121 122 123
// 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
124 125 126 127
`ifndef IGNORE_ATTR
    (* keep = "true" *)
`endif    
    reg   [FRAME_HEIGHT_BITS-1:0] frame_y;     // current line number referenced to the frame top
128 129 130 131 132
    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
133 134
//    reg                     [2:0] bank_reg [2:0];
    reg             [3 * 3 - 1:0] bank_reg;
135 136 137 138
    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
139
    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
140
    reg         [NUM_XFER_BITS:0] lim_by_xfer;   // number of bursts left limited by the longest transfer (currently 64)
141 142 143 144 145 146 147
//    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
    
    
    
148
    reg         [NUM_XFER_BITS:0] xfer_num128_r;   // number of 128-bit words to transfer (8*16 bits) - full bursts of 8
149
//    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
150
    wire                          pgm_param_w;  // program one of the parameters, invalidate calculated results for PAR_MOD_LATENCY
151 152 153
    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;
154
    reg     [PAR_MOD_LATENCY-1:0] par_mod_r;
155
    reg     [PAR_MOD_LATENCY-1:0] recalc_r; // 1-hot CE for re-calculating registers
156
    wire                          calc_valid;   // calculated registers have valid values   
157
    wire                          chn_en;   // enable requests by channel (continue ones in progress), enable frame_start inputs
158
    wire                          chn_rst; // resets command, including fifo;
159
    reg                           chn_rst_d; // delayed by 1 cycle do detect turning off
160 161 162 163 164
//    reg                           xfer_reset_page_r;
    reg                           xfer_page_rst_r=1;
    reg                           xfer_page_rst_pos=1;  
    reg                           xfer_page_rst_neg=1;  
    
165 166
    reg                     [2:0] page_cntr;
    
167
//    wire                          cmd_wrmem; //=MCNTRL_SCANLINE_WRITE_MODE; // 0: read from memory, 1:write to memory
168
    wire                    [1:0] cmd_extra_pages; // external module needs more than 1 page
169
    wire                          skip_too_late;
170
    wire                          disable_need; // do not assert need, only want
171 172 173 174
    wire                          repeat_frames; // mode bit
    wire                          single_frame_w; // pulse
    wire                          rst_frame_num_w;
    reg                           single_frame_r;  // pulse
175
    reg                     [1:0] rst_frame_num_r; // reset frame number/next start address
176 177
    reg                           frame_en;       // enable next frame
    
178 179 180 181
    reg                           busy_r;
    reg                           want_r;
    reg                           need_r;
    reg                           frame_done_r;
182
    reg                           frame_finished_r;    
183 184 185 186 187
    wire                          last_in_row_w;
    wire                          last_row_w;
    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;
188 189 190 191
//    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;
    
192
    wire                          pre_want;
193
    reg                           pre_want_r1;
194 195 196 197 198 199 200 201
    wire                    [1:0] status_data;
    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;
202 203
    wire                          set_frame_size_w;
    wire                          set_last_frame_w;
204 205 206 207
    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
208 209
    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
210 211
      
    
212
    reg                    [12:0] mode_reg;//mode register: {dis_need,repet,single,rst_frame,na[2:0],extra_pages[1:0],write_mode,enable,!reset}
213 214 215 216
    
    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; 
217
    reg   [NUM_RC_BURST_BITS-1:0] start_addr;     // (programmed) Frame start (in {row,col8} in burst8, bank ==0
218 219
    reg   [NUM_RC_BURST_BITS-1:0] next_frame_start_addr;
    reg     [LAST_FRAME_BITS-1:0] frame_number_cntr;
220 221
    reg     [LAST_FRAME_BITS-1:0] frame_number_current;
    
222
    reg                           is_last_frame;
223 224
//    reg                     [2:0] frame_start_r;
    reg                     [4:0] frame_start_r; // increased length to have time from line_unfinished to suspend (external)
225 226 227 228 229 230 231 232 233 234
    
    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
    reg    [FRAME_WIDTH_BITS-1:0] start_x;        // (programmed) normally 0, copied to curr_x on frame_start  
    reg   [FRAME_HEIGHT_BITS-1:0] start_y;        // (programmed) normally 0, copied to curr_y on frame_start 
235
    reg                           xfer_done_d;    // xfer_done delayed by 1 cycle (also includes xfer_skipped)
236
    assign frame_number =       frame_number_current;
237
    
238 239 240
    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);
241 242
    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);
243 244 245 246
    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);
247
    
248 249
    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];
250
    
251
    // Set parameter registers
Andrey Filippov's avatar
Andrey Filippov committed
252 253
    always @(posedge mclk) begin
        if      (mrst)               mode_reg <= 0;
254
        else if (set_mode_w)         mode_reg <= cmd_data[12:0]; // 4:0]; // [4:0];
255

Andrey Filippov's avatar
Andrey Filippov committed
256 257
        if (mrst) single_frame_r <= 0;
        else      single_frame_r <= single_frame_w;
258
        
Andrey Filippov's avatar
Andrey Filippov committed
259 260
        if (mrst) rst_frame_num_r <= 0;
        else      rst_frame_num_r <= {rst_frame_num_r[0],
261 262 263 264 265
                                     rst_frame_num_w |
                                     set_start_addr_w |
                                     set_last_frame_w |
                                     set_frame_size_w};

Andrey Filippov's avatar
Andrey Filippov committed
266
        if      (mrst)               start_range_addr <= 0;
267 268
        else if (set_start_addr_w)   start_range_addr <= cmd_data[NUM_RC_BURST_BITS-1:0];

Andrey Filippov's avatar
Andrey Filippov committed
269
        if      (mrst)               frame_size <= 0;
270 271
        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];
272

Andrey Filippov's avatar
Andrey Filippov committed
273
        if      (mrst)             last_frame_number <= 0;
274 275
        else if (set_last_frame_w) last_frame_number <= cmd_data[LAST_FRAME_BITS-1:0];
        
Andrey Filippov's avatar
Andrey Filippov committed
276
        if      (mrst)              frame_full_width <=  0;
Andrey Filippov's avatar
Andrey Filippov committed
277
        else if (set_frame_width_w) frame_full_width <= {lsw13_zero,cmd_data[FRAME_WIDTH_BITS-1:0]};
278
        
Andrey Filippov's avatar
Andrey Filippov committed
279 280
        if (mrst) is_last_frame <= 0;
        else      is_last_frame <= frame_number_cntr == last_frame_number;
281
        
282 283
//        if (mrst) frame_start_r <= 0;
//        else      frame_start_r <= {frame_start_r[3:0], frame_start & frame_en};
284

Andrey Filippov's avatar
Andrey Filippov committed
285
        if      (mrst)                            frame_en <= 0;
286 287 288
        else if (single_frame_r || repeat_frames) frame_en <= 1;
        else if (frame_start)                     frame_en <= 0;
        
Andrey Filippov's avatar
Andrey Filippov committed
289
        if      (mrst)               frame_number_cntr <= 0;
290 291 292
        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
293
        if      (mrst)               frame_number_current <= 0;
294 295 296
        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
297
        if      (mrst)               next_frame_start_addr <= start_range_addr; // just to use rst
298 299 300
        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
301
        if      (mrst)               start_addr <= start_range_addr; // just to use rst
302 303
        else if (frame_start_r[0])   start_addr <= next_frame_start_addr;
        
Andrey Filippov's avatar
Andrey Filippov committed
304
        if      (mrst) begin
305 306 307 308 309 310 311
               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
312
        if      (mrst) begin
313 314 315 316 317 318 319
               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
320
        if      (mrst) begin
321 322 323 324 325 326 327 328 329
               start_x <= 0; 
               start_y <=  0;
        end else if (set_window_start_w)  begin
               start_x <= cmd_data[FRAME_WIDTH_BITS-1:0];
               start_y  <=cmd_data[FRAME_HEIGHT_BITS+15:16];
        end
    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];
330 331
    assign xfer_start_rd=  xfer_start_rd_r;
    assign xfer_start_wr=  xfer_start_wr_r;
332
    assign calc_valid=  par_mod_r[PAR_MOD_LATENCY-1]; // MSB, longest 0
333 334 335
    assign xfer_page_rst_wr=  xfer_page_rst_r;
    assign xfer_page_rst_rd=  xfer_page_rst_neg;
    
336 337
    assign xfer_partial=      xfer_limited_by_mem_page_r;
    
338
    assign frame_done=  frame_done_r;
339 340
    assign frame_finished=  frame_finished_r;
    
341 342 343
//    assign pre_want=    chn_en && busy_r && !want_r && !xfer_start_r[0] && calc_valid && !last_block && !suspend && !(|frame_start_r);
    // accelerating pre_want:
    assign pre_want= pre_want_r1 && !want_r && !xfer_start_r[0] && !suspend ;
344

345 346 347 348
    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;
349
    assign xfer_bank=   bank_reg[3 * 2 +: 3]; // TODO: just a single reg layer
350 351
    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
352
    assign line_unfinished = line_unfinished_r; // [FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS];
353 354 355 356 357
    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];
358
    assign disable_need =    mode_reg[MCONTR_LINTILE_DIS_NEED];
359
    assign skip_too_late =   mode_reg[MCONTR_LINTILE_SKIP_LATE];
360
    assign status_data= {frame_finished_r, busy_r};     // TODO: Add second bit?
361
    assign pgm_param_w=      cmd_we;
362 363
    localparam [COLADDR_NUMBER-3-NUM_XFER_BITS-1:0] EXTRA_BITS=0;
    assign remainder_in_xfer = {EXTRA_BITS, lim_by_xfer}-mem_page_left;
364 365
    
    integer i;
366
    wire xfer_limited_by_mem_page= mem_page_left < {EXTRA_BITS,lim_by_xfer};
367
    reg  xfer_limited_by_mem_page_r;
368 369 370 371 372
//  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 
373 374 375 376 377 378 379
    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;
    reg          frame_start_pending; // frame_start came before previous one was finished
    reg    [1:0] frame_start_pending_long;
    wire         xfer_done_skipped = xfer_skipped || xfer_done;
380
    
381 382 383 384 385
    wire         frame_start_delayed = frame_start_pending_long[1] && !frame_start_pending_long[0];
    wire         frame_start_mod = (frame_start && !busy_r) || frame_start_delayed; // when frame_start_delayed it will completely miss a frame_start
    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;
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    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;
402

403 404 405
        if (mrst) start_skip_r <= 0;
        else      start_skip_r <= start_skip_w;
        
406 407
        if (mrst) xfer_skipped <= 0;
        else      xfer_skipped <= start_not_partial && skip_run;
408
            
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
//        if  (mrst || frame_start_delayed) frame_start_pending <= 0;
        if  (mrst) frame_start_pending <= 0;
//        else       frame_start_pending <= {frame_start_pending[0], busy_r && (frame_start_pending[0] | frame_start)};
        else       frame_start_pending <= busy_r && (frame_start_pending | frame_start);

        if  (mrst) frame_start_pending_long <= 0;
        else       frame_start_pending_long <= {frame_start_pending_long[0], (busy_r || skip_run) && (frame_start_pending_long[0] | frame_start)};

        if (mrst) frame_start_r <= 0;
//        else      frame_start_r <= {frame_start_r[3:0], frame_start & frame_en};
        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

425 426 427
        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;
428
        
429 430
    end    
    
431
/// Recalcualting just after starting request - preparing for the next one. Also happens after parameter change.
432
/// Should dppend only on the parameters updated separately (curr_x, curr_y)
433
    always @(posedge mclk) begin // TODO: Match latencies (is it needed?) Reduce consumption by CE?
434 435 436 437
        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
438
            row_left <= window_width - curr_x; // 14 bits - 13 bits
439 440
        end
// registers to be absorbed in DSP block        
441 442 443 444 445
        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
446
        
447 448 449
// 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
450 451
//            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
452
        end
453
        bank_reg[0 +:3]   <= frame_y[2:0]; //TODO: is it needed - a pipeline for the bank? - remove! 
454
        for (i=0;i<2; i = i+1)
455
            bank_reg[(i+1)*3 +:3] <= bank_reg[i * 3 +: 3];
456
            
Andrey Filippov's avatar
Andrey Filippov committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
            
        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
            
            
482
    end
483
wire    start_not_partial= xfer_start_r[0] && !xfer_limited_by_mem_page_r;    
484 485
// 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
486
    always @(posedge mclk) begin
487 488 489
        // acceletaring pre_want
        pre_want_r1 <= chn_en &&  !frame_done_r && busy_r && par_mod_r[PAR_MOD_LATENCY-2] && !(|frame_start_r[4:1]) && !last_block;
    
Andrey Filippov's avatar
Andrey Filippov committed
490
        if      (mrst)                par_mod_r<=0;
491 492 493 494 495
        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};
496

Andrey Filippov's avatar
Andrey Filippov committed
497
        if      (mrst)         chn_rst_d <= 0;
498 499
        else                   chn_rst_d <= chn_rst;

Andrey Filippov's avatar
Andrey Filippov committed
500
        if      (mrst)         recalc_r<=0;
501
        else if (chn_rst)      recalc_r<=0;
502
        else                   recalc_r <= {recalc_r[PAR_MOD_LATENCY-2:0],
503
             ((xfer_start_r[0] | frame_start_r[0]) & ~chn_rst) | pgm_param_w | (chn_rst_d & ~chn_rst)};
504
        
Andrey Filippov's avatar
Andrey Filippov committed
505
        if      (mrst)              busy_r <= 0;
506 507 508
        else if (chn_rst)           busy_r <= 0;
        else if (frame_start_r[0])  busy_r <= 1;
        else if (frame_done_r)      busy_r <= 0;
509
        
Andrey Filippov's avatar
Andrey Filippov committed
510
        if (mrst)         xfer_done_d <= 0;
511
        else              xfer_done_d <= xfer_done_skipped;
512
        
513
        
Andrey Filippov's avatar
Andrey Filippov committed
514
        if (mrst)                   continued_xfer <= 1'b0;
515 516 517
        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
518

519
        // single cycle (sent out)
Andrey Filippov's avatar
Andrey Filippov committed
520
        if (mrst)         frame_done_r <= 0;
521
        else              frame_done_r <= busy_r && last_block && xfer_done_d && (pending_xfers==0);
522

523
        // turns and stays on (used in status)
Andrey Filippov's avatar
Andrey Filippov committed
524
        if (mrst)                             frame_finished_r <= 0;
525 526
        else if (chn_rst || frame_start_r[0]) frame_finished_r <= 0;
        else if (frame_done_r)                frame_finished_r <= 1;
527
        
528
        
529 530 531
//        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
532

533 534 535
//        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;
536
        
Andrey Filippov's avatar
Andrey Filippov committed
537
        if (mrst)                                  page_cntr <= 0;
538
        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?
539 540
        else if ( start_not_partial && !next_page) page_cntr <= page_cntr - 1;     
        else if (!start_not_partial &&  next_page) page_cntr <= page_cntr + 1;
541
        
Andrey Filippov's avatar
Andrey Filippov committed
542 543
        if (mrst) xfer_page_rst_r <= 1;
        else      xfer_page_rst_r <= chn_rst || (MCNTRL_SCANLINE_FRAME_PAGE_RESET ? (frame_start_r[0] & cmd_wrmem):1'b0);
544

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

548 549
        
// increment x,y (two cycles)
550
        if (mrst)                                 curr_x <= 0;
551
        else if (chn_rst || frame_start_r[0])     curr_x <= start_x;
552 553
        else if (xfer_start_r[0])                 curr_x <= last_in_row?0: curr_x + xfer_num128_r;
        
554
        if (mrst)                                 curr_y <= 0;
555
        else if (chn_rst || frame_start_r[0])     curr_y <= start_y;
556 557
        else if (xfer_start_r[0] && last_in_row)  curr_y <= next_y[FRAME_HEIGHT_BITS-1:0];
               
558 559 560
        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;
561
        
562 563 564 565
        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;
566
        
567 568
        if (recalc_r[0]) line_unfinished_relw_r <= curr_y + (cmd_wrmem ? 0: 1);
        
569 570 571
//        if (mrst || (frame_start || !chn_en))  line_unfinished_r <= {FRAME_HEIGHT_BITS{~cmd_wrmem}}; // lowest/highest value until valid
        if (mrst || (frame_start_mod || !chn_en))  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;
572 573


574
    end
575 576 577
    always @ (negedge mclk) begin
        xfer_page_rst_neg <= xfer_page_rst_pos;
    end
578 579 580 581 582 583 584
    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
585 586 587 588 589 590 591 592
        .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
593 594 595 596 597 598
    );

    status_generate #(
        .STATUS_REG_ADDR  (MCNTRL_SCANLINE_STATUS_REG_ADDR),
        .PAYLOAD_BITS     (2)
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
599 600 601 602
        .rst              (1'b0),          //rst), // input
        .clk              (mclk),          // input
        .srst             (mrst),          // input
        .we               (set_status_w),  // input
603
        .wd               (cmd_data[7:0]), // input[7:0] 
Andrey Filippov's avatar
Andrey Filippov committed
604 605 606 607
        .status           (status_data),   // input[25:0] 
        .ad               (status_ad),     // output[7:0] 
        .rq               (status_rq),     // output
        .start            (status_start)   // input
608 609 610
    );
endmodule