axibram_write.v 7.68 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
module  axibram_write #(
23 24 25
    parameter ADDRESS_BITS = 10 // number of memory address bits
)(
   input         aclk,    // clock - should be buffered
26 27
//   input         aresetn, // reset, active low
   input         rst,     // reset, active highw
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   
// 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
   
54 55 56 57 58
// 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
    
59 60
   output        bram_wclk,
   output  [ADDRESS_BITS-1:0] bram_waddr,
61
   output        bram_wen,    // external memory wreite enable, (internally combined with registered dev_ready
62 63 64
   output  [3:0] bram_wstb, 
   output [31:0] bram_wdata
);
65
//    wire rst=~aresetn;
66 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 94
// **** 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 
    reg  [ 3:0] write_left;          // number of read transfers
// 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;
    wire        bram_we_w;          // write BRAM memory 
    wire        start_write_burst_w;
    wire        write_in_progress_w;
95
    reg         dev_ready_r;        // device, selected at start burst
96 97 98 99 100
    assign      next_wr_address_w=
      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]));
        
101
    assign      bram_we_w= w_nempty &&  write_in_progress && dev_ready_r;
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    assign start_write_burst_w=aw_nempty && (!write_in_progress || (w_nempty && (write_left[3:0]==4'b0)));
    assign write_in_progress_w=aw_nempty || (write_in_progress && !(w_nempty && (write_left[3:0]==4'b0))); 
    
    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
      else if (bram_we_w)           write_left <= write_left-1;
            
      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;
122 123 124
      
      if (rst) dev_ready_r <= 1'b0;
      else     dev_ready_r <= dev_ready;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    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
*/

144 145 146 147
// external memory interface (write only)
   assign pre_awaddr=awaddr_out[ADDRESS_BITS-1:0];
   assign start_burst=start_write_burst_w;
   
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
   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];
    
fifo_reg_W_D   #( .DATA_WIDTH(20+ADDRESS_BITS),.DATA_DEPTH(4))    
    waddr_i (
        .rst(rst),
        .clk(aclk),
        .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]}),
        .nempty(aw_nempty),
        .full(),
        .half_full(aw_half_full)
    );
fifo_reg_W_D   #( .DATA_WIDTH(49),.DATA_DEPTH(4))    
    wdata_i (
        .rst(rst),
        .clk(aclk),
        .we(wvalid && wready),
        .re(bram_we_w), //start_write_burst_w), // wrong
        .data_in({wid[11:0],wlast,wstb[3:0],wdata[31:0]}),
        .data_out({wid_out[11:0],wlast_out,wstb_out[3:0],wdata_out[31:0]}),
        .nempty(w_nempty),
        .full(),
        .half_full(w_half_full)
    );
fifo_reg_W_D  #( .DATA_WIDTH(14),.DATA_DEPTH(4))    
    wresp_i (
        .rst(rst),
        .clk(aclk),
        .we(bram_we_w),
        .re(bready && bvalid),
        .data_in({wid_out[11:0],bresp_in[1:0]}),
        .data_out({bid[11:0],bresp[1:0]}),
        .nempty(bvalid),
        .full(),
        .half_full()
    );

endmodule