axibram_write.v 10.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*******************************************************************************
 * Module: axibram_write
 * Date:2014-03-18  
 * Author: Andrey Filippov
 * Description: Read block RAM memory (or memories?) over AXI PS Master GP0
 * Memory is supposed to be fast enough
 *
 * Copyright (c) 2014 Elphel, Inc.
 * axibram_write.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.
 *
 *  axibram_write.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/> .
 *******************************************************************************/
22
//`define DEBUG_FIFO 1 
23
`include "system_defines.vh" 
24
`undef DEBUG_FIFO
25
module  axibram_write #(
26 27 28
    parameter ADDRESS_BITS = 10 // number of memory address bits
)(
   input         aclk,    // clock - should be buffered
29 30
//   input         aresetn, // reset, active low
   input         rst,     // reset, active highw
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
   
// AXI Write Address
   input  [31:0] awaddr,  // AWADDR[31:0], input
   input         awvalid, // AWVALID, input
   output        awready, // AWREADY, output
   input  [11:0] awid,    // AWID[11:0], input
//   input  [ 1:0] awlock,  // AWLOCK[1:0], input
//   input  [ 3:0] awcache, // AWCACHE[3:0], input
//   input  [ 2:0] awprot,  // AWPROT[2:0], input
   input  [ 3:0] awlen,   // AWLEN[3:0], input
   input  [ 1:0] awsize,  // AWSIZE[1:0], input
   input  [ 1:0] awburst, // AWBURST[1:0], input
//   input  [ 3:0] awqos,   // AWQOS[3:0], input
// AXI PS Master GP0: Write Data
   input  [31:0] wdata,   // WDATA[31:0], input
   input         wvalid,  // WVALID, input
   output        wready,  // WREADY, output
   input  [11:0] wid,     // WID[11:0], input
   input         wlast,   // WLAST, input
   input  [ 3:0] wstb,    // WSTRB[3:0], input
// AXI PS Master GP0: Write Responce
   output        bvalid,  // BVALID, output
   input         bready,  // BREADY, input
   output [11:0] bid,     // BID[11:0], output
   output [ 1:0] bresp,    // BRESP[1:0], output
   
57 58 59 60 61
// BRAM (and other write modules) interface
   output [ADDRESS_BITS-1:0] pre_awaddr, // same as awaddr_out, early address to decode and return dev_ready
   output        start_burst, // start of write burst, valid pre_awaddr, save externally to control ext. dev_ready multiplexer
   input         dev_ready,   // extrernal combinatorial ready signal, multiplexed from different sources according to pre_awaddr@start_burst
    
62 63
   output        bram_wclk,
   output  [ADDRESS_BITS-1:0] bram_waddr,
64
   output        bram_wen,    // external memory wreite enable, (internally combined with registered dev_ready
65 66
   output  [3:0] bram_wstb, 
   output [31:0] bram_wdata
Andrey Filippov's avatar
Andrey Filippov committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
`ifdef DEBUG_FIFO
    ,
        output    waddr_under,
        output    wdata_under,
        output    wresp_under, 
        output    waddr_over,
        output    wdata_over,
        output    wresp_over,
        
        output [3:0]   waddr_wcount, 
        output [3:0]   waddr_rcount, 
        output [3:0]   waddr_num_in_fifo, 
        
        output [3:0]   wdata_wcount, 
        output [3:0]   wdata_rcount, 
        output [3:0]   wdata_num_in_fifo, 
        
        output [3:0]   wresp_wcount, 
        output [3:0]   wresp_rcount, 
        output [3:0]   wresp_num_in_fifo,
        
        output [3:0]   wleft,
        
        output [3:0]   wlength,
        output reg [3:0] wlen_in_dbg  

`endif   
94
);
95
//    wire rst=~aresetn;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
// **** Write channel: ****
    wire aw_nempty;
    wire aw_half_full;
    assign awready=~aw_half_full;
    wire [ 1:0] awburst_out;
    // SuppressWarnings VEditor all 
    wire [ 1:0] awsize_out; // not used
    wire [ 3:0] awlen_out;
    wire [ADDRESS_BITS-1:0] awaddr_out;
    // SuppressWarnings VEditor all 
    wire [11:0] awid_out;   // not used
    wire w_nempty;
    wire w_half_full;
    assign wready=~w_half_full;
    wire [31:0] wdata_out;
    // SuppressWarnings VEditor all 
    wire        wlast_out;   // not used
    wire [ 3:0] wstb_out;    // WSTRB[3:0], input
    wire [11:0] wid_out;
    reg         write_in_progress=0;
    reg  [ADDRESS_BITS-1:0] write_address;       // transfer address (not including lower bits 
Andrey Filippov's avatar
Andrey Filippov committed
117
    reg  [ 3:0] write_left;          // number of write transfers
118 119 120 121
// will ignore arsize - assuming always 32 bits  (a*size[2:0]==2)
    reg  [ 1:0] wburst;             // registered burst type
    reg  [ 3:0] wlen;               // registered awlen type (for wrapped over transfers)
    wire [ADDRESS_BITS-1:0] next_wr_address_w;  // next transfer address;
122
    wire        bram_we_w; //,bram_we_nonmasked;   // write BRAM memory non-masked - should be combined with  
123 124
    wire        start_write_burst_w;
    wire        write_in_progress_w;
125 126 127 128 129 130
    
    wire        aw_nempty_ready; // aw_nempty and device ready
    wire        w_nempty_ready; // w_nempty and device ready
    assign aw_nempty_ready=aw_nempty && dev_ready_r; // should it be dev_ready?
    assign w_nempty_ready=w_nempty && dev_ready_r; // should it be dev_ready?
    
131
    reg         dev_ready_r;        // device, selected at start burst
132
    assign      next_wr_address_w= //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 13-bit target.
133 134 135 136
      wburst[1]?
        (wburst[0]? {ADDRESS_BITS{1'b0}}:((write_address[ADDRESS_BITS-1:0]+1) & {{(ADDRESS_BITS-4){1'b1}}, ~wlen[3:0]})):
        (wburst[0]? (write_address[ADDRESS_BITS-1:0]+1):(write_address[ADDRESS_BITS-1:0]));
        
137 138
    assign      bram_we_w=         w_nempty_ready &&  write_in_progress;
    assign start_write_burst_w=w_nempty_ready && aw_nempty_ready && (!write_in_progress || (w_nempty_ready && (write_left[3:0]==4'b0)));
Andrey Filippov's avatar
Andrey Filippov committed
139 140
//    assign write_in_progress_w=                  aw_nempty_ready || (write_in_progress && !(w_nempty_ready && (write_left[3:0]==4'b0))); 
    assign write_in_progress_w=w_nempty_ready && aw_nempty_ready || (write_in_progress && !(w_nempty_ready && (write_left[3:0]==4'b0))); 
141 142 143 144 145 146 147 148 149 150 151 152 153
    
    always @ (posedge  aclk or posedge  rst) begin
      if   (rst)                    wburst[1:0] <= 0;
      else if (start_write_burst_w) wburst[1:0] <= awburst_out[1:0];

      if   (rst)                    wlen[3:0] <= 0;
      else if (start_write_burst_w) wlen[3:0] <= awlen_out[3:0];
    
      if   (rst) write_in_progress <= 0;
      else       write_in_progress <= write_in_progress_w;

      if   (rst) write_left <= 0;
      else if (start_write_burst_w) write_left <= awlen_out[3:0]; // precedence over inc
154
      else if (bram_we_w)           write_left <= write_left-1; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 4-bit target.
155 156 157 158
            
      if   (rst)                    write_address <= {ADDRESS_BITS{1'b0}};
      else if (start_write_burst_w) write_address <= awaddr_out[ADDRESS_BITS-1:0]; // precedence over inc
      else if (bram_we_w)           write_address <= next_wr_address_w;
159 160 161
      
      if (rst) dev_ready_r <= 1'b0;
      else     dev_ready_r <= dev_ready;
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    end
// **** Write responce channel ****    
    wire [ 1:0] bresp_in;
    assign bresp_in=2'b0;
        
/*
   output        bvalid,  // BVALID, output
   input         bready,  // BREADY, input
   output [11:0] bid,     // BID[11:0], output
   output [ 1:0] bresp    // BRESP[1:0], output

*/
/*    
    reg bram_reg_re_r;
    always @ (posedge aclk) begin
        bram_reg_re_r <= bram_reg_re_w;
    end
*/

181 182 183 184
// external memory interface (write only)
   assign pre_awaddr=awaddr_out[ADDRESS_BITS-1:0];
   assign start_burst=start_write_burst_w;
   
185 186 187 188 189 190
   assign  bram_wclk  = aclk;
   assign  bram_waddr = write_address[ADDRESS_BITS-1:0];
   assign  bram_wen   = bram_we_w; 
   assign  bram_wstb   = wstb_out[3:0]; 
   assign  bram_wdata = wdata_out[31:0];
    
Andrey Filippov's avatar
Andrey Filippov committed
191 192 193 194 195 196 197 198
 `ifdef DEBUG_FIFO
    assign wleft=write_left;
    assign wlength[3:0]=wlen[3:0];
    always @ (posedge aclk) begin
        wlen_in_dbg <= awlen[3:0];
    end
 `endif  
fifo_same_clock   #( .DATA_WIDTH(20+ADDRESS_BITS),.DATA_DEPTH(4))
199
    waddr_i (
Andrey Filippov's avatar
Andrey Filippov committed
200 201
        .rst       (rst),
        .clk       (aclk),
202
        .sync_rst  (1'b0),
Andrey Filippov's avatar
Andrey Filippov committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216
        .we        (awvalid && awready),
        .re        (start_write_burst_w),
        .data_in   ({awid[11:0], awburst[1:0],awsize[1:0],awlen[3:0],awaddr[ADDRESS_BITS+1:2]}),
        .data_out  ({awid_out[11:0], awburst_out[1:0],awsize_out[1:0],awlen_out[3:0],awaddr_out[ADDRESS_BITS-1:0]}),  //SuppressThisWarning ISExst Assignment to awsize_out ignored, since the identifier is never used
        .nempty    (aw_nempty),
        .half_full (aw_half_full)
`ifdef DEBUG_FIFO
        ,
        .under      (waddr_under), // output reg 
        .over       (waddr_over), // output reg
        .wcount     (waddr_wcount), // output[3:0] reg 
        .rcount     (waddr_rcount), // output[3:0] reg 
        .num_in_fifo(waddr_num_in_fifo) // output[3:0] 
`endif         
217
    );
218
fifo_same_clock   #( .DATA_WIDTH(49),.DATA_DEPTH(4))    
219 220 221
    wdata_i (
        .rst(rst),
        .clk(aclk),
222
        .sync_rst  (1'b0),
223 224 225
        .we(wvalid && wready),
        .re(bram_we_w), //start_write_burst_w), // wrong
        .data_in({wid[11:0],wlast,wstb[3:0],wdata[31:0]}),
226
        .data_out({wid_out[11:0],wlast_out,wstb_out[3:0],wdata_out[31:0]}), //SuppressThisWarning ISExst Assignment to wlast ignored, since the identifier is never used
227 228
        .nempty(w_nempty),
        .half_full(w_half_full)
Andrey Filippov's avatar
Andrey Filippov committed
229 230 231 232 233 234 235 236
`ifdef DEBUG_FIFO
        ,
        .under      (wdata_under), // output reg 
        .over       (wdata_over), // output reg
        .wcount     (wdata_wcount), // output[3:0] reg 
        .rcount     (wdata_rcount), // output[3:0] reg 
        .num_in_fifo(wdata_num_in_fifo) // output[3:0] 
`endif
237
    );
Andrey Filippov's avatar
Andrey Filippov committed
238 239 240 241 242 243 244 245 246
//debugging - slow down bresp
reg was_bresp_re=0;
wire bresp_re;
assign bresp_re=bready && bvalid && !was_bresp_re;
always @ (posedge rst or posedge aclk) begin
    if (rst) was_bresp_re<=0;
    else was_bresp_re <= bresp_re;
end
  
247
fifo_same_clock  #( .DATA_WIDTH(14),.DATA_DEPTH(4))    
248 249 250
    wresp_i (
        .rst(rst),
        .clk(aclk),
251
        .sync_rst  (1'b0),
252
        .we(bram_we_w),
Andrey Filippov's avatar
Andrey Filippov committed
253 254
//        .re(bready && bvalid),
        .re(bresp_re), // not allowing RE next cycle after bvalid
255 256 257 258
        .data_in({wid_out[11:0],bresp_in[1:0]}),
        .data_out({bid[11:0],bresp[1:0]}),
        .nempty(bvalid),
        .half_full()
Andrey Filippov's avatar
Andrey Filippov committed
259 260 261 262 263 264 265 266 267
`ifdef DEBUG_FIFO
        ,
        .under      (wresp_under), // output reg 
        .over       (wresp_over), // output reg
        .wcount     (wresp_wcount), // output[3:0] reg 
        .rcount     (wresp_rcount), // output[3:0] reg 
        .num_in_fifo(wresp_num_in_fifo) // output[3:0] 
        
`endif
268 269 270
    );

endmodule