Commit f57364b8 authored by Andrey Filippov's avatar Andrey Filippov

axi interface files added

parent bd8a0bce
/*******************************************************************************
* Module: axibram
* Date:2014-03-18
* Author: Andrey Filippov
* Description:
*
* Copyright (c) 2014 Elphel, Inc.
* axibram.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.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/> .
*******************************************************************************/
module axibram(
input aclk, // clock - should be buffered
input aresetn, // reset, active low
// AXI Read Address
input [31:0] araddr, // ARADDR[31:0], input
input arvalid, // ARVALID, input
output arready, // ARREADY, output
input [11:0] arid, // ARID[11:0], input
// input [ 1:0] arlock, // ARLOCK[1:0], input
// input [ 3:0] archache,// ARCACHE[3:0], input
// input [ 2:0] arprot, // ARPROT[2:0], input
input [ 3:0] arlen, // ARLEN[3:0], input
input [ 1:0] arsize, // ARSIZE[1:0], input
input [ 1:0] arburst, // ARBURST[1:0], input
// input [ 3:0] adqos, // ARQOS[3:0], input
// AXI Read Data
output [31:0] rdata, // RDATA[31:0], output
output reg rvalid, // RVALID, output
input rready, // RREADY, input
output reg [11:0] rid, // RID[11:0], output
output reg rlast, // RLAST, output
output [ 1:0] rresp, // RRESP[1:0], output
// 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
);
// **** Read channel ****
wire ar_nempty;
wire ar_half_full;
assign arready=~ar_half_full;
wire [ 1:0] arburst_out;
// SuppressWarnings VEditor all
wire [ 1:0] arsize_out; // not used
wire [ 3:0] arlen_out;
wire [ 9:0] araddr_out;
wire [11:0] arid_out;
wire rst=~aresetn;
reg read_in_progress=0;
reg read_in_progress_d=0; // delayed by one active cycle (not skipped)
reg read_in_progress_or=0; // read_in_progress || read_in_progress_d
reg [ 9:0] read_address; // transfer address (not including lower bits
reg [ 3:0] read_left; // number of read transfers
// will ignore arsize - assuming always 32 bits (a*size[2:0]==2)
reg [ 1:0] rburst; // registered burst type
reg [ 3:0] rlen; // registered burst type
wire [ 9:0] next_rd_address_w; // next transfer address;
assign next_rd_address_w=
rburst[1]?
(rburst[0]? (10'h0):((read_address[9:0]+1) & {6'h3f, ~rlen[3:0]})):
(rburst[0]? (read_address[9:0]+1):(read_address[9:0]));
wire start_read_burst_w;
// wire bram_re_w;
wire bram_reg_re_w;
wire read_in_progress_w;
wire read_in_progress_d_w;
wire last_in_burst_w;
wire last_in_burst_d_w;
reg pre_last_in_burst_r;
assign rresp=2'b0;
// reduce combinatorial delay from rready (use it in final mux)
// assign bram_reg_re_w= read_in_progress && (!rvalid || rready);
// assign start_read_burst_w=ar_nempty && (!read_in_progress || (bram_reg_re_w && (read_left==4'b0))); // reduce delay from arready
assign last_in_burst_w= bram_reg_re_w && (read_left==4'b0);
assign last_in_burst_d_w=bram_reg_re_w && pre_last_in_burst_r;
// make sure ar_nempty is updated
// assign start_read_burst_w=ar_nempty && (!read_in_progress || last_in_burst_w); // reduce delay from arready
assign read_in_progress_w= start_read_burst_w || (read_in_progress && !last_in_burst_w); // reduce delay from arready
assign read_in_progress_d_w=(read_in_progress && bram_reg_re_w) ||
(read_in_progress && !last_in_burst_d_w); // reduce delay from arready
// assign read_in_progress_d_w=read_in_progress_d;
wire pre_rvalid_w;
assign pre_rvalid_w=bram_reg_re_w || (rvalid && !rready);
reg bram_reg_re_0;
wire pre_left_zero_w;
reg last_in_burst_1;
reg last_in_burst_0;
reg start_read_burst_0;
reg start_read_burst_1;
reg [11:0] pre_rid0;
reg [11:0] pre_rid;
always @ (posedge aclk or posedge rst) begin
if (rst) pre_last_in_burst_r <= 0;
// else if (start_read_burst_w) pre_last_in_burst_r <= (read_left==4'b0);
else if (bram_reg_re_w) pre_last_in_burst_r <= (read_left==4'b0);
if (rst) rburst[1:0] <= 0;
else if (start_read_burst_w) rburst[1:0] <= arburst_out[1:0];
if (rst) rlen[3:0] <= 0;
else if (start_read_burst_w) rlen[3:0] <= arlen_out[3:0];
if (rst) read_in_progress <= 0;
else read_in_progress <= read_in_progress_w;
if (rst) read_in_progress_d <= 0;
// else read_in_progress_d <= read_in_progress_d_w;
else if (bram_reg_re_w) read_in_progress_d <= read_in_progress_d_w;
if (rst) read_in_progress_or <= 0;
// else read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// else if (bram_reg_re_w) read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// FIXME:
else if (bram_reg_re_w || !read_in_progress_or) read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// reg read_in_progress_d=0; // delayed by one active cycle (not skipped)
// reg read_in_progress_or=0; // read_in_progress || read_in_progress_d
if (rst) read_left <= 0;
else if (start_read_burst_w) read_left <= arlen_out[3:0]; // precedence over inc
else if (bram_reg_re_w) read_left <= read_left-1;
if (rst) read_address <= 10'b0;
else if (start_read_burst_w) read_address <= araddr_out[9:0]; // precedence over inc
else if (bram_reg_re_w) read_address <= next_rd_address_w;
if (rst) rvalid <= 1'b0;
else if (bram_reg_re_w && read_in_progress_d) rvalid <= 1'b1;
else if (rready) rvalid <= 1'b0;
if (rst) rlast <= 1'b0;
else if (last_in_burst_d_w) rlast <= 1'b1;
else if (rready) rlast <= 1'b0;
end
always @ (posedge aclk) begin
// bram_reg_re_0 <= read_in_progress_w && !pre_rvalid_w;
bram_reg_re_0 <= (ar_nempty && !read_in_progress) || (read_in_progress && !read_in_progress);
last_in_burst_1 <= read_in_progress_w && pre_left_zero_w;
last_in_burst_0 <= read_in_progress_w && !pre_rvalid_w && pre_left_zero_w;
start_read_burst_1 <= !read_in_progress_w || pre_left_zero_w;
start_read_burst_0 <= !read_in_progress_w || (!pre_rvalid_w && pre_left_zero_w);
if (start_read_burst_w) pre_rid0[11:0] <= arid_out[11:0];
if (bram_reg_re_w) pre_rid[11:0] <= pre_rid0[11:0];
if (bram_reg_re_w) rid[11:0] <= pre_rid[11:0];
end
// reducing rready combinatorial delay
assign pre_left_zero_w=start_read_burst_w?(arlen_out[3:0]==4'b0):(bram_reg_re_w && (read_left==4'b0001));
// assign bram_reg_re_w= read_in_progress && (!rvalid || rready);
assign bram_reg_re_w= read_in_progress_or && (!rvalid || rready); // slower/simplier
// assign bram_reg_re_w= rready? read_in_progress : bram_reg_re_0; // faster - more verification
assign last_in_burst_w=bram_reg_re_w && (read_left==4'b0); // slower/simplier
// assign last_in_burst_w=rready? (read_in_progress && (read_left==4'b0)): (bram_reg_re_0 && (read_left==4'b0));
// assign last_in_burst_w=rready? last_in_burst_1: last_in_burst_0; // faster (unfinished) - more verification
assign start_read_burst_w=ar_nempty && (!read_in_progress || (bram_reg_re_w && (read_left==4'b0))); // reduce delay from rready
// assign start_read_burst_w=ar_nempty && (!read_in_progress || ((rready? read_in_progress : bram_reg_re_0) && (read_left==4'b0)));
// assign start_read_burst_w=
// rready?
// (ar_nempty && (!read_in_progress || ((read_in_progress) && (read_left==4'b0)))):
// (ar_nempty && (!read_in_progress || ((bram_reg_re_0 ) && (read_left==4'b0))));
/*
assign start_read_burst_w=
ar_nempty*(rready?
(!read_in_progress || (read_left==4'b0)):
((!read_in_progress || ((bram_reg_re_0 ) && (read_left==4'b0)))));
*/
// assign start_read_burst_w= ar_nempty && (rready?start_read_burst_1:start_read_burst_0);
// **** 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 [ 9: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 [ 9: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 [ 9: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;
assign next_wr_address_w=
wburst[1]?
(wburst[0]? (10'h0):((write_address[9:0]+1) & {6'h3f, ~wlen[3:0]})):
(wburst[0]? (write_address[9:0]+1):(write_address[9:0]));
assign bram_we_w= w_nempty && write_in_progress;
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 <= 10'b0;
else if (start_write_burst_w) write_address <= awaddr_out[9:0]; // precedence over inc
else if (bram_we_w) write_address <= next_wr_address_w;
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
*/
ram_1kx32_1kx32
#(
.REGISTERS(1) // 1 - registered output
)
ram_1kx32_1kx32_i
(
.rclk(aclk), // clock for read port
.raddr(read_in_progress?read_address[9:0]:10'h3ff), // read address
// .ren(read_in_progress_or) , // read port enable
.ren(bram_reg_re_w) , // read port enable
.regen(bram_reg_re_w), // output register enable
// .regen(bram_reg_re_r), // output register enable
.data_out(rdata[31:0]), // data out
.wclk(aclk), // clock for read port
.waddr(write_address[9:0]), // write address
.we(bram_we_w), // write port enable
.web(wstb_out[3:0]), // write byte enable
.data_in(wdata_out[31:0]) // data out
);
fifo_reg_W_D #( .DATA_WIDTH(30),.DATA_DEPTH(4))
raddr_i (
.rst(rst),
.clk(aclk),
.we(arvalid && arready),
.re(start_read_burst_w),
.data_in({arid[11:0], arburst[1:0],arsize[1:0],arlen[3:0],araddr[11:2]}),
.data_out({arid_out[11:0], arburst_out[1:0],arsize_out[1:0],arlen_out[3:0],araddr_out[9:0]}),
.nempty(ar_nempty),
.full(),
.half_full(ar_half_full)
);
fifo_reg_W_D #( .DATA_WIDTH(30),.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[11:2]}),
.data_out({awid_out[11:0], awburst_out[1:0],awsize_out[1:0],awlen_out[3:0],awaddr_out[9: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
/*******************************************************************************
* Module: axibram_read
* Date:2014-03-18
* Author: Andrey Filippov
* Description: Read block RAM memory over AXI PS Master GP0
*
* Copyright (c) 2014 Elphel, Inc.
* axibram_read.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_read.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/> .
*******************************************************************************/
module axibram_read#(
parameter ADDRESS_BITS = 10 // number of memory address bits
)(
input aclk, // clock - should be buffered
input aresetn, // reset, active low
// AXI Read Address
input [31:0] araddr, // ARADDR[31:0], input
input arvalid, // ARVALID, input
output arready, // ARREADY, output
input [11:0] arid, // ARID[11:0], input
// input [ 1:0] arlock, // ARLOCK[1:0], input
// input [ 3:0] archache,// ARCACHE[3:0], input
// input [ 2:0] arprot, // ARPROT[2:0], input
input [ 3:0] arlen, // ARLEN[3:0], input
input [ 1:0] arsize, // ARSIZE[1:0], input
input [ 1:0] arburst, // ARBURST[1:0], input
// input [ 3:0] adqos, // ARQOS[3:0], input
// AXI Read Data
output [31:0] rdata, // RDATA[31:0], output
output reg rvalid, // RVALID, output
input rready, // RREADY, input
output reg [11:0] rid, // RID[11:0], output
output reg rlast, // RLAST, output
output [ 1:0] rresp,
// BRAM interface
output bram_rclk, // .rclk(aclk), // clock for read port
output [ADDRESS_BITS-1:0] bram_raddr, // .raddr(read_in_progress?read_address[9:0]:10'h3ff), // read address
output bram_ren, // .ren(bram_reg_re_w) , // read port enable
output bram_regen, // .regen(bram_reg_re_w), // output register enable
input [31:0] bram_rdata // .data_out(rdata[31:0]), // data out
// RRESP[1:0], output
);
// **** AXI Read channel ****
wire ar_nempty;
wire ar_half_full;
assign arready=~ar_half_full;
wire [ 1:0] arburst_out;
// SuppressWarnings VEditor all
wire [ 1:0] arsize_out; // not used
wire [ 3:0] arlen_out;
wire [ADDRESS_BITS-1:0] araddr_out;
wire [11:0] arid_out;
wire rst=~aresetn;
reg read_in_progress=0;
reg read_in_progress_d=0; // delayed by one active cycle (not skipped)
reg read_in_progress_or=0; // read_in_progress || read_in_progress_d
reg [ADDRESS_BITS-1:0] read_address; // transfer address (not including lower bits
reg [ 3:0] read_left; // number of read transfers
// will ignore arsize - assuming always 32 bits (a*size[2:0]==2)
reg [ 1:0] rburst; // registered burst type
reg [ 3:0] rlen; // registered burst type
wire [ADDRESS_BITS-1:0] next_rd_address_w; // next transfer address;
assign next_rd_address_w=
rburst[1]?
(rburst[0]? {ADDRESS_BITS{1'b0}}:((read_address[ADDRESS_BITS-1:0]+1) & {{(ADDRESS_BITS-4){1'b1}}, ~rlen[3:0]})):
(rburst[0]? (read_address[ADDRESS_BITS-1:0]+1):(read_address[ADDRESS_BITS-1:0]));
wire start_read_burst_w;
// wire bram_re_w;
wire bram_reg_re_w;
wire read_in_progress_w;
wire read_in_progress_d_w;
wire last_in_burst_w;
wire last_in_burst_d_w;
reg pre_last_in_burst_r;
assign rresp=2'b0;
// reduce combinatorial delay from rready (use it in final mux)
// assign bram_reg_re_w= read_in_progress && (!rvalid || rready);
// assign start_read_burst_w=ar_nempty && (!read_in_progress || (bram_reg_re_w && (read_left==4'b0))); // reduce delay from arready
assign last_in_burst_w= bram_reg_re_w && (read_left==4'b0);
assign last_in_burst_d_w=bram_reg_re_w && pre_last_in_burst_r;
// make sure ar_nempty is updated
// assign start_read_burst_w=ar_nempty && (!read_in_progress || last_in_burst_w); // reduce delay from arready
assign read_in_progress_w= start_read_burst_w || (read_in_progress && !last_in_burst_w); // reduce delay from arready
assign read_in_progress_d_w=(read_in_progress && bram_reg_re_w) ||
(read_in_progress && !last_in_burst_d_w); // reduce delay from arready
// assign read_in_progress_d_w=read_in_progress_d;
wire pre_rvalid_w;
assign pre_rvalid_w=bram_reg_re_w || (rvalid && !rready);
reg bram_reg_re_0;
wire pre_left_zero_w;
reg last_in_burst_1;
reg last_in_burst_0;
reg start_read_burst_0;
reg start_read_burst_1;
reg [11:0] pre_rid0;
reg [11:0] pre_rid;
// Block RAM interface
assign bram_rclk = aclk; // clock for read port
assign bram_raddr = read_in_progress?read_address[ADDRESS_BITS-1:0]:{ADDRESS_BITS{1'b1}}; // read address
assign bram_ren = bram_reg_re_w; // read port enable
assign bram_regen = bram_reg_re_w; // output register enable
assign rdata[31:0] = bram_rdata; // data out
always @ (posedge aclk or posedge rst) begin
if (rst) pre_last_in_burst_r <= 0;
// else if (start_read_burst_w) pre_last_in_burst_r <= (read_left==4'b0);
else if (bram_reg_re_w) pre_last_in_burst_r <= (read_left==4'b0);
if (rst) rburst[1:0] <= 0;
else if (start_read_burst_w) rburst[1:0] <= arburst_out[1:0];
if (rst) rlen[3:0] <= 0;
else if (start_read_burst_w) rlen[3:0] <= arlen_out[3:0];
if (rst) read_in_progress <= 0;
else read_in_progress <= read_in_progress_w;
if (rst) read_in_progress_d <= 0;
// else read_in_progress_d <= read_in_progress_d_w;
else if (bram_reg_re_w) read_in_progress_d <= read_in_progress_d_w;
if (rst) read_in_progress_or <= 0;
// else read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// else if (bram_reg_re_w) read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// FIXME:
else if (bram_reg_re_w || !read_in_progress_or) read_in_progress_or <= read_in_progress_d_w || read_in_progress_w;
// reg read_in_progress_d=0; // delayed by one active cycle (not skipped)
// reg read_in_progress_or=0; // read_in_progress || read_in_progress_d
if (rst) read_left <= 0;
else if (start_read_burst_w) read_left <= arlen_out[3:0]; // precedence over inc
else if (bram_reg_re_w) read_left <= read_left-1;
if (rst) read_address <= {ADDRESS_BITS{1'b0}};
else if (start_read_burst_w) read_address <= araddr_out[ADDRESS_BITS-1:0]; // precedence over inc
else if (bram_reg_re_w) read_address <= next_rd_address_w;
if (rst) rvalid <= 1'b0;
else if (bram_reg_re_w && read_in_progress_d) rvalid <= 1'b1;
else if (rready) rvalid <= 1'b0;
if (rst) rlast <= 1'b0;
else if (last_in_burst_d_w) rlast <= 1'b1;
else if (rready) rlast <= 1'b0;
end
always @ (posedge aclk) begin
// bram_reg_re_0 <= read_in_progress_w && !pre_rvalid_w;
bram_reg_re_0 <= (ar_nempty && !read_in_progress) || (read_in_progress && !read_in_progress);
last_in_burst_1 <= read_in_progress_w && pre_left_zero_w;
last_in_burst_0 <= read_in_progress_w && !pre_rvalid_w && pre_left_zero_w;
start_read_burst_1 <= !read_in_progress_w || pre_left_zero_w;
start_read_burst_0 <= !read_in_progress_w || (!pre_rvalid_w && pre_left_zero_w);
if (start_read_burst_w) pre_rid0[11:0] <= arid_out[11:0];
if (bram_reg_re_w) pre_rid[11:0] <= pre_rid0[11:0];
if (bram_reg_re_w) rid[11:0] <= pre_rid[11:0];
end
// reducing rready combinatorial delay
assign pre_left_zero_w=start_read_burst_w?(arlen_out[3:0]==4'b0):(bram_reg_re_w && (read_left==4'b0001));
// assign bram_reg_re_w= read_in_progress && (!rvalid || rready);
assign bram_reg_re_w= read_in_progress_or && (!rvalid || rready); // slower/simplier
// assign bram_reg_re_w= rready? read_in_progress : bram_reg_re_0; // faster - more verification
assign last_in_burst_w=bram_reg_re_w && (read_left==4'b0); // slower/simplier
// assign last_in_burst_w=rready? (read_in_progress && (read_left==4'b0)): (bram_reg_re_0 && (read_left==4'b0));
// assign last_in_burst_w=rready? last_in_burst_1: last_in_burst_0; // faster (unfinished) - more verification
assign start_read_burst_w=ar_nempty && (!read_in_progress || (bram_reg_re_w && (read_left==4'b0))); // reduce delay from rready
// assign start_read_burst_w=ar_nempty && (!read_in_progress || ((rready? read_in_progress : bram_reg_re_0) && (read_left==4'b0)));
// assign start_read_burst_w=
// rready?
// (ar_nempty && (!read_in_progress || ((read_in_progress) && (read_left==4'b0)))):
// (ar_nempty && (!read_in_progress || ((bram_reg_re_0 ) && (read_left==4'b0))));
/*
assign start_read_burst_w=
ar_nempty*(rready?
(!read_in_progress || (read_left==4'b0)):
((!read_in_progress || ((bram_reg_re_0 ) && (read_left==4'b0)))));
*/
// assign start_read_burst_w= ar_nempty && (rready?start_read_burst_1:start_read_burst_0);
fifo_reg_W_D #( .DATA_WIDTH(ADDRESS_BITS+20),.DATA_DEPTH(4))
raddr_i (
.rst(rst),
.clk(aclk),
.we(arvalid && arready),
.re(start_read_burst_w),
.data_in({arid[11:0], arburst[1:0],arsize[1:0],arlen[3:0],araddr[ADDRESS_BITS+1:2]}),
.data_out({arid_out[11:0], arburst_out[1:0],arsize_out[1:0],arlen_out[3:0],araddr_out[ADDRESS_BITS-1:0]}),
.nempty(ar_nempty),
.full(),
.half_full(ar_half_full)
);
endmodule
/*******************************************************************************
* 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/> .
*******************************************************************************/
module axibram_write#(
parameter ADDRESS_BITS = 10 // number of memory address bits
)(
input aclk, // clock - should be buffered
input aresetn, // reset, active low
// 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
// BRAM interface
output bram_wclk,
output [ADDRESS_BITS-1:0] bram_waddr,
output bram_wen,
output [3:0] bram_wstb,
output [31:0] bram_wdata
);
wire rst=~aresetn;
// **** 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;
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]));
assign bram_we_w= w_nempty && write_in_progress;
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;
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
*/
// BRAM interface
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
/*
** -----------------------------------------------------------------------------**
** macros353.v
**
** I/O pads related circuitry
**
** Copyright (C) 2002 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** This program 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.
**
** This program 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/>.
** -----------------------------------------------------------------------------**
**
*/
// just make more convenient A[3:0] instead of 4 one-bit inputs
// TODO: Replace direct instances of SRL16 to imporve portability
/*
module MSRL16 (Q, A, CLK, D);
output Q;
input [3:0] A;
input CLK, D;
SRL16 i_q(.Q(Q), .A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CLK(CLK), .D(D));
endmodule
module MSRL16_1 (Q, A, CLK, D);
output Q;
input [3:0] A;
input CLK, D;
SRL16_1 i_q(.Q(Q), .A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CLK(CLK), .D(D));
endmodule
*/
/*
module myRAM_WxD_D(D,WE,clk,AW,AR,QW,QR);
parameter DATA_WIDTH=16;
parameter DATA_DEPTH=4;
parameter DATA_2DEPTH=(1<<DATA_DEPTH)-1;
input [DATA_WIDTH-1:0] D;
input WE,clk;
input [DATA_DEPTH-1:0] AW;
input [DATA_DEPTH-1:0] AR;
output [DATA_WIDTH-1:0] QW;
output [DATA_WIDTH-1:0] QR;
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
always @ (posedge clk) if (WE) ram[AW] <= D;
assign QW= ram[AW];
assign QR= ram[AR];
endmodule
*/
module ram_WxD
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4,
parameter integer DATA_2DEPTH=(1<<DATA_DEPTH)-1
)
(
input [DATA_WIDTH-1:0] D,
input WE,
input clk,
input [DATA_DEPTH-1:0] AW,
input [DATA_DEPTH-1:0] AR,
output [DATA_WIDTH-1:0] QW,
output [DATA_WIDTH-1:0] QR);
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
always @(posedge clk) if (WE) ram[AW] <= D;
assign QW= ram[AW];
assign QR= ram[AR];
endmodule
/*
FIFO with minimal latency 1, uses 1 register slice on the data input, output - 1 mux after register
*/
module fifo_reg_W_D
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4,
parameter integer DATA_2DEPTH=(1<<DATA_DEPTH)-1
)
(
input rst, // reset, active high
input clk, // clock - positive edge
input we, // write enable
input re, // read enable
input [DATA_WIDTH-1:0] data_in, // input data
output [DATA_WIDTH-1:0] data_out, // output data
output reg nempty, // FIFO has some data
output reg full, // FIFO full
output reg half_full // FIFO half full
);
reg [DATA_DEPTH :0] fill=0;
reg just_one=0;
reg [DATA_WIDTH-1:0] inreg;
reg [DATA_WIDTH-1:0] outreg;
reg [DATA_DEPTH-1:0] ra;
reg [DATA_DEPTH-1:0] wa;
wire [DATA_DEPTH :0] next_fill;
reg wem;
wire rem;
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
// wire [DATA_DEPTH :0] pre_next_fill= ((we && ~re)?1:((~we && re)?-1:0));
assign next_fill = fill[4:0]+((we && ~re)?1:((~we && re)?5'b11111:5'b00000));
// assign next_fill = fill+((we && ~re)?1:((~we && re)?-1:0));
// assign next_fill[DATA_DEPTH :0] = fill[DATA_DEPTH :0]+pre_next_fill[DATA_DEPTH :0];
// assign next_fill[DATA_DEPTH :0] = fill[DATA_DEPTH :0]+1;
// assign next_fill[DATA_DEPTH :0] = fill[DATA_DEPTH :0]+((we && ~re)?5'b1:0);
// assign next_fill[4 :0] = fill[4 :0]+((we && ~re)?5'b1:0);
assign data_out = just_one?inreg:outreg;
assign rem = just_one? wem : re;
always @ (posedge clk or posedge rst) begin
if (rst) fill <= 0;
// else fill <= next_fill;
// else fill <= fill+1;
// else fill <= fill[4 :0]+((we && ~re)?1:((~we && re)?-1:0));
// else fill <= fill[4 :0]+((we && ~re)?5'b00001:((~we && re)?5'b11111:5'b00000));
else if (we && ~re) fill <= fill+1;
else if (~we && re) fill <= fill-1;
if (rst) wa <= 0;
else if (wem) wa <= wa+1;
if (rst) ra <= 1; // 0;
// else if (re) ra <= ra+1; //wrong?
// else if (rem) ra <= ra+1; //may be still wrong
else if (re) ra <= ra+1; //now ra is 1 ahead
else if (!nempty) ra <= wa+1; // Just recover from bit errors TODO: fix
if (rst) nempty <= 0;
else nempty <= (next_fill != 0);
end
always @ (posedge clk) begin
if (wem) ram[wa] <= inreg;
just_one <= (next_fill == 1);
// nempty <= (next_fill != 0);
half_full <=(fill & (1<<(DATA_DEPTH-1)))!=0;
full <= (fill & (1<< DATA_DEPTH ))!=0;
if (we) inreg <= data_in;
if (rem) outreg <= just_one?inreg:ram[ra];
wem <= we;
end
endmodule
// tri0 GSR = glbl.GSR;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment