axibram_write.v 11.6 KB
Newer Older
1 2 3 4 5 6 7
/*!
 * <b>Module:</b>axibram_write
 * @file axibram_write.v
 * @date 2014-03-18  
 * @author Andrey Filippov
 *
 * @brief Read block RAM memory (or memories?) over AXI PS Master GP0
8 9
 * Memory is supposed to be fast enough
 *
10 11 12 13
 * @copyright Copyright (c) 2014 Elphel, Inc.
 *
 * <b>License:</b>
 *
14 15 16 17 18 19 20 21 22 23 24 25
 * 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/> .
26 27 28 29 30 31
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
32
 * files and/or simulating the code, the copyright holders of this Program give
33 34
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
Andrey Filippov's avatar
Andrey Filippov committed
35
 * charge, and there is no dependence on any encrypted modules for simulating of
36 37 38
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
39
 */
40
//`define DEBUG_FIFO 1 
41
`include "system_defines.vh" 
42 43 44
`ifdef DEBUG_FIFO
  `undef DEBUG_FIFO
`endif
45
module  axibram_write #(
46 47 48
    parameter ADDRESS_BITS = 10 // number of memory address bits
)(
   input         aclk,    // clock - should be buffered
Andrey Filippov's avatar
Andrey Filippov committed
49
   input         arst,     // @aclk sync reset, active high
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
   
// 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  [ 3:0] awlen,   // AWLEN[3:0], input
   input  [ 1:0] awsize,  // AWSIZE[1:0], input
   input  [ 1:0] awburst, // AWBURST[1: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
Andrey Filippov's avatar
Andrey Filippov committed
66
// AXI PS Master GP0: Write response
67 68 69 70 71
   output        bvalid,  // BVALID, output
   input         bready,  // BREADY, input
   output [11:0] bid,     // BID[11:0], output
   output [ 1:0] bresp,    // BRESP[1:0], output
   
72 73 74 75 76
// 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
    
77 78
   output        bram_wclk,
   output  [ADDRESS_BITS-1:0] bram_waddr,
79 80
   output        pre_bram_wen,// 1 ahead of bram_wen, not masked by dev_ready
   output        bram_wen,    // external memory write enable, (internally combined with registered dev_ready
81 82
   output  [3:0] bram_wstb, 
   output [31:0] bram_wdata
Andrey Filippov's avatar
Andrey Filippov committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
`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   
110
);
111
//    wire rst=~aresetn;
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
// **** 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
133
    reg  [ 3:0] write_left;          // number of write transfers
134 135 136 137
// 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;
138
    wire        bram_we_w; //,bram_we_nonmasked;   // write BRAM memory non-masked - should be combined with  
139 140
    wire        start_write_burst_w;
    wire        write_in_progress_w;
141 142 143 144 145 146
    
    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?
    
147
    reg         dev_ready_r;        // device, selected at start burst
148
    assign      next_wr_address_w= //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 13-bit target.
149 150 151 152
      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]));
        
153
    assign      bram_we_w=         w_nempty_ready &&  write_in_progress;
154 155 156 157 158
//    assign start_write_burst_w=w_nempty_ready && 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))); 
    // adding wlast_out to take precedence over (write_left[3:0]==4'b0), maybe wlast_out itself is sufficient
    assign start_write_burst_w=w_nempty_ready && aw_nempty_ready && (!write_in_progress || (w_nempty_ready && ((write_left[3:0]==4'b0) || wlast_out)));
    assign write_in_progress_w=w_nempty_ready && aw_nempty_ready || (write_in_progress && !(w_nempty_ready && ((write_left[3:0]==4'b0) || wlast_out))); 
159
    
160
    assign pre_bram_wen = write_in_progress_w;
Andrey Filippov's avatar
Andrey Filippov committed
161 162
    always @ (posedge  aclk) begin
      if   (arst)                   wburst[1:0] <= 0;
163 164
      else if (start_write_burst_w) wburst[1:0] <= awburst_out[1:0];

Andrey Filippov's avatar
Andrey Filippov committed
165
      if   (arst)                   wlen[3:0] <= 0;
166 167
      else if (start_write_burst_w) wlen[3:0] <= awlen_out[3:0];
    
Andrey Filippov's avatar
Andrey Filippov committed
168 169
      if   (arst) write_in_progress <= 0;
      else        write_in_progress <= write_in_progress_w;
170

Andrey Filippov's avatar
Andrey Filippov committed
171
      if   (arst)                   write_left <= 0;
172
      else if (start_write_burst_w) write_left <= awlen_out[3:0]; // precedence over inc
173
      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.
174
            
Andrey Filippov's avatar
Andrey Filippov committed
175
      if   (arst)                   write_address <= {ADDRESS_BITS{1'b0}};
176 177
      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;
178
      
Andrey Filippov's avatar
Andrey Filippov committed
179 180
      if (arst) dev_ready_r <= 1'b0;
      else      dev_ready_r <= dev_ready;
181
    end
182
// **** Write response channel ****    
183 184 185
    wire [ 1:0] bresp_in;
    assign bresp_in=2'b0;

186 187 188 189
// external memory interface (write only)
   assign pre_awaddr=awaddr_out[ADDRESS_BITS-1:0];
   assign start_burst=start_write_burst_w;
   
190 191 192 193 194 195
   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
196 197 198 199 200 201 202 203
 `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))
204
    waddr_i (
Andrey Filippov's avatar
Andrey Filippov committed
205
        .rst       (1'b0), //rst),
Andrey Filippov's avatar
Andrey Filippov committed
206
        .clk       (aclk),
Andrey Filippov's avatar
Andrey Filippov committed
207
        .sync_rst  (arst),
Andrey Filippov's avatar
Andrey Filippov committed
208 209
        .we        (awvalid && awready),
        .re        (start_write_burst_w),
210
        .data_in   ({awid[11:0], awburst[1:0],awsize[1:0],awlen[3:0],awaddr[ADDRESS_BITS+1:2]}),
Andrey Filippov's avatar
Andrey Filippov committed
211 212 213 214 215 216 217 218 219 220 221
        .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         
222
    );
223
fifo_same_clock   #( .DATA_WIDTH(49),.DATA_DEPTH(4))    
224
    wdata_i (
Andrey Filippov's avatar
Andrey Filippov committed
225
        .rst(1'b0), //rst),
226
        .clk(aclk),
Andrey Filippov's avatar
Andrey Filippov committed
227
        .sync_rst  (arst),
228 229 230
        .we(wvalid && wready),
        .re(bram_we_w), //start_write_burst_w), // wrong
        .data_in({wid[11:0],wlast,wstb[3:0],wdata[31:0]}),
231
        .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
232 233
        .nempty(w_nempty),
        .half_full(w_half_full)
Andrey Filippov's avatar
Andrey Filippov committed
234 235 236 237 238 239 240 241
`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
242
    );
Andrey Filippov's avatar
Andrey Filippov committed
243 244 245 246
//debugging - slow down bresp
reg was_bresp_re=0;
wire bresp_re;
assign bresp_re=bready && bvalid && !was_bresp_re;
Andrey Filippov's avatar
Andrey Filippov committed
247 248 249
always @ (posedge aclk) begin
    if (arst) was_bresp_re<=0;
    else      was_bresp_re <= bresp_re;
Andrey Filippov's avatar
Andrey Filippov committed
250 251
end
  
252
fifo_same_clock  #( .DATA_WIDTH(14),.DATA_DEPTH(4))    
253
    wresp_i (
Andrey Filippov's avatar
Andrey Filippov committed
254
        .rst(1'b0), //rst),
255
        .clk(aclk),
Andrey Filippov's avatar
Andrey Filippov committed
256
        .sync_rst  (arst),
257
        .we(bram_we_w &&((write_left[3:0]==4'b0) || wlast_out)), // added ((write_left[3:0]==4'b0) || wlast_out) - only last wrtite -> bresp
Andrey Filippov's avatar
Andrey Filippov committed
258 259
//        .re(bready && bvalid),
        .re(bresp_re), // not allowing RE next cycle after bvalid
260 261 262 263
        .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
264 265 266 267 268 269 270 271 272
`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
273 274 275
    );

endmodule