mcntrl_tiled_rw.v 39.1 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: mcntrl_tiled_rw
 * Date:2015-02-03  
4
 * Author: Andrey Filippov     
5 6
 * Description:  Organize paged R/W from DDR3 memory in tiled order
 * with window support
7 8
 * Tiles spreading over two different frames is not yet supported (needed for
 * line-scan mode in JPEG (JP4 - OK)
9
 *
10
 * Copyright (c) 2015 Elphel, Inc.
11 12 13 14 15 16 17 18 19 20 21 22
 * mcntrl_tiled_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_tiled_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/> .
23 24 25 26 27 28
 *
 * 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"
29
 * files and/or simulating the code, the copyright holders of this Program give
30 31
 * 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
32
 * charge, and there is no dependence on any encrypted modules for simulating of
33 34 35
 * 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.
36 37 38 39
 *******************************************************************************/
`timescale 1ns/1ps

module  mcntrl_tiled_rw#(
40
    parameter ADDRESS_NUMBER=                   15,
41 42 43
    parameter COLADDR_NUMBER=                   10,
    parameter FRAME_WIDTH_BITS=                 13,    // Maximal frame width - 8-word (16 bytes) bursts 
    parameter FRAME_HEIGHT_BITS=                16,    // Maximal frame height 
44 45
    parameter MAX_TILE_WIDTH=                   6,     // number of bits to specify maximal tile (width-1) (6 -> 64)
    parameter MAX_TILE_HEIGHT=                  6,     // number of bits to specify maximal tile (height-1) (6 -> 64)
46
    parameter LAST_FRAME_BITS=                 16,     // number of bits in frame counter (before rolls over)
47
    parameter MCNTRL_TILED_ADDR=            'h120,
48
    parameter MCNTRL_TILED_MASK=            'h7f0, // both channels 0 and 1
49
    parameter MCNTRL_TILED_MODE=            'h0,   // set mode register: {byte32,keep_open,extra_pages[1:0],write_mode,enable,!reset}
50 51
    parameter MCNTRL_TILED_STATUS_CNTRL=    'h1,   // control status reporting
    parameter MCNTRL_TILED_STARTADDR=       'h2,   // 22-bit frame start address (3 CA LSBs==0. BA==0)
52 53 54 55 56 57
    parameter MCNTRL_TILED_FRAME_SIZE=      'h3,   // 22-bit frame start address increment (3 CA LSBs==0. BA==0)
    parameter MCNTRL_TILED_FRAME_LAST=      'h4,   // 16-bit last frame number in the buffer
    parameter MCNTRL_TILED_FRAME_FULL_WIDTH='h5,   // Padded line length (8-row increment), in 8-bursts (16 bytes)
    parameter MCNTRL_TILED_WINDOW_WH=       'h6,   // low word - 13-bit window width (0->'h4000), high word - 16-bit frame height (0->'h10000)
    parameter MCNTRL_TILED_WINDOW_X0Y0=     'h7,   // low word - 13-bit window left, high word - 16-bit window top
    parameter MCNTRL_TILED_WINDOW_STARTXY=  'h8,   // low word - 13-bit start X (relative to window), high word - 16-bit start y
58 59
                                                      // 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?
60
                                                      // Read back current address (for debugging)?
61
    parameter MCNTRL_TILED_TILE_WHS=        'h9,   // low byte - 6-bit tile width in 8-bursts, second byte - tile height (0 - > 64),
62
                                                   // 3-rd byte - vertical step (to control tile vertical overlap)
63
    parameter MCNTRL_TILED_STATUS_REG_ADDR= 'h5,
64 65 66 67
    parameter MCNTRL_TILED_PENDING_CNTR_BITS=2,    // Number of bits to count pending trasfers, currently 2 is enough, but may increase
                                                   // 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
68 69 70 71 72 73 74 75 76 77 78
    parameter MCNTRL_TILED_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_KEEP_OPEN =     5, // keep banks open (will be used only if number of rows <= 8)
    parameter MCONTR_LINTILE_BYTE32 =        6, // use 32-byte wide columns in each tile (false - 16-byte) 
    parameter MCONTR_LINTILE_RST_FRAME =     8, // reset frame number 
    parameter MCONTR_LINTILE_SINGLE =        9, // read/write a single page 
79 80 81
    parameter MCONTR_LINTILE_REPEAT =       10,  // read/write pages until disabled
    parameter MCONTR_LINTILE_DIS_NEED =     11   // disable 'need' request 
     
82
)(
Andrey Filippov's avatar
Andrey Filippov committed
83
    input                          mrst,
84 85 86 87 88 89 90 91 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
    
    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
97
    output                         frame_finished,// turns on and stays on after frame_done
98
// optional I/O for channel synchronization
99 100
// 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. 
101
    input                          suspend,       // suspend transfers (from external line number comparator)
102
    output   [LAST_FRAME_BITS-1:0] frame_number,  // current frame number (for multi-frame ranges)
103 104 105
    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 
106 107 108 109 110
//    output                         xfer_start,    // initiate a transfer (next cycle after xfer_grant), following signals (up to xfer_partial) are valid
    output                         xfer_start_rd,    // initiate a transfer (next cycle after xfer_grant), following signals (up to xfer_partial) are valid
    output                         xfer_start_wr,    // initiate a transfer (next cycle after xfer_grant), following signals (up to xfer_partial) are valid
    output                         xfer_start32_rd,  // initiate a transfer to 32-byte wide colums scanning in each tile
    output                         xfer_start32_wr,  // initiate a transfer to 32-byte wide colums scanning in each tile 
111 112 113
    output                   [2:0] xfer_bank,     // start bank address
    output    [ADDRESS_NUMBER-1:0] xfer_row,      // memory row
    output    [COLADDR_NUMBER-4:0] xfer_col,      // start memory column in 8-bursts
114 115
    output    [FRAME_WIDTH_BITS:0] rowcol_inc,    // increment row+col (after bank) for the new scan line in 8-bursts (externally pad with 0)
    output    [MAX_TILE_WIDTH-1:0] num_rows_m1,   // number of rows to read minus 1
116
    output   [MAX_TILE_HEIGHT-1:0] num_cols_m1,   // number of 16-pixel columns to read (rows first, then columns) - 1
117 118 119
    output                         keep_open,     // (programmable bit)keep banks open (for <=8 banks only
    output                         xfer_partial,  // partial tile (first of 2) , sequencer will not generate page_next at the end of block   
    input                          xfer_page_done,     // transfer to/from the buffer finished (partial transfers should not generate), use rpage_nxt_chn@mclk
120 121
    output                         xfer_page_rst_wr, // reset buffer internal page - at each frame start or when specifically reset (write to memory channel), @posedge
    output                         xfer_page_rst_rd // reset buffer internal page - at each frame start or when specifically reset (read memory channel), @negedge
122
);
123 124
// FIXME: not all tile heights are valid (because of the banks)

125
//MAX_TILE_WIDTH
126 127
    localparam NUM_RC_BURST_BITS=ADDRESS_NUMBER+COLADDR_NUMBER-3;  //to spcify row and col8 == 22
    localparam MPY_WIDTH=        NUM_RC_BURST_BITS; // 22
128
    localparam PAR_MOD_LATENCY=  9; // TODO: Find actual worst-case latency for:
129 130 131
    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
132 133
    reg   [NUM_RC_BURST_BITS-1:0] line_start_addr;// (calculated) Line start (in {row,col8} in burst8
    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
134
 // calculating full width from the frame width
135 136 137
//WARNING: [Synth 8-3936] Found unconnected internal register 'frame_y_reg' and it is trimmed from '16' to '3' bits. [memctrl/mcntrl_tiled_rw.v:307]
// 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
138 139 140 141
`ifndef IGNORE_ATTR
    (* keep = "true" *)
`endif    
    reg   [FRAME_HEIGHT_BITS-1:0] frame_y;     // current line number referenced to the frame top
142 143 144 145 146
    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
147 148
//    reg                     [2:0] bank_reg [2:0];
    reg             [3 * 3 - 1:0] bank_reg;
149 150 151 152 153
    wire [FRAME_WIDTH_BITS+FRAME_HEIGHT_BITS-3:0] mul_rslt_w;
 //   wire                    [2:0] cur_bank;
    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
154 155 156
    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_tile_width;  // number of bursts postponed to the next partial tile (because of the page crossing) MSB-sign
    reg                           continued_tile;        // this is a continued tile (caused by page crossing) - only once
157
    reg      [MAX_TILE_WIDTH-1:0] leftover_cols;         // valid with continued_tile, number of columns left
158 159
    wire                          pgm_param_w;  // program one of the parameters, invalidate calculated results for PAR_MOD_LATENCY
    reg                     [2:0] xfer_start_r;
160 161 162 163
    reg                           xfer_start_rd_r;
    reg                           xfer_start_wr_r;
    reg                           xfer_start32_rd_r;
    reg                           xfer_start32_wr_r;
164 165
    reg     [PAR_MOD_LATENCY-1:0] par_mod_r; 
    reg     [PAR_MOD_LATENCY-1:0] recalc_r; // 1-hot CE for re-calculating registers
166
    wire                          calc_valid;   // calculated registers have valid values   
167
    wire                          chn_en;   // enable requests by channel (continue ones in progress), enable frame_start inputs
168
    wire                          chn_rst; // resets command, including fifo;
169
    reg                           chn_rst_d; // delayed by 1 cycle do detect turning off
170 171 172
    reg                           xfer_page_rst_r=1;
    reg                           xfer_page_rst_pos=1;  
    reg                           xfer_page_rst_neg=1;  
173 174
    reg                     [2:0] page_cntr; // to maintain requests - difference between client requests and generated requests
                                             // partial (truncated by memory page) generated requests should not count 
175
    
176
    wire                          cmd_wrmem; //= MCNTRL_TILED_WRITE_MODE; // 0: read from memory, 1:write to memory (change to parameter?)
177
    wire                    [1:0] cmd_extra_pages; // external module needs more than 1 page
178
    wire                          byte32; // use 32-byte wide colums in each tile (0 - use 16-byte ones)
179
    wire                          disable_need; // do not assert need, only want
180 181 182 183
    wire                          repeat_frames; // mode bit
    wire                          single_frame_w; // pulse
    wire                          rst_frame_num_w;
    reg                           single_frame_r;  // pulse
184
    reg                     [1:0] rst_frame_num_r; // reset frame number/next start address
185 186
    reg                           frame_en;       // enable next frame
    
187 188 189 190
    reg                           busy_r;
    reg                           want_r;
    reg                           need_r;
    reg                           frame_done_r;
191
    reg                           frame_finished_r;    
192 193 194
    wire                          last_in_row_w;
    wire                          last_row_w;
    reg                           last_block;
195
    reg [MCNTRL_TILED_PENDING_CNTR_BITS-1:0] pending_xfers; // number of requested,. but not finished block transfers   (to genearate frame done)   
196
    reg   [NUM_RC_BURST_BITS-1:0] row_col_r;
197 198
//    reg   [FRAME_HEIGHT_BITS-1:0] line_unfinished_r0;
//    reg   [FRAME_HEIGHT_BITS-1:0] line_unfinished_r1;
199 200 201
//    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;
202
    
203 204 205 206 207 208 209 210 211
    wire                          pre_want;
    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;
212 213 214
    wire                          set_frame_size_w;
    wire                          set_last_frame_w;
    
215 216 217 218
    wire                          set_frame_width_w;
    wire                          set_window_wh_w;
    wire                          set_window_x0y0_w;
    wire                          set_window_start_w;
219
    wire                          set_tile_whs_w;
220
    wire                          lsw13_zero=!(|cmd_data[FRAME_WIDTH_BITS-1:0]); // LSW 13 (FRAME_WIDTH_BITS) low bits are all 0 - set carry bit  
Andrey Filippov's avatar
Andrey Filippov committed
221
//    wire                          msw13_zero=!(|cmd_data[FRAME_WIDTH_BITS+15:16]); // MSW 13 (FRAME_WIDTH_BITS) low bits are all 0 - set carry bit
222
    wire                          msw_zero=  !(|cmd_data[31:16]); // MSW all bits are 0 - set carry bit
223
    wire                          tile_width_zero= !(|cmd_data[ 0+:MAX_TILE_WIDTH]);  
224
    wire                          tile_height_zero=!(|cmd_data[ 8+:MAX_TILE_HEIGHT]);  
225
    wire                          tile_vstep_zero= !(|cmd_data[16+:MAX_TILE_HEIGHT]);  
226
    
227
//    reg                     [5:0] mode_reg;//mode register: {write_mode,keep_open,extra_pages[1:0],enable,!reset}
228
//    reg                     [6:0] mode_reg;//mode register: {byte32,keep_open,extra_pages[1:0],write_mode,enable,!reset}
229
    reg                    [11:0] mode_reg;//mode register: {dis_need,repet,single,rst_frame,na,byte32,keep_open,extra_pages[1:0],write_mode,enable,!reset}
230 231 232 233 234 235
    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; 
    reg   [NUM_RC_BURST_BITS-1:0] start_addr;       // (programmed) Frame start (in {row,col8} in burst8, bank ==0
    reg   [NUM_RC_BURST_BITS-1:0] next_frame_start_addr;
    reg     [LAST_FRAME_BITS-1:0] frame_number_cntr;
236
    reg     [LAST_FRAME_BITS-1:0] frame_number_current;
237
    reg                           is_last_frame;
238 239
//    reg                     [2:0] frame_start_r;
    reg                     [4:0] frame_start_r; // increased length to have time from line_unfinished to suspend (external)
240 241
//    reg                           rst_frame_num_d;
    
242
    reg        [MAX_TILE_WIDTH:0] tile_cols;  // full number of columns in a tile
243
//    reg       [MAX_TILE_HEIGHT:0] tile_rows;  // full number of rows in a tile
244 245
//    reg     [MAX_TILE_HEIGHT-1:0] tile_rows;  // full number of rows in a tile
    reg       [MAX_TILE_HEIGHT:0] tile_rows;  // full number of rows in a tile
246
    reg       [MAX_TILE_HEIGHT:0] tile_vstep; // vertical step between rows of tiles
247 248 249 250

    reg        [MAX_TILE_WIDTH:0] num_cols_r; // full number of columns to transfer (not minus 1)
    wire       [MAX_TILE_WIDTH:0] num_cols_m1_w; // full number of columns to transfer minus 1 with extra bit
    wire      [MAX_TILE_HEIGHT:0] num_rows_m1_w; // full number of columns to transfer minus 1 with extra bit
251 252 253 254 255
    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
256
//    reg     [FRAME_HEIGHT_BITS:0] window_m_tile_height;  // (window height-tile height
257 258 259 260
    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 
261
    reg                           xfer_page_done_d;   // next cycle after xfer_page_done
262
    
263
    assign frame_number =       frame_number_current;
264 265 266 267
    
    assign set_mode_w =         cmd_we && (cmd_a== MCNTRL_TILED_MODE);
    assign set_status_w =       cmd_we && (cmd_a== MCNTRL_TILED_STATUS_CNTRL);
    assign set_start_addr_w =   cmd_we && (cmd_a== MCNTRL_TILED_STARTADDR);
268 269
    assign set_frame_size_w =   cmd_we && (cmd_a== MCNTRL_TILED_FRAME_SIZE);
    assign set_last_frame_w =   cmd_we && (cmd_a== MCNTRL_TILED_FRAME_LAST);
270 271 272 273
    assign set_frame_width_w =  cmd_we && (cmd_a== MCNTRL_TILED_FRAME_FULL_WIDTH);
    assign set_window_wh_w =    cmd_we && (cmd_a== MCNTRL_TILED_WINDOW_WH);
    assign set_window_x0y0_w =  cmd_we && (cmd_a== MCNTRL_TILED_WINDOW_X0Y0);
    assign set_window_start_w = cmd_we && (cmd_a== MCNTRL_TILED_WINDOW_STARTXY);
274
    assign set_tile_whs_w =     cmd_we && (cmd_a== MCNTRL_TILED_TILE_WHS);
275
    
276 277
    assign single_frame_w =  cmd_we && (cmd_a== MCNTRL_TILED_MODE) && cmd_data[MCONTR_LINTILE_SINGLE];
    assign rst_frame_num_w = cmd_we && (cmd_a== MCNTRL_TILED_MODE) && cmd_data[MCONTR_LINTILE_RST_FRAME];
278 279


280
    //
281
    // Set parameter registers
Andrey Filippov's avatar
Andrey Filippov committed
282 283
    always @(posedge mclk) begin
        if      (mrst)               mode_reg <= 0;
284
        else if (set_mode_w)         mode_reg <= cmd_data[11:0]; // [5:0];
285
        
Andrey Filippov's avatar
Andrey Filippov committed
286 287
        if (mrst) single_frame_r <= 0;
        else      single_frame_r <= single_frame_w;
288
        
Andrey Filippov's avatar
Andrey Filippov committed
289 290
        if (mrst) rst_frame_num_r <= 0;
        else      rst_frame_num_r <= {rst_frame_num_r[0],
291 292 293 294 295
                                     rst_frame_num_w |
                                     set_start_addr_w |
                                     set_last_frame_w |
                                     set_frame_size_w};

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

Andrey Filippov's avatar
Andrey Filippov committed
299
        if      (mrst)               frame_size <= 0;
300 301
        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];
302

Andrey Filippov's avatar
Andrey Filippov committed
303
        if      (mrst)             last_frame_number <= 0;
304 305
        else if (set_last_frame_w) last_frame_number <= cmd_data[LAST_FRAME_BITS-1:0];
        
Andrey Filippov's avatar
Andrey Filippov committed
306
        if      (mrst)              frame_full_width <=  0;
Andrey Filippov's avatar
Andrey Filippov committed
307
        else if (set_frame_width_w) frame_full_width <= {lsw13_zero,cmd_data[FRAME_WIDTH_BITS-1:0]};
308
        
Andrey Filippov's avatar
Andrey Filippov committed
309
        if (mrst) is_last_frame <= 0;
310 311
        else     is_last_frame <= frame_number_cntr == last_frame_number;
        
Andrey Filippov's avatar
Andrey Filippov committed
312
        if (mrst) frame_start_r <= 0;
313
        else     frame_start_r <= {frame_start_r[3:0], frame_start & frame_en};
314

Andrey Filippov's avatar
Andrey Filippov committed
315
        if      (mrst)                            frame_en <= 0;
316 317 318
        else if (single_frame_r || repeat_frames) frame_en <= 1;
        else if (frame_start)                     frame_en <= 0;
        
Andrey Filippov's avatar
Andrey Filippov committed
319
        if      (mrst)               frame_number_cntr <= 0;
320 321
        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);
322
        
Andrey Filippov's avatar
Andrey Filippov committed
323
        if      (mrst)               frame_number_current <= 0;
324 325
        else if (rst_frame_num_r[0]) frame_number_current <= 0;
        else if (frame_start_r[2])   frame_number_current <= frame_number_cntr;
326

Andrey Filippov's avatar
Andrey Filippov committed
327
        if      (mrst)               next_frame_start_addr <= start_range_addr; // just to use rst
328 329 330
        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
331
        if      (mrst)               start_addr <= start_range_addr; // just to use rst
332 333 334
        else if (frame_start_r[0])   start_addr <= next_frame_start_addr;

        
Andrey Filippov's avatar
Andrey Filippov committed
335
        if (mrst) begin
336 337 338 339 340 341 342
               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
343
        if (mrst) begin
344 345
               tile_cols <= 0; 
               tile_rows <=  0;
346 347 348
               tile_vstep <= 0;
        end else if (set_tile_whs_w)  begin
               tile_cols <=  {tile_width_zero,  cmd_data[ 0+:MAX_TILE_WIDTH]};
349
               tile_rows <=  {tile_height_zero, cmd_data[ 8+:MAX_TILE_HEIGHT]};
350
               tile_vstep <= {tile_vstep_zero,  cmd_data[16+:MAX_TILE_HEIGHT]};
351 352
        end

Andrey Filippov's avatar
Andrey Filippov committed
353
        if (mrst) begin
354
               window_x0 <= 0; 
355
               window_y0 <= 0;
356 357 358 359 360
        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
361
        if (mrst) begin
362 363 364 365 366 367
               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
368
        
369 370
    end
    assign mul_rslt_w=  frame_y8_r * frame_full_width_r; // 5 MSBs will be discarded
371 372 373 374 375
//    assign xfer_start=  xfer_start_r[0];
    assign xfer_start_rd=  xfer_start_rd_r;
    assign xfer_start_wr=  xfer_start_wr_r;
    assign xfer_start32_rd=  xfer_start32_rd_r;
    assign xfer_start32_wr=  xfer_start32_wr_r;
376
    assign calc_valid=  par_mod_r[PAR_MOD_LATENCY-1]; // MSB, longest 0
377 378
    assign frame_done=      frame_done_r;
    assign frame_finished=  frame_finished_r;
379
    assign pre_want=    chn_en && busy_r && !want_r && !xfer_start_r[0] && calc_valid && !last_block && !suspend && !(|frame_start_r);
380
    assign last_in_row_w=(row_left=={{(FRAME_WIDTH_BITS-MAX_TILE_WIDTH){1'b0}},num_cols_r}); // what if it crosses page? OK, num_cols_r & row_left know that
381 382 383
// tiles must completely fit window
// all window should be covered (tiles may extend):    
    assign last_row_w=  next_y>=window_height;
384
    //window_m_tile_height
385 386
    assign xfer_want=   want_r;
    assign xfer_need=   need_r;
387
    assign xfer_bank=   bank_reg[2*3 +: 3]; // TODO: just a single reg layer
388 389
    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
390 391
//    assign line_unfinished = line_unfinished_r[FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS];
    assign line_unfinished = line_unfinished_r;
392 393 394 395 396 397 398 399

    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 keep_open=        mode_reg[MCONTR_LINTILE_KEEP_OPEN]; // keep banks open (will be used only if number of rows <= 8
    assign byte32=           mode_reg[MCONTR_LINTILE_BYTE32]; // use 32-byte wide columns in each tile (false - 16-byte) 
    assign repeat_frames=    mode_reg[MCONTR_LINTILE_REPEAT];
400
    assign disable_need =    mode_reg[MCONTR_LINTILE_DIS_NEED];
401
    assign status_data=      {frame_finished_r, busy_r}; 
402
    assign pgm_param_w=      cmd_we;
403 404 405 406 407 408
    assign rowcol_inc=       frame_full_width;
    assign num_cols_m1_w=    num_cols_r-1;
    assign num_rows_m1_w=    tile_rows-1; // now number of rows == tile height
    assign num_cols_m1=      num_cols_m1_w[MAX_TILE_WIDTH-1:0];  // remove MSB
    assign num_rows_m1=      num_rows_m1_w[MAX_TILE_HEIGHT-1:0]; // remove MSB
    assign remainder_tile_width = {EXTRA_BITS,lim_by_tile_width}-mem_page_left;
409
    
410 411 412
    assign xfer_page_rst_wr=  xfer_page_rst_r;
    assign xfer_page_rst_rd=  xfer_page_rst_neg;
    
413
    assign xfer_partial=    xfer_limited_by_mem_page_r;
414
    
415
    integer i;
416 417 418
    localparam [COLADDR_NUMBER-3-MAX_TILE_WIDTH-1:0] EXTRA_BITS=0;
    wire xfer_limited_by_mem_page;
    reg  xfer_limited_by_mem_page_r;
419
    assign xfer_limited_by_mem_page= keep_open && (mem_page_left < {EXTRA_BITS,lim_by_tile_width}); // if not keep_open - no need to break
420
    always @(posedge mclk) begin // TODO: Match latencies (is it needed?) Reduce consumption by CE?
421 422 423 424
    // cycle 1
        if (recalc_r[0]) begin
            frame_x <= curr_x + window_x0;
            frame_y <= curr_y + window_y0;
425
            next_y <= curr_y + tile_vstep;
426 427
            row_left <= window_width - curr_x; // 14 bits - 13 bits
        end    
428 429 430 431 432 433 434 435 436 437 438
// registers to be absorbed in DSP block        
        frame_y8_r <= frame_y[FRAME_HEIGHT_BITS-1:3]; // lat=2 // if (recalc_r[2]) begin
        frame_full_width_r <= frame_full_width; //(cycle 2) // if (recalc_r[2]) begin
        start_addr_r <= start_addr; // // if (recalc_r[2]) begin
        mul_rslt <= mul_rslt_w[MPY_WIDTH-1:0]; // frame_y8_r * frame_width_r; // 7 bits will be discarded lat=3; if (recalc_r[3]) begin
        line_start_addr <= start_addr_r+mul_rslt; // lat=4 if (recalc_r[4]) begin
// TODO: Verify MPY/register timing above        
        if (recalc_r[5]) begin    // cycle 6
            row_col_r <= line_start_addr+frame_x;
            line_start_page_left <=  - line_start_addr[COLADDR_NUMBER-4:0]; // 7 bits
        end
439 440 441
        bank_reg[0 +: 3]   <= frame_y[2:0]; //TODO: is it needed - a pipeline for the bank? - remove! 
        for (i=0; i<2; i = i+1)
            bank_reg[(i+1)*3 +: 3] <= bank_reg[i*3 +: 3];
442 443
     
        if (recalc_r[6]) begin    // cycle 7
Andrey Filippov's avatar
Andrey Filippov committed
444
            mem_page_left <= {1'b1,line_start_page_left} - frame_x[COLADDR_NUMBER-4:0];
445 446 447 448
            lim_by_tile_width <= (|row_left[FRAME_WIDTH_BITS:MAX_TILE_WIDTH] || (row_left[MAX_TILE_WIDTH:0]>= tile_cols))?
                                    tile_cols:
                                    row_left[MAX_TILE_WIDTH:0]; // 7 bits, max 'h40
        end
449 450

        if (recalc_r[7]) begin    // cycle 8
451 452
            xfer_limited_by_mem_page_r <= xfer_limited_by_mem_page && !continued_tile;     
            num_cols_r<= continued_tile?
453
                {EXTRA_BITS,leftover_cols}:
454
                (xfer_limited_by_mem_page? mem_page_left[MAX_TILE_WIDTH:0]:lim_by_tile_width[MAX_TILE_WIDTH:0]);
455
                leftover_cols <= remainder_tile_width[MAX_TILE_WIDTH-1:0];
456
        end
457
        if (recalc_r[8]) begin    // cycle 9
458 459
            last_in_row <= last_in_row_w;
        end
460 461 462
    end
    
// now have row start address, bank and row_left ;
463 464
// calculate number to read (min of row_left, maximal xfer and what is left in the DDR3 page
wire    start_not_partial= xfer_start_r[0] && !xfer_limited_by_mem_page_r;    
Andrey Filippov's avatar
Andrey Filippov committed
465 466
    always @(posedge mclk) begin
        if      (mrst)               par_mod_r<=0;
467 468 469 470 471
        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};
472

Andrey Filippov's avatar
Andrey Filippov committed
473
        if     (mrst)          chn_rst_d <= 0;
474 475
        else                   chn_rst_d <= chn_rst;

Andrey Filippov's avatar
Andrey Filippov committed
476
        if      (mrst)         recalc_r<=0;
477
        else if (chn_rst)      recalc_r<=0;
478
//        else                 recalc_r <= {recalc_r[PAR_MOD_LATENCY-2:0], (xfer_grant & ~chn_rst) | pgm_param_w | (chn_rst_d & ~chn_rst)};
479
        else                   recalc_r <= {recalc_r[PAR_MOD_LATENCY-2:0],
480
                                 ((xfer_start_r[0] | frame_start_r[0])  & ~chn_rst) | pgm_param_w | (chn_rst_d & ~chn_rst)};
481
        
Andrey Filippov's avatar
Andrey Filippov committed
482
        if      (mrst)              busy_r <= 0;
483 484 485
        else if (chn_rst)           busy_r <= 0;
        else if (frame_start_r[0])  busy_r <= 1;
        else if (frame_done_r)      busy_r <= 0;
486
        
Andrey Filippov's avatar
Andrey Filippov committed
487 488
        if (mrst) xfer_page_done_d <= 0;
        else      xfer_page_done_d <= xfer_page_done;
489
        
Andrey Filippov's avatar
Andrey Filippov committed
490 491
        if (mrst) xfer_start_r <= 0;
        else      xfer_start_r <= {xfer_start_r[1:0],xfer_grant && !chn_rst};
492
        
Andrey Filippov's avatar
Andrey Filippov committed
493 494
        if (mrst) xfer_start_rd_r <= 0;
        else      xfer_start_rd_r <=  xfer_grant && !chn_rst && !cmd_wrmem && !byte32;
495

Andrey Filippov's avatar
Andrey Filippov committed
496 497
        if (mrst) xfer_start_wr_r <= 0;
        else      xfer_start_wr_r <=  xfer_grant && !chn_rst && cmd_wrmem && !byte32;
498

Andrey Filippov's avatar
Andrey Filippov committed
499 500
        if (mrst) xfer_start32_rd_r <= 0;
        else      xfer_start32_rd_r <=  xfer_grant && !chn_rst && !cmd_wrmem && byte32;
501

Andrey Filippov's avatar
Andrey Filippov committed
502
        if (mrst) xfer_start32_wr_r <= 0;
503 504
        else     xfer_start32_wr_r <=  xfer_grant && !chn_rst && cmd_wrmem && byte32;

505
        if (mrst)                  continued_tile <= 1'b0;
506
        else if (chn_rst)          continued_tile <= 1'b0;
507
        else if (frame_start_r[0]) continued_tile <= 1'b0;
508 509
        else if (xfer_start_r[0])  continued_tile <= xfer_limited_by_mem_page_r; // only set after actual start if it was partial, not after parameter change
        
510
        if (mrst || disable_need)                         need_r <= 0;
511 512
        else if (chn_rst || xfer_grant)                   need_r <= 0;
        else if ((pre_want  || want_r) && (page_cntr>=3)) need_r <= 1; // may raise need if want was already set
513

514
        if (mrst)                                                want_r <= 0;
515 516 517
        else if (chn_rst || xfer_grant)                          want_r <= 0;
        else if (pre_want && (page_cntr>{1'b0,cmd_extra_pages})) want_r <= 1;
        
Andrey Filippov's avatar
Andrey Filippov committed
518
        if (mrst)                                   page_cntr <= 0;
519
        else if (frame_start_r[0])                 page_cntr <= cmd_wrmem?0:4;
520 521
        else if ( start_not_partial && !next_page) page_cntr <= page_cntr - 1;     
        else if (!start_not_partial &&  next_page) page_cntr <= page_cntr + 1;
522
        
Andrey Filippov's avatar
Andrey Filippov committed
523
        if (mrst) xfer_page_rst_r <= 1;
524
        else     xfer_page_rst_r <= chn_rst || (MCNTRL_TILED_FRAME_PAGE_RESET ? (frame_start_r[0] & cmd_wrmem):1'b0);
525

Andrey Filippov's avatar
Andrey Filippov committed
526
        if (mrst) xfer_page_rst_pos <= 1;
527
        else     xfer_page_rst_pos <= chn_rst || (MCNTRL_TILED_FRAME_PAGE_RESET ? (frame_start_r[0] & ~cmd_wrmem):1'b0);
528 529
        
// increment x,y (two cycles)
Andrey Filippov's avatar
Andrey Filippov committed
530
        if (mrst)                                  curr_x <= 0;
531
        else if (chn_rst || frame_start_r[0])     curr_x <= start_x;
532
        else if (xfer_start_r[0])                 curr_x <= last_in_row?0: curr_x + num_cols_r;
533
        
Andrey Filippov's avatar
Andrey Filippov committed
534
        if (mrst)                                  curr_y <= 0;
535
        else if (chn_rst || frame_start_r[0])     curr_y <= start_y;
536 537
        else if (xfer_start_r[0] && last_in_row)  curr_y <= next_y[FRAME_HEIGHT_BITS-1:0];
               
Andrey Filippov's avatar
Andrey Filippov committed
538
        if      (mrst)                         last_block <= 0;
539
        else if (chn_rst || !busy_r)          last_block <= 0;
540
        else if (xfer_start_r[0])             last_block <= last_row_w && last_in_row_w;
541 542
 
 // start_not_partial is not generated when partial (first of 2, caused by a tile crossing memory page) transfer is requested       
Andrey Filippov's avatar
Andrey Filippov committed
543
 // here we need to cout all requests - partial or not
Andrey Filippov's avatar
Andrey Filippov committed
544
        if      (mrst)                                   pending_xfers <= 0;
545
        else if (chn_rst || !busy_r)                    pending_xfers <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
546 547
        else if ( xfer_start_r[0] && !xfer_page_done) pending_xfers <= pending_xfers + 1;     
        else if (!xfer_start_r[0] &&  xfer_page_done) pending_xfers <= pending_xfers - 1; // page done is not generated on partial (first) pages
548
        
549
        // single cycle (sent out)
Andrey Filippov's avatar
Andrey Filippov committed
550
        if (mrst)          frame_done_r <= 0;
551 552 553
        else              frame_done_r <= busy_r && last_block && xfer_page_done_d && (pending_xfers==0);

        // turns and stays on (used in status)
Andrey Filippov's avatar
Andrey Filippov committed
554
        if (mrst)                              frame_finished_r <= 0;
555 556
        else if (chn_rst || frame_start_r[0]) frame_finished_r <= 0;
        else if (frame_done_r)                frame_finished_r <= 1;
557
        //line_unfinished_r cmd_wrmem
558 559 560 561
/*       
        if (mrst)                             line_unfinished_r[0 +: FRAME_HEIGHT_BITS] <= 0; //{FRAME_HEIGHT_BITS{1'b0}};
        else if (chn_rst || frame_start_r[0]) line_unfinished_r[0 +: FRAME_HEIGHT_BITS] <= window_y0+start_y;
        else if (xfer_start_r[2])             line_unfinished_r[0 +: FRAME_HEIGHT_BITS] <= window_y0+next_y[FRAME_HEIGHT_BITS-1:0]; // latency 2 from xfer_start
562

563 564
        if (mrst)                              line_unfinished_r[FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS] <= 0; //{FRAME_HEIGHT_BITS{1'b0}};
        else if (chn_rst || frame_start_r[2]) line_unfinished_r[FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS] <= window_y0+start_y; // _r[0] -> _r[2] to make it simultaneous with frame_number
565 566
        
        // in read mode advance line number ASAP
567
        else if (xfer_start_r[2] && !cmd_wrmem) line_unfinished_r[FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS] <= window_y0+next_y[FRAME_HEIGHT_BITS-1:0]; // latency 2 from xfer_start
568
        // in write mode advance line number only when it is guaranteed it will be the first to actually access memory
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
        else if (xfer_grant      && cmd_wrmem)  line_unfinished_r[FRAME_HEIGHT_BITS +: FRAME_HEIGHT_BITS] <=  line_unfinished_r[0 +: FRAME_HEIGHT_BITS];
*/
/* 
        if (mrst)                                                line_unfinished_relw_r <= 0;
        else if (cmd_wrmem && (frame_start_r[1] || !chn_en))     line_unfinished_relw_r <= start_y;
        else if ((!cmd_wrmem && recalc_r[1]) || xfer_start_r[2]) line_unfinished_relw_r <= next_y[FRAME_HEIGHT_BITS-1:0];
        //  xfer_start_r[2] and recalc_r[1] are at the same time
        
        if (mrst || (frame_start || !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;
*/
        if (recalc_r[0]) line_unfinished_relw_r <= curr_y + (cmd_wrmem ? 0: tile_rows);
        
        if (mrst || (frame_start || !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;
584 585
        
    end
586 587 588
    always @ (negedge mclk) begin
        xfer_page_rst_neg <= xfer_page_rst_pos;
    end
589 590 591 592 593 594 595
    cmd_deser #(
        .ADDR       (MCNTRL_TILED_ADDR),
        .ADDR_MASK  (MCNTRL_TILED_MASK),
        .NUM_CYCLES (6),
        .ADDR_WIDTH (4),
        .DATA_WIDTH (32)
    ) cmd_deser_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
596 597 598 599 600 601
        .rst        (1'b0),     // input
        .clk        (mclk),     // input
        .srst       (mrst),     // input
        .ad         (cmd_ad),   // input[7:0] 
        .stb        (cmd_stb),  // input
        .addr       (cmd_a),    // output[15:0] 
602
        .data       (cmd_data), // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
603
        .we         (cmd_we)    // output
604 605 606 607 608 609
    );

    status_generate #(
        .STATUS_REG_ADDR  (MCNTRL_TILED_STATUS_REG_ADDR),
        .PAYLOAD_BITS     (2)
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
610 611 612 613
        .rst              (1'b0),          // input
        .clk              (mclk),          // input
        .srst             (mrst),          // input
        .we               (set_status_w),  // input
614
        .wd               (cmd_data[7:0]), // input[7:0] 
Andrey Filippov's avatar
Andrey Filippov committed
615 616 617 618
        .status           (status_data),   // input[25:0] 
        .ad               (status_ad),     // output[7:0] 
        .rq               (status_rq),     // output
        .start            (status_start)   // input
619 620 621
    );
endmodule