membridge.v 37.4 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: membridge
 * Date:2015-04-26  
4
 * Author: Andrey Filippov     
5 6
 * Description: bi-directional bridge between system and video memory over axi_hp
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19
 * membridge.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.
 *
 *  membridge.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/> .
20 21 22 23 24 25
 *
 * 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"
26
 * files and/or simulating the code, the copyright holders of this Program give
27 28
 * 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
29
 * charge, and there is no dependence on any encrypted modules for simulating of
30 31 32
 * 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.
33 34
 *******************************************************************************/
`timescale 1ns/1ps
35
//`define MEMBRIDGE_DEBUG_READ 1
36 37
module  membridge#(
    parameter MEMBRIDGE_ADDR=                     'h200,
38
    parameter MEMBRIDGE_MASK=                     'h7f0,
Andrey Filippov's avatar
Andrey Filippov committed
39
    parameter MEMBRIDGE_CTRL=                     'h0, // bit 0 - enable, bits[2:1]: 11 - start(continue), 01 - start and reset address
40 41 42 43 44 45
    parameter MEMBRIDGE_STATUS_CNTRL=             'h1,
    parameter MEMBRIDGE_LO_ADDR64=                'h2, // low address of the system memory, in 64-bit words (<<3 to get byte address)
    parameter MEMBRIDGE_SIZE64=                   'h3, // size of the system memory range (access will roll over to lo_addr
    parameter MEMBRIDGE_START64=                  'h4, // start address relative to lo_addr
    parameter MEMBRIDGE_LEN64=                    'h5, // full length of transfer in 64-bit words
    parameter MEMBRIDGE_WIDTH64=                  'h6, // frame width in 64-bit words (partial last page in each line)
46
    parameter MEMBRIDGE_MODE=                     'h7, // bits [3:0] - *_cache, bit [4] - cache debug
47 48 49 50
    parameter MEMBRIDGE_STATUS_REG=               'h3b,
    parameter FRAME_HEIGHT_BITS=                   16,   // Maximal frame height bits
    parameter FRAME_WIDTH_BITS=                    13
//    ,parameter MCNTRL_SCANLINE_FRAME_PAGE_RESET=  1'b0 // reset internal page number to zero at the frame start (false - only when hard/soft reset)
51 52 53
`ifdef DEBUG_RING
    ,parameter DEBUG_CMD_LATENCY = 2 
`endif        
54 55
    
)(
Andrey Filippov's avatar
Andrey Filippov committed
56 57 58 59 60 61
//    input         rst,
    input                         mrst, // @posedge mclk - sync reset
    input                         hrst, // @posedge hclk - sync reset
    
    input                         mclk, // for command/status
    input                         hclk,   // global clock to run axi_hp @ 150MHz
62 63 64 65 66 67 68 69 70
    // 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,   // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
    output                        status_rq,   // input request to send status downstream
    input                         status_start, // Acknowledge of the first status packet byte (address)
    // mcntrl_linear_rw.v interface
    output                        frame_start_chn, // input
    output                        next_page_chn, // input
71
    input                         cmd_wrmem,      // @mclk - writing to DDR3 mode (0 - reading from DDR3)
72 73 74
    input                         page_ready_chn, // output single mclk
    input                         frame_done_chn, // output single mclk
    input [FRAME_HEIGHT_BITS-1:0] line_unfinished_chn1, // output[15:0] @SuppressThisWarning VEditor unused (yet)
Andrey Filippov's avatar
Andrey Filippov committed
75
    output                        suspend_chn1, //
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
    // buffer interface, DDR3 memory read
    input                         xfer_reset_page_rd, // input
    input                         buf_wpage_nxt,     // input
    input                         buf_wr, // input
    input                  [63:0] buf_wdata,
    // buffer interface, DDR3 memory write
    input                         xfer_reset_page_wr, // input  @ posedge mclk
    input                         buf_rpage_nxt,
    input                         buf_rd,
    output                [63:0]  buf_rdata, 
    // axi_hp signals write channel
    // write address
    output  [31:0] afi_awaddr,
    output         afi_awvalid,
    input          afi_awready, // @SuppressThisWarning VEditor unused - used FIF0 level
    output  [ 5:0] afi_awid,
    output  [ 1:0] afi_awlock,
    output  [ 3:0] afi_awcache,
    output  [ 2:0] afi_awprot,
    output  [ 3:0] afi_awlen,
96
    output  [ 1:0] afi_awsize,
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    output  [ 1:0] afi_awburst,
    output  [ 3:0] afi_awqos,
    // write data
    output  [63:0] afi_wdata,
    output         afi_wvalid,
    input          afi_wready,  // @SuppressThisWarning VEditor unused - used FIF0 level
    output  [ 5:0] afi_wid,
    output         afi_wlast,
    output  [ 7:0] afi_wstrb,
    // write response
    input          afi_bvalid,
    output         afi_bready,
    input   [ 5:0] afi_bid,      // @SuppressThisWarning VEditor unused
    input   [ 1:0] afi_bresp,    // @SuppressThisWarning VEditor unused
    // PL extra (non-AXI) signals
    input   [ 7:0] afi_wcount,
    input   [ 5:0] afi_wacount,
    output         afi_wrissuecap1en,
    // AXI_HP signals - read channel
    // read address
    output  [31:0] afi_araddr,
    output         afi_arvalid,
    input          afi_arready,  // @SuppressThisWarning VEditor unused - used FIF0 level
    output  [ 5:0] afi_arid,
    output  [ 1:0] afi_arlock,
    output  [ 3:0] afi_arcache,
    output  [ 2:0] afi_arprot,
    output  [ 3:0] afi_arlen,
125
    output  [ 1:0] afi_arsize,
126 127 128 129 130 131 132 133
    output  [ 1:0] afi_arburst,
    output  [ 3:0] afi_arqos,
    // read data
    input   [63:0] afi_rdata,
    input          afi_rvalid,
    output         afi_rready,
    input   [ 5:0] afi_rid,     // @SuppressThisWarning VEditor unused
    input          afi_rlast,   // @SuppressThisWarning VEditor unused
134
    input   [ 1:0] afi_rresp,   // @SuppressThisWarning VEditor unused
135 136 137 138
    // PL extra (non-AXI) signals
    input   [ 7:0] afi_rcount,
    input   [ 2:0] afi_racount,
    output         afi_rdissuecap1en
139 140 141 142 143
`ifdef DEBUG_RING       
    ,output                       debug_do, // output to the debug ring
     input                        debug_sl, // 0 - idle, (1,0) - shift, (1,1) - load // SuppressThisWarning VEditor - not used
     input                        debug_di  // input from the debug ring
`endif         
144 145
    
);
146 147
    localparam BUFWR_WE_WIDTH = 4; //2; // 4;
    localparam SAFE_RD_BITS =   3; //2; // 3;
148 149 150
    // Some constant signals:
    
    assign afi_awlock =        2'h0;
151
//    assign afi_awcache =       4'h3;
152
    assign afi_awprot =        3'h0;
153
    assign afi_awsize =        2'h3;
154 155 156 157 158 159
    assign afi_awburst =       2'h1;
    assign afi_awqos =         4'h0;
    assign afi_wstrb =         8'hff;
    assign afi_wrissuecap1en = 1'b0;

    assign afi_arlock =        2'h0;
160
//    assign afi_arcache =       4'h3;
161
    assign afi_arprot =        3'h0;
162
    assign afi_arsize =        2'h3;
163 164 165 166 167
    assign afi_arburst =       2'h1;
    assign afi_arqos =         4'h0;
    assign afi_rdissuecap1en = 1'b0;


Andrey Filippov's avatar
Andrey Filippov committed
168 169
    assign frame_start_chn = start_mclk;
    assign suspend_chn1    = 1'b0;
170 171 172 173 174 175 176 177 178 179
    wire [ 3:0] cmd_a;    // control register address
    wire [31:0] cmd_data; // register data
    wire        cmd_we;   // register write
    
    wire set_ctrl_w;
    wire set_status_w;
    wire set_lo_addr64_w;
    wire set_size64_w;
    wire set_start64_w;
    wire set_len64_w;
180
    wire set_mode_w;
181
    wire set_width64_w;
182 183 184 185 186 187
    reg  [4:0] mode_reg_mclk;
    reg  [4:0] mode_reg;
    wire       cache_debug;
    assign cache_debug=mode_reg[4];
    assign afi_awcache =       mode_reg[3:0]; // 4'h3;
    assign afi_arcache =       mode_reg[3:0]; // 4'h3;
188 189 190 191 192 193 194
    assign set_ctrl_w =         cmd_we && (cmd_a== MEMBRIDGE_CTRL);
    assign set_lo_addr64_w =    cmd_we && (cmd_a== MEMBRIDGE_LO_ADDR64);
    assign set_size64_w =       cmd_we && (cmd_a== MEMBRIDGE_SIZE64);
    assign set_start64_w =      cmd_we && (cmd_a== MEMBRIDGE_START64);
    assign set_len64_w =        cmd_we && (cmd_a== MEMBRIDGE_LEN64);
    assign set_width64_w =      cmd_we && (cmd_a== MEMBRIDGE_WIDTH64);
    assign set_status_w =       cmd_we && (cmd_a== MEMBRIDGE_STATUS_CNTRL);
195
    assign set_mode_w =         cmd_we && (cmd_a== MEMBRIDGE_MODE);
196 197 198 199
    reg [28:0] lo_addr64_mclk;
    reg [28:0] size64_mclk;
    reg [28:0] start64_mclk;
    reg [28:0] len64_mclk;
200 201 202
//  reg [FRAME_WIDTH_BITS+1:0] width64_mclk; // FRAME_WIDTH_BITS in 128 bit bursts
    reg [FRAME_WIDTH_BITS:0] width64_mclk; // FRAME_WIDTH_BITS in 128 bit bursts
    reg [FRAME_WIDTH_BITS:0]   width64_minus1_mclk; // FRAME_WIDTH_BITS in 128 bit bursts
203 204 205
    reg        rdwr_en_mclk;
    reg        rdwr_reset_addr_mclk; // resets system memory address
    reg        start_mclk;
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
`ifdef MEMBRIDGE_DEBUG_READ    
    reg        debug_aw_mclk; // enable sending next address over AFI
    reg        debug_w_mclk; // enable sending next data burst over AFI
    wire       debug_aw; // enable sending next address over AFI, sync to hclk
    wire       debug_w; // enable sending next data burst over AFI, sync to hclk
    reg  [6:0] debug_aw_allowed;
    reg  [8:0] debug_w_allowed;
    reg  [4:0] debug_bufrd_rd;
    reg        debug_disable_set_mclk; // disable debug slowdown
    wire       debug_disable_set;      // disable debug slowdown
    reg        debug_disable; // disable debug slowdown
    wire       debug_aw_ready;
    wire       debug_w_ready;
    assign debug_aw_ready = (!debug_aw_allowed[6] && (|debug_aw_allowed[5:0])) || debug_disable; // > 0
    assign debug_w_ready =  (!debug_w_allowed[8]  && (|debug_w_allowed [7:0]) &&((|debug_w_allowed [7:1]) || !(|debug_bufrd_rd))) || debug_disable; // > 0
`endif    
222 223 224 225 226 227 228
//cmd_wrmem
    always @ (posedge mclk) begin
        if (set_lo_addr64_w)    lo_addr64_mclk       <= {cmd_data[28:4],4'b0}; // align to 16-bursts
        if (set_size64_w)       size64_mclk          <= {cmd_data[28:4],4'b0}; // align to 16-bursts
        if (set_lo_addr64_w)    start64_mclk         <= 0;
        else if (set_start64_w) start64_mclk         <= {cmd_data[28:4],4'b0}; // align to 16-bursts
        if (set_len64_w)        len64_mclk           <= cmd_data[28:0]; // OK not to be aligned
229 230
//        if (set_width64_w)      width64_mclk         <= {~(|cmd_data[FRAME_WIDTH_BITS:0]),cmd_data[FRAME_WIDTH_BITS:0]}; // OK not to be aligned
        if (set_width64_w)      width64_mclk         <= cmd_data[FRAME_WIDTH_BITS:0]; // OK not to be aligned
231
        if (set_ctrl_w)         rdwr_reset_addr_mclk <= cmd_data[1] && !cmd_data[2];
232
        width64_minus1_mclk <= width64_mclk-1;
233 234
    end

Andrey Filippov's avatar
Andrey Filippov committed
235 236
    always @ (posedge mclk) begin
        if      (mrst)       rdwr_en_mclk <= 0;
237 238
        else if (set_ctrl_w) rdwr_en_mclk <= cmd_data[0];
        
Andrey Filippov's avatar
Andrey Filippov committed
239 240
        if   (mrst) start_mclk <= 0;
        else        start_mclk <= set_ctrl_w & cmd_data[1];
241

Andrey Filippov's avatar
Andrey Filippov committed
242
        if      (mrst)       mode_reg_mclk <= 5'h03;
243 244
        else if (set_mode_w) mode_reg_mclk <= cmd_data[4:0];

245
`ifdef MEMBRIDGE_DEBUG_READ
Andrey Filippov's avatar
Andrey Filippov committed
246
        if  (mrst) debug_aw_mclk <= 0;
247 248
        else       debug_aw_mclk <= set_ctrl_w & cmd_data[2];

Andrey Filippov's avatar
Andrey Filippov committed
249
        if  (mrst) debug_w_mclk <= 0;
250 251
        else       debug_w_mclk <= set_ctrl_w & cmd_data[3];

Andrey Filippov's avatar
Andrey Filippov committed
252
        if  (mrst) debug_disable_set_mclk <= 0;
253
        else       debug_disable_set_mclk <= set_ctrl_w & cmd_data[4];
254 255
        
        
256
`endif
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

    end
    
    // syncronize mclk ->hclk
    
    reg [28:0] lo_addr64;
    reg [28:0] size64;
    reg [28:0] start64;
    reg [28:0] len64;
    reg [FRAME_WIDTH_BITS:0]   last_in_line64;
    reg [24:0] last_addr1k; // last adress before rollover w/o 4 LSB
    reg        rdwr_en;     // TODO: Use it?
    reg        rdwr_reset_addr; // resets system memory address
    wire       start_hclk;
    reg        rd_start;
    reg        wr_start;
    reg  [2:0] rdwr_start;
    reg        wr_mode;
    wire       page_ready; // @ posedge hclk
    wire       frame_done; // @ posedge hclk
//next_page_chn
    wire       reset_page_wr; // @ posedge hclk (from @ posedge mclk)
    wire       reset_page_rd; // @ posedge hclk (from @ negedge mclk)
    reg        page_ready_rd;
    reg        page_ready_wr;
    reg        next_page_rd;
    reg        next_page_wr;
    
    wire       next_page; // @ posedge hclk - source 
286
//    wire       busy_next_page; // do not send next_page -previous is crossing clock boundaries
287 288 289 290 291 292
    
    assign next_page= next_page_wr | next_page_rd;
    
    // incrementing IDs for read (MSB==0) and write (MSB==1)
    reg [4:0] rd_id;
    reg [4:0] wr_id;
293 294
    
    reg        read_no_more; // after frame_done - no more requests for new pages to read
295 296 297 298 299 300 301 302 303 304 305 306 307

    assign afi_arid={1'b1,rd_id};
    assign afi_awid={1'b1,wr_id};
    assign afi_wid= {1'b1,wr_id};

    
    
    
    always @ (posedge hclk) begin
        lo_addr64       <= lo_addr64_mclk;
        size64          <= size64_mclk;
        start64         <= start64_mclk;
        len64           <= len64_mclk;
308
        mode_reg        <= mode_reg_mclk;
309
        last_in_line64  <= width64_minus1_mclk;
310 311 312 313 314
        wr_mode         <= cmd_wrmem;
        rdwr_reset_addr <= rdwr_reset_addr_mclk;
        last_addr1k     <= size64[28:4] - 1;
    end

Andrey Filippov's avatar
Andrey Filippov committed
315 316 317
    always @ (posedge hclk) begin
        if (hrst) rdwr_en <= 0;
        else      rdwr_en <= rdwr_en_mclk;
318 319
        
        
Andrey Filippov's avatar
Andrey Filippov committed
320 321
        if (hrst) rdwr_start <= 0;
        else      rdwr_start <= {rdwr_start[1:0],start_hclk};
322

Andrey Filippov's avatar
Andrey Filippov committed
323 324
        if (hrst) rd_start <= 0;
        else      rd_start <= rdwr_start[2] && !wr_mode; // later to enable adders+ to propagate
325
        
Andrey Filippov's avatar
Andrey Filippov committed
326 327
        if (hrst) wr_start <= 0;
        else      wr_start <= rdwr_start[2] && wr_mode;
328
        
329
//        page_ready_rd <= page_ready && !wr_mode && !read_no_more;
330
        
Andrey Filippov's avatar
Andrey Filippov committed
331
        if      (hrst)     rd_id <= 0;
332 333
        else if (rd_start) rd_id <= rd_id +1;

Andrey Filippov's avatar
Andrey Filippov committed
334
        if      (hrst)     wr_id <= 0;
335
        else if (wr_start) wr_id <= wr_id +1;
336 337
        
        
338 339 340

    end
    // mclk -> hclk
Andrey Filippov's avatar
Andrey Filippov committed
341 342 343 344
    pulse_cross_clock start_i          (.rst(mrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(start_mclk), .out_pulse(start_hclk),.busy());
    pulse_cross_clock page_ready_i     (.rst(mrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(page_ready_chn), .out_pulse(page_ready),.busy());
    pulse_cross_clock frame_done_i     (.rst(mrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(frame_done_chn), .out_pulse(frame_done),.busy());
    pulse_cross_clock  reset_page_wr_i (.rst(mrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(xfer_reset_page_wr), .out_pulse(reset_page_wr),.busy());
345 346 347

`ifdef MEMBRIDGE_DEBUG_READ
    // mclk -> hclk, debug-only
Andrey Filippov's avatar
Andrey Filippov committed
348 349 350
    pulse_cross_clock debug_aw_i         (.rst(hrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(debug_aw_mclk), .out_pulse(debug_aw),.busy());
    pulse_cross_clock debug_w_i          (.rst(hrst), .src_clk(mclk), .dst_clk(hclk), .in_pulse(debug_w_mclk),  .out_pulse(debug_w), .busy());
    pulse_cross_clock debug_disable_set_i(.rst(hrst),.src_clk(mclk),.dst_clk(hclk), .in_pulse(debug_disable_set_mclk),.out_pulse(debug_disable_set), .busy());
351
`endif    
352
    // negedge mclk -> hclk (verify clock inversion is absorbed)
Andrey Filippov's avatar
Andrey Filippov committed
353 354 355
    reg mrstn = 1;
    always @ (negedge mclk) mrstn <= mrst;
    pulse_cross_clock  reset_page_rd_i (.rst(mrstn), .src_clk(~mclk),.dst_clk(hclk), .in_pulse(xfer_reset_page_rd), .out_pulse(reset_page_rd),.busy());
356 357
    
    // hclk -> mclk
358 359 360 361 362 363 364 365 366 367 368 369 370 371
//    pulse_cross_clock next_page_i  (.rst(hrst), .src_clk(hclk), .dst_clk(mclk), .in_pulse(next_page), .out_pulse(next_page_chn),.busy(busy_next_page));
    
    elastic_cross_clock #(
        .WIDTH(2),
        .EXTRA_DLY(0)
    ) elastic_cross_clock_i (
        .rst          (hrst),          // input
        .src_clk      (hclk),          // input
        .dst_clk      (mclk),          // input
        .in_pulses    (next_page),     // input
        .out_pulse    (next_page_chn), // output
        .busy         ()               // output
    );
    
372 373
    
    // Common to both directions
Andrey Filippov's avatar
Andrey Filippov committed
374
    localparam DELAY_ADVANCE_ADDR=3;    
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    reg [28:0] rel_addr64; // realtive (to lo_addr) address
    wire                         advance_rel_addr_w;
    wire                         advance_rel_addr_wr;
    wire                         advance_rel_addr_rd;
    
    reg                          advance_rel_addr;

    reg [DELAY_ADVANCE_ADDR-1:0] advance_rel_addr_d;
    reg                   [28:0] left64;
    reg                          last_burst;
    reg                          rollover;
    reg                   [ 3:0] afi_len;
    reg                   [ 4:0] afi_len_plus1;
    reg                          low4_zero;
    
    reg [28:0]                 buf_left64;      // number of 64-bit words yet to be read from the DDR3 (or written to it)
    reg [FRAME_WIDTH_BITS:0]   buf_in_line64;   // number of last 64-bit words in line
    
    //last_addr1k
    assign afi_awlen = afi_len;
    assign afi_arlen = afi_len;
    reg [28:0] axi_addr64;
    wire left_zero;
    
    assign afi_awaddr={axi_addr64,3'b0};
    assign afi_araddr={axi_addr64,3'b0};
    
    assign left_zero = low4_zero && last_burst;
Andrey Filippov's avatar
Andrey Filippov committed
403 404 405
    always @ (posedge hclk) begin
        if (hrst) advance_rel_addr_d <= 0;
        else      advance_rel_addr_d <= {advance_rel_addr_d[DELAY_ADVANCE_ADDR-2:0],advance_rel_addr};
406 407 408 409 410 411 412 413
                
    end

    reg        read_started;
    reg        write_busy;
    wire       rw_in_progress;
    reg        busy;
    reg        done;
414
    reg        pre_done;
415 416 417 418

    assign rw_in_progress = read_started || write_busy;
    
    always @ (posedge hclk) begin
Andrey Filippov's avatar
Andrey Filippov committed
419
        advance_rel_addr <= advance_rel_addr_w && !advance_rel_addr && !(|advance_rel_addr_d); // make sure advance_rel_addr_w is recalculated after address change
420 421 422 423
        last_burst <= ! (|left64[28:4]);
        rollover <= rel_addr64[28:4] == last_addr1k;
        low4_zero <= ! (|left64[3:0]);
        if (rdwr_start[0] && rdwr_reset_addr) rel_addr64 <= start64;
Andrey Filippov's avatar
Andrey Filippov committed
424
        else if (advance_rel_addr) rel_addr64 <= last_burst?(rel_addr64 + {25'h0,left64[3:0]}) : (rollover?29'h0:(rel_addr64 + 29'h10));
425 426 427 428

        axi_addr64 <= lo_addr64 + rel_addr64;
        
        if (rdwr_start)            left64 <= len64;
Andrey Filippov's avatar
Andrey Filippov committed
429
        else if (advance_rel_addr) left64 <= last_burst? 0: (left64 - 29'h10);
430 431 432 433
        
        afi_len       <= (|left64[28:4])?4'hf : (left64[3:0]-1);
        afi_len_plus1 <= (|left64[28:4]) ? 5'h10 : {1'b0,left64[3:0]};
        
434
        page_ready_rd <= page_ready && !wr_mode  && !read_no_more;
435 436 437 438 439 440 441 442
        page_ready_wr <= page_ready &&  wr_mode;
        
        if (!rw_in_progress) buf_left64 <= len64;
        else if (buf_rdwr)   buf_left64 <= buf_left64 - 1;
        
        if (!rw_in_progress) buf_in_line64 <= 0;
        else if (buf_rdwr)   buf_in_line64 <= is_last_in_line? {(FRAME_WIDTH_BITS+1){1'b0}} : (buf_in_line64 +1);
        
443 444
        if (hrst) next_page_rd <= 0;
        else      next_page_rd <= next_page_rd_w;
445
        
446 447
        if (hrst) next_page_wr <= 0;
        else      next_page_wr <= next_page_wr_w;
448 449 450 451 452
        
    end

    // DDR3 read - AFI write
    //rdwr_en    
453 454
    reg  [7:0] axi_arw_requested;     // 64-bit words to be read/written over axi queued to AR/AW channels
    reg  [7:0] axi_bursts_requested;  // number of bursts requested
455 456 457
    reg  [7:0] wresp_conf;         // number of 64-bit words confirmed through axi b channel (wrong confirmed only bursts)!
    wire [7:0] axi_wr_pending;     // Number of bursts queued to AW but not yet confirmed through B-channel;
    reg  [7:0] axi_wr_left;        // Number of bursts queued through AW but not sent over W;
458 459 460
    wire [7:0] axi_rd_pending;

    reg  [7:0] axi_rd_received;
461
    assign axi_rd_pending= axi_arw_requested - axi_rd_received; // WRONG! - use bursts, not words!
462 463
//    assign axi_wr_pending= axi_arw_requested - wresp_conf;
    assign axi_wr_pending= axi_bursts_requested - wresp_conf;
464
    
465 466 467 468 469 470 471 472 473 474 475 476 477
    reg        read_busy;
    reg        read_over;
    reg        afi_bvalid_r;
    reg  [1:0] read_page;
//    reg  [6:0] read_addr;
    reg  [2:0] read_pages_ready;
    
    assign afi_bready = 1'b1; // always ready to receive confirmation
    
    reg        afi_wd_safe_not_full;
    reg        afi_wa_safe_not_full;
    
    assign advance_rel_addr_w =  advance_rel_addr_wr || advance_rel_addr_rd;
478 479 480 481 482 483
//    assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64); // left 64 is decremented by 16, except possibly the last (partial)
`ifdef MEMBRIDGE_DEBUG_READ
    assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64) && debug_aw_ready; // debugging ddr3 -> system
`else
    assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64);
`endif    
484 485
    assign afi_awvalid=advance_rel_addr && read_started;
    
Andrey Filippov's avatar
Andrey Filippov committed
486 487
    always @ (posedge hclk) begin
        if      (hrst)      read_busy <= 0;
488 489
        else if (rd_start)  read_busy <= 1;
        else if (read_over) read_busy <= 0;
490 491 492
        
        
        
Andrey Filippov's avatar
Andrey Filippov committed
493
        if      (hrst)       read_started <= 0;
494
        else if (!read_busy) read_started <= 0;
495
        else if (wr_mode)    read_started <= 0; // just debugging, making sure read is disabled in write mode
496
        else if (page_ready) read_started <= 1; // first page is in the buffer - use it to mask page number comparison
497 498
        
`ifdef MEMBRIDGE_DEBUG_READ
Andrey Filippov's avatar
Andrey Filippov committed
499
        if      (hrst)                      debug_aw_allowed <= 0;
500 501 502 503 504
        else if (!read_busy)                debug_aw_allowed <= 0;
        else if ( debug_aw && !afi_awvalid) debug_aw_allowed <= debug_aw_allowed + 1;
        else if (!debug_aw &&  afi_awvalid) debug_aw_allowed <= debug_aw_allowed - 1;
        
        
Andrey Filippov's avatar
Andrey Filippov committed
505
        if      (hrst)                                   debug_w_allowed <= 0;
506 507 508 509
        else if (!read_busy)                             debug_w_allowed <= 0;
        else if ( debug_w && !(afi_wvalid && afi_wlast)) debug_w_allowed <= debug_w_allowed + 1;
        else if (!debug_w &&  (afi_wvalid && afi_wlast)) debug_w_allowed <= debug_w_allowed - 1;
        
Andrey Filippov's avatar
Andrey Filippov committed
510
        if      (hrst)              debug_disable <= 0;
511 512 513 514
        else if (!read_busy)        debug_disable <= 0;
        else if (debug_disable_set) debug_disable <= 1;
`endif        
        
515 516

        afi_bvalid_r <=afi_bvalid;
517
        
Andrey Filippov's avatar
Andrey Filippov committed
518
        if      (hrst)         wresp_conf <= 0;
519 520
        else if (!read_busy)   wresp_conf <= 0;
        else if (afi_bvalid_r) wresp_conf <= wresp_conf +1;
Andrey Filippov's avatar
Andrey Filippov committed
521
        
522
        read_over <= left_zero && (axi_wr_pending == 0) && read_started; 
523
        
Andrey Filippov's avatar
Andrey Filippov committed
524
        if      (hrst)           read_page <= 0;
525
        else if (reset_page_rd)  read_page <= 0;
526
        else if (done_page_rd_w) read_page <= read_page + 1;
527

Andrey Filippov's avatar
Andrey Filippov committed
528
        if      (hrst)                              read_pages_ready <= 0;
529
        else if (!read_busy)                        read_pages_ready <= 0;
530 531
        else if ( page_ready_rd && !done_page_rd_w) read_pages_ready <= read_pages_ready +1;
        else if (!page_ready_rd &&  done_page_rd_w) read_pages_ready <= read_pages_ready -1;
532
        
Andrey Filippov's avatar
Andrey Filippov committed
533 534
        if (hrst) afi_wd_safe_not_full <= 0;
        else      afi_wd_safe_not_full <=  rdwr_en && (!afi_wcount[7] && !(&afi_wcount[6:3]));
535

Andrey Filippov's avatar
Andrey Filippov committed
536 537
        if (hrst) afi_wa_safe_not_full <= 0;
        else      afi_wa_safe_not_full <=  rdwr_en && (!afi_wacount[5] && !(&afi_wacount[4:2]));
538
        
Andrey Filippov's avatar
Andrey Filippov committed
539 540
        if (hrst) busy <= 0;
        else      busy <=  read_busy || write_busy;
541
        
Andrey Filippov's avatar
Andrey Filippov committed
542
        if (hrst) pre_done <= 0; // delay done to turn on same time busy is off
543 544
        else     pre_done <= (write_busy && frame_done) || (read_busy && read_over);
        
Andrey Filippov's avatar
Andrey Filippov committed
545
        if      (hrst)           done <= 0;
546 547 548
        else if (!rdwr_en)       done <= 0; // disabling when idle will reset done
        else if (pre_done)       done <= 1;
        else if (rdwr_start)     done <= 0;
549
        
550 551 552 553 554 555
        if      (hrst )       read_no_more <= 0;
        else if (!read_busy)  read_no_more <= 0;
        else if (frame_done)  read_no_more <= 1;
        
        
        
556 557 558 559 560 561 562
    end
    
    // handle interaction with the buffer, advance addresses, keep track of partial (last) pages in each line
    wire                       bufrd_rd_w;
    wire                       bufwr_we_w; // TODO: assign
    
    reg                  [2:0] bufrd_rd;
563
    reg   [BUFWR_WE_WIDTH-1:0] bufwr_we;
564 565 566 567 568
    reg                        buf_rdwr; // equiv to  bufrd_rd[0] || bufwr_we)
    wire                       is_last_in_line;
    wire                       is_last_in_page;
    wire                       next_page_rd_w;
    wire                       next_page_wr_w;
569 570 571 572 573 574
    wire                       done_page_rd_w;
    wire                       safe_some_left_rd_w;
    reg                        left_was_1; // was <=1 (0 does not matter)  valid next after buffer address
    reg                        left_many;
    
    
575
//    assign next_page_rd_w = read_started && !busy_next_page && is_last_in_page && bufrd_rd[0];
576 577
    assign done_page_rd_w = read_started && is_last_in_page && bufrd_rd[0];
    assign next_page_rd_w = done_page_rd_w && !read_no_more;
578 579
    assign is_last_in_line = buf_in_line64 == last_in_line64;
    assign is_last_in_page = is_last_in_line || (&buf_in_line64[6:0]);
580 581
//    assign safe_some_left_rd_w =  (axi_wr_left[7:1]!=0) || (axi_wr_left[0] && !bufrd_rd[0]);
    assign safe_some_left_rd_w =  left_many || (|buf_left64[1:0] && !(|bufrd_rd)); // Fine tune
582
`ifdef MEMBRIDGE_DEBUG_READ
583 584
    assign bufrd_rd_w = safe_some_left_rd_w && !read_over && afi_wd_safe_not_full &&
                        (|read_pages_ready[2:1] || (read_pages_ready[0] && (!is_last_in_page || read_no_more))) && debug_w_ready;
585
`else
586 587 588 589
//  assign bufrd_rd_w =               afi_wd_safe_not_full && (|read_pages_ready[2:1] || (read_pages_ready[0] && !is_last_in_page));
    
    assign bufrd_rd_w = safe_some_left_rd_w && !read_over && afi_wd_safe_not_full &&
                        (|read_pages_ready[2:1] || (read_pages_ready[0] && (!is_last_in_page || read_no_more)));
590
`endif    
591 592
//last_in_line64 - last word number in scan line
    reg                  [3:0] src_wcntr;
593 594
//    reg                  [2:0] wlast_in_burst;
    reg                        wlast; // valid 2 after buffer address, same as wvalid
595
    
596 597 598 599 600
    reg                        src_was_f;  // valid next after buffer address

//    assign afi_wlast = wlast_in_burst[2];
    assign afi_wlast = wlast;

601 602 603 604
    always @ (posedge hclk) begin
        if (!rw_in_progress) left_was_1 <= 0;
        else if   (buf_rdwr) left_was_1 <= !(|buf_left64[28:1]);
        
605 606 607 608 609 610
/*        if (!rw_in_progress) left_many <= 0;
        else if   (buf_rdwr) */
        
        left_many <= |buf_left64[28:2];


611 612 613
        if    (!read_started) src_wcntr <= 0;
        else if (bufrd_rd[0]) src_wcntr <= src_wcntr+1;
        
614 615 616 617 618 619 620 621 622
        if    (!read_started) src_was_f <= 0;          
        else if (bufrd_rd[0]) src_was_f <= &src_wcntr; // valid with buffer address
        
//        if    (!read_started) wlast_in_burst <= 0;
//        else if (bufrd_rd[0]) wlast_in_burst <= {wlast_in_burst[1:0],left_was_1 | (&src_wcntr)};

        if    (!read_started) wlast <= 0;
        else if (bufrd_rd[1]) wlast <= left_was_1 || src_was_f;
        
623 624
        
        bufrd_rd <= {bufrd_rd[1:0], bufrd_rd_w };
625 626 627
`ifdef MEMBRIDGE_DEBUG_READ
        debug_bufrd_rd<= {debug_bufrd_rd[3:0], bufrd_rd_w };
`endif        
628
        buf_rdwr <= bufrd_rd_w || bufwr_we_w;
629
        bufwr_we <= {bufwr_we[BUFWR_WE_WIDTH-2:0],bufwr_we_w};
630 631 632 633 634 635 636 637 638 639 640 641
        
    end
    assign afi_wvalid=bufrd_rd[2];

    // write to ddr3 from afi
    reg        afi_rd_safe_not_empty;
    reg        afi_ra_safe_not_full;
    reg        afi_safe_rd_pending;
 //    assign advance_rel_addr_wr = read_started && afi_wa_safe_not_full && (|left64); // left 64 is decremented by 16, except possibly the last (partial)
    assign advance_rel_addr_rd = write_busy && afi_ra_safe_not_full && afi_safe_rd_pending && (|left64);
    assign afi_arvalid=advance_rel_addr && write_busy;

642 643
//    assign next_page_wr_w = write_busy && !busy_next_page && is_last_in_page && bufwr_we[0];
    assign next_page_wr_w = write_busy && is_last_in_page && bufwr_we[0];
644 645 646 647 648 649 650 651 652 653 654
    
    assign bufwr_we_w= afi_rd_safe_not_empty && !write_pages_ready[2] && (!(&write_pages_ready[1:0]) ||  !is_last_in_page);
    
    // handle buffer address, page 
    reg  [1:0] write_page;        // current number of buffer page
    reg  [2:0] write_pages_ready; // number of pages in the buffer
    reg  [1:0] write_page_r;      // 1-cycle delayed page address
    reg  [6:0] buf_in_line64_r;   // 1-cycle delayed buffer address
    
    assign afi_rready = bufwr_we[0];

Andrey Filippov's avatar
Andrey Filippov committed
655 656
    always @ (posedge hclk) begin
        if      (hrst)       write_busy <= 0;
657
        else if (wr_start)   write_busy <= 1;
658
        else if (!wr_mode)   write_busy <= 0; // Just debugging, making sure write mode is disabled in read mode
659 660
        else if (frame_done) write_busy <= 0;

Andrey Filippov's avatar
Andrey Filippov committed
661
        if      (hrst)                          axi_arw_requested <= 0;
662 663
        else if (!write_busy && !read_started)  axi_arw_requested <= 0;
        else if (advance_rel_addr)              axi_arw_requested <= axi_arw_requested + afi_len_plus1;
664
        
Andrey Filippov's avatar
Andrey Filippov committed
665
        if      (hrst)                          axi_bursts_requested <= 0;
666 667
        else if (!write_busy && !read_started)  axi_bursts_requested <= 0;
        else if (advance_rel_addr)              axi_bursts_requested <= axi_bursts_requested + 1;
668

669 670 671 672 673 674 675 676
        if      (hrst)                          axi_rd_received <= 0;
        else if (!write_busy)                   axi_rd_received <= 0;
        else if (bufwr_we[0])                   axi_rd_received <= axi_rd_received + 1;

        if      (hrst)                                        axi_wr_left <= 0;
        else if (!read_started)                               axi_wr_left <= 0;
        else if ( advance_rel_addr && !(wlast && afi_wvalid)) axi_wr_left <= axi_wr_left + 1;
        else if (!advance_rel_addr &&  (wlast && afi_wvalid)) axi_wr_left <= axi_wr_left - 1;
677 678
        
        
Andrey Filippov's avatar
Andrey Filippov committed
679
        if (hrst) afi_rd_safe_not_empty <= 0;
680 681
         // allow 1 cycle latency, no continuous reads when FIFO is low (like in the very end of the transfer)
         // Adjust '2' in afi_rcount[6:2] ? 
682
        else     afi_rd_safe_not_empty <= rdwr_en && ( afi_rcount[7] || (|afi_rcount[6:SAFE_RD_BITS]) || (!(|bufwr_we) && !bufwr_we_w && afi_rvalid));
683

Andrey Filippov's avatar
Andrey Filippov committed
684 685
        if (hrst) afi_ra_safe_not_full <= 0;
        else      afi_ra_safe_not_full <= rdwr_en && ( !afi_racount[2] && !(&afi_racount[1:0]));
686
        
Andrey Filippov's avatar
Andrey Filippov committed
687
        if      (hrst)        afi_safe_rd_pending <= 0;
688 689
        else if (!write_busy) afi_safe_rd_pending <= 0;
        else                  afi_safe_rd_pending <= rdwr_en && ( !axi_rd_pending[7] && !(&axi_rd_pending[6:4]));
690 691
        
        // handle buffer address, page 
Andrey Filippov's avatar
Andrey Filippov committed
692
        if      (hrst)           write_page <= 0;
693 694 695
        else if (reset_page_wr)  write_page <= 0;
        else if (next_page_wr_w) write_page <= write_page + 1;

Andrey Filippov's avatar
Andrey Filippov committed
696
        if      (hrst)                              write_pages_ready <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
697
        else if (!write_busy)                       write_pages_ready <= 0;
698 699 700 701
        else if ( page_ready_wr && !next_page_wr_w) write_pages_ready <= write_pages_ready -1; //+1;
        else if (!page_ready_wr &&  next_page_wr_w) write_pages_ready <= write_pages_ready +1; //-1;

    end
702 703 704 705 706 707 708 709
`ifdef MEMBRIDGE_DEBUG_WRITE
    reg [30:0] dbg_read_counter;
    always @ (posedge hclk) begin
        if     (!write_busy )  dbg_read_counter <= 0;
        else if (bufwr_we[0])  dbg_read_counter <= dbg_read_counter + 1;
    end
`endif    
    
710
    reg [63:0] rdata_r;        
711 712 713
    always @ (posedge hclk) begin
        write_page_r    <= write_page;
        buf_in_line64_r <= buf_in_line64[6:0];
714
//        rdata_r <= afi_rdata;
715 716 717
`ifdef MEMBRIDGE_DEBUG_WRITE
        rdata_r <= cache_debug?{dbg_read_counter,1'h1,dbg_read_counter,1'h0}:afi_rdata[63:0]; // debugging
`else        
718
        rdata_r <= cache_debug?{wr_id[3:0],2'b0,write_page_r[1:0],afi_rcount[7:0],afi_rdata[47:0]}:afi_rdata[63:0]; // debugging
719
`endif        
720 721 722 723 724 725 726 727 728
    end    
        
    cmd_deser #(
        .ADDR       (MEMBRIDGE_ADDR),
        .ADDR_MASK  (MEMBRIDGE_MASK),
        .NUM_CYCLES (6),
        .ADDR_WIDTH (4),
        .DATA_WIDTH (32)
    ) cmd_deser_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
729 730 731 732 733 734 735 736
        .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[3:0] 
        .data       (cmd_data),  // output[31:0] 
        .we         (cmd_we)     // output
737 738 739 740
    );

    status_generate #(
        .STATUS_REG_ADDR  (MEMBRIDGE_STATUS_REG),
741 742 743
`ifdef MEMBRIDGE_DEBUG_READ
        .PAYLOAD_BITS     (18) // 2) // With debug
`else
744
        .PAYLOAD_BITS     (18) //2)
745
`endif        
746
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
747 748 749 750 751
        .rst              (1'b0),                                            //   rst), // input
        .clk              (mclk),                                            // input
        .srst             (mrst),                                            // input
        .we               (set_status_w),                                    // input
        .wd               (cmd_data[7:0]),                                   // input[7:0]
752 753 754
`ifdef MEMBRIDGE_DEBUG_READ
        .status           ({debug_aw_allowed, debug_w_allowed, done, busy}), // input[25:0]
`else
Andrey Filippov's avatar
Andrey Filippov committed
755
        .status           ({axi_arw_requested, wresp_conf, done, busy}),     // input[25:0] 
756
`endif
Andrey Filippov's avatar
Andrey Filippov committed
757 758 759
        .ad               (status_ad),                                       // output[7:0] 
        .rq               (status_rq),                                       // output
        .start            (status_start)                                     // input
760 761 762
    );

// Port 1rd (read DDR to AFI) buffer, linear
763 764 765 766 767 768 769 770 771 772 773 774 775
wire [63:0] afi_wdata0;
`ifdef MEMBRIDGE_DEBUG_WRITE
    reg [15:0] dbg_write_counter;
    always @ (posedge hclk) begin
        if (!read_busy || !cache_debug) dbg_write_counter <= 0;
        else if (bufrd_rd[1])          dbg_write_counter <= dbg_write_counter + 1;
    end
    assign afi_wdata = {afi_wdata0[63:16], dbg_write_counter[0]? dbg_write_counter[15:0]: afi_wdata0[15:0]};
`else
    assign afi_wdata = afi_wdata0;
`endif


776 777 778
    mcntrl_buf_rd #(
        .LOG2WIDTH_RD(6) // 64 bit external interface
    ) chn1rd_buf_i (
Andrey Filippov's avatar
Andrey Filippov committed
779
        .ext_clk      (hclk),                           // input
780
        .ext_raddr    ({read_page,buf_in_line64[6:0]}), // input[8:0] 
Andrey Filippov's avatar
Andrey Filippov committed
781 782
        .ext_rd       (bufrd_rd[0]),                    // input
        .ext_regen    (bufrd_rd[1]),                    // input
783 784
        .ext_data_out (afi_wdata0),                     // output[63:0]
//        .emul64       (1'b0),                           // input Modify buffer addresses (used for JP4 until a 64-wide mode is implemented)
Andrey Filippov's avatar
Andrey Filippov committed
785 786 787 788 789 790 791
        .wclk         (!mclk),                          // input
        .wpage_in     (2'b0),                           // input[1:0] 
        .wpage_set    (xfer_reset_page_rd),             // input  TODO: Generate @ negedge mclk on frame start
        .page_next    (buf_wpage_nxt),                  // input
        .page         (),                               // output[1:0]
        .we           (buf_wr),                         // input
        .data_in      (buf_wdata)                       // input[63:0] 
792 793 794 795 796 797
    );

// Port 1wr (write DDR from AFI) buffer, linear
    mcntrl_buf_wr #(
         .LOG2WIDTH_WR(6)  // 64 bit external interface
    ) chn1wr_buf_i (
Andrey Filippov's avatar
Andrey Filippov committed
798
        .ext_clk      (hclk),                                 // input
799
        .ext_waddr    ({write_page_r, buf_in_line64_r[6:0]}), // input[8:0] 
Andrey Filippov's avatar
Andrey Filippov committed
800 801 802 803 804 805 806 807 808
        .ext_we       (bufwr_we[1]),                          // input
        .ext_data_in  (rdata_r),                              //afi_rdata), // input[63:0] buf_wdata - from AXI
        .rclk         (mclk),                                 // input
        .rpage_in     (2'b0),                                 // input[1:0] 
        .rpage_set    (xfer_reset_page_wr),                   // input  @ posedge mclk
        .page_next    (buf_rpage_nxt),                        // input
        .page         (),                                     // output[1:0]
        .rd           (buf_rd),                               // input
        .data_out     (buf_rdata)                             // output[63:0] 
809 810
    );

811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
`ifdef DEBUG_RING
    debug_slave #(
        .SHIFT_WIDTH       (32),
        .READ_WIDTH        (32),
        .WRITE_WIDTH       (32),
        .DEBUG_CMD_LATENCY (DEBUG_CMD_LATENCY)
    ) debug_slave_i (
        .mclk       (mclk),          // input
        .mrst       (mrst),          // input
        .debug_di   (debug_di), // input
        .debug_sl   (debug_sl),      // input
        .debug_do   (debug_do), // output
        .rd_data   ({
        5'b0, afi_racount[2:0],
        afi_rcount[7:0],
        2'b0, afi_wacount[5:0],
        afi_wcount[7:0]
        }), // input[31:0]
        .wr_data    (), // output[31:0]  - not used
        .stb        () // output  - not used
    );
`endif    

834 835
endmodule