Commit 78539c1a authored by Andrey Filippov's avatar Andrey Filippov

Removed x393 as submodule, copied needed files only (to resolve future recursion)

parent 29d789db
[submodule "x393"]
path = x393
url = https://github.com/Elphel/x393.git
#!/bin/bash
REPO_ROOT=".."
CWD="$(pwd)"
cd $REPO_ROOT
cp -v --parents \
x393/simulation_modules/simul_axi_master_wraddr.v \
x393/simulation_modules/simul_axi_master_rdaddr.v \
x393/simulation_modules/simul_axi_master_wdata.v \
x393/simulation_modules/simul_axi_slow_ready.v \
x393/simulation_modules/simul_axi_hp_rd.v \
x393/simulation_modules/simul_axi_hp_wr.v \
x393/simulation_modules/simul_axi_read.v \
x393/util_modules/fifo_same_clock_fill.v \
x393/util_modules/dly_16.v \
x393/util_modules/axi_hp_clk.v \
x393/simulation_modules/simul_fifo.v \
x393/simulation_modules/simul_axi_fifo_out.v \
x393/util_modules/dly01_16.v \
x393/wrap/pll_base.v \
x393/wrap/ram18p_var_w_var_r.v \
x393/util_modules/fifo_sameclock_control.v \
x393/util_modules/pulse_cross_clock.v \
x393/axi/axibram_read.v \
x393/wrap/ram_var_w_var_r.v \
x393/wrap/ramt_var_wb_var_r.v \
x393/util_modules/fifo_cross_clocks.v \
x393/axi/axibram_write.v \
x393/util_modules/fifo_same_clock.v \
x393/util_modules/resync_data.v \
x393/wrap/ramt_var_w_var_r.v \
x393/glbl.v \
$CWD
cd $CWD
Subproject commit 1e167c275aa336683875434b4ae406d803b3db3d
/*******************************************************************************
* 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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
// Check that this fix did not break anything:
`include "system_defines.vh"
`define USE_SHORT_REN_REGEN
module axibram_read #(
parameter ADDRESS_BITS = 10 // number of memory address bits
)(
input aclk, // clock - should be buffered
// input rst, // reset, active high
input arst, // @posedge aclk sync reset, active high
// 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 [ 3:0] arlen, // ARLEN[3:0], input
input [ 1:0] arsize, // ARSIZE[1:0], input
input [ 1:0] arburst, // ARBURST[1: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,
// External memory synchronization
output [ADDRESS_BITS-1:0] pre_araddr, // same as awaddr_out, early address to decode and return dev_ready
output start_burst, // start of read burst, valid pre_araddr, save externally to control ext. dev_ready multiplexer
input dev_ready, // extrernal combinatorial ready signal, multiplexed from different sources according to pre_araddr@start_burst
// External memory 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= //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 13-bit target.
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);
wire pre_left_zero_w;
// TODO: Speed up by moving registers
// SuppressWarnings VEditor all - not yet used
reg bram_reg_re_0;
// SuppressWarnings VEditor all - not yet used
reg last_in_burst_1;
// SuppressWarnings VEditor all - not yet used
reg last_in_burst_0;
// SuppressWarnings VEditor all - not yet used
reg start_read_burst_0;
// SuppressWarnings VEditor all - not yet used
reg start_read_burst_1;
reg [11:0] pre_rid0;
reg [11:0] pre_rid;
// External memory interface - synchronization with ready
assign pre_araddr= araddr_out[ADDRESS_BITS-1:0];
assign start_burst= start_read_burst_w;
//input dev_ready, // extrernal combinatorial ready signal, multiplexed from different sources according to pre_araddr@start_burst
// External memory 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
`ifdef USE_SHORT_REN_REGEN
reg bram_regen_r;
// assign bram_ren = bram_reg_re_w && !pre_last_in_burst_r ; // read port enable
/// assign bram_ren = read_in_progress;
assign bram_ren = read_in_progress && dev_ready;
assign bram_regen = bram_regen_r; // output register enable
`else
assign bram_ren = bram_reg_re_w; // read port enable
assign bram_regen = bram_reg_re_w; // output register enable
`endif
assign rdata[31:0] = bram_rdata; // data out
always @ (posedge aclk) begin
`ifdef USE_SHORT_REN_REGEN
if (arst) bram_regen_r <= 0;
else bram_regen_r <= bram_ren;
`endif
if (arst) 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 (arst) rburst[1:0] <= 0;
else if (start_read_burst_w) rburst[1:0] <= arburst_out[1:0];
if (arst) rlen[3:0] <= 0;
else if (start_read_burst_w) rlen[3:0] <= arlen_out[3:0];
if (arst) read_in_progress <= 0;
else read_in_progress <= read_in_progress_w;
if (arst) 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 (arst) 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 (arst) 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; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 4-bit target.
if (arst) 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 (arst) rvalid <= 1'b0;
else if (bram_reg_re_w && read_in_progress_d) rvalid <= 1'b1;
else if (rready) rvalid <= 1'b0;
if (arst) rlast <= 1'b0;
else if (last_in_burst_d_w) rlast <= 1'b1;
else if (rready) rlast <= 1'b0;
end
always @ (posedge aclk) begin //SuppressThisWarning ISExst Assignment to bram_reg_re_0 ignored, since the identifier is never used
// 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= dev_ready && 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_same_clock #( .DATA_WIDTH(ADDRESS_BITS+20),.DATA_DEPTH(4))
raddr_i (
.rst(1'b0),
.clk(aclk),
.sync_rst(arst),
.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]}), //SuppressThisWarning ISExst Assignment to arsize ignored, since the identifier is never used
.nempty(ar_nempty),
.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
//`define DEBUG_FIFO 1
`include "system_defines.vh"
`ifdef DEBUG_FIFO
`undef DEBUG_FIFO
`endif
module axibram_write #(
parameter ADDRESS_BITS = 10 // number of memory address bits
)(
input aclk, // clock - should be buffered
input arst, // @aclk sync reset, active high
// 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
// AXI PS Master GP0: Write response
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 (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
output bram_wclk,
output [ADDRESS_BITS-1:0] bram_waddr,
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
output [3:0] bram_wstb,
output [31:0] bram_wdata
`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
);
// 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 write 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; //,bram_we_nonmasked; // write BRAM memory non-masked - should be combined with
wire start_write_burst_w;
wire write_in_progress_w;
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?
reg dev_ready_r; // device, selected at start burst
assign next_wr_address_w= //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 13-bit target.
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_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)));
// 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)));
assign pre_bram_wen = write_in_progress_w;
always @ (posedge aclk) begin
if (arst) wburst[1:0] <= 0;
else if (start_write_burst_w) wburst[1:0] <= awburst_out[1:0];
if (arst) wlen[3:0] <= 0;
else if (start_write_burst_w) wlen[3:0] <= awlen_out[3:0];
if (arst) write_in_progress <= 0;
else write_in_progress <= write_in_progress_w;
if (arst) 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; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 4-bit target.
if (arst) 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;
if (arst) dev_ready_r <= 1'b0;
else dev_ready_r <= dev_ready;
end
// **** Write response channel ****
wire [ 1:0] bresp_in;
assign bresp_in=2'b0;
// external memory interface (write only)
assign pre_awaddr=awaddr_out[ADDRESS_BITS-1:0];
assign start_burst=start_write_burst_w;
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];
`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))
waddr_i (
.rst (1'b0), //rst),
.clk (aclk),
.sync_rst (arst),
.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
);
fifo_same_clock #( .DATA_WIDTH(49),.DATA_DEPTH(4))
wdata_i (
.rst(1'b0), //rst),
.clk(aclk),
.sync_rst (arst),
.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]}), //SuppressThisWarning ISExst Assignment to wlast ignored, since the identifier is never used
.nempty(w_nempty),
.half_full(w_half_full)
`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
);
//debugging - slow down bresp
reg was_bresp_re=0;
wire bresp_re;
assign bresp_re=bready && bvalid && !was_bresp_re;
always @ (posedge aclk) begin
if (arst) was_bresp_re<=0;
else was_bresp_re <= bresp_re;
end
fifo_same_clock #( .DATA_WIDTH(14),.DATA_DEPTH(4))
wresp_i (
.rst(1'b0), //rst),
.clk(aclk),
.sync_rst (arst),
.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
// .re(bready && bvalid),
.re(bresp_re), // not allowing RE next cycle after bvalid
.data_in({wid_out[11:0],bresp_in[1:0]}),
.data_out({bid[11:0],bresp[1:0]}),
.nempty(bvalid),
.half_full()
`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
);
endmodule
`timescale 1 ps / 1 ps
module glbl ();
parameter ROC_WIDTH = 10000;// 100000;
parameter TOC_WIDTH = 0;
//SuppressWarnings VEditor - this value is used in other modules through global reference
wire GSR;
//SuppressWarnings VEditor - this value is used in other modules through global reference
wire GTS;
//SuppressWarnings VEditor - this value is used in other modules through global reference
wire PRLD;
//SuppressWarnings VEditor - this value is used in other modules through global reference
wire PLL_LOCKG;
reg GSR_int;
reg GTS_int;
reg PRLD_int;
assign (weak1, weak0) GSR = GSR_int;
assign (weak1, weak0) GTS = GTS_int;
assign (weak1, weak0) PRLD = PRLD_int;
initial begin
GSR_int = 1'b1;
PRLD_int = 1'b1;
#(ROC_WIDTH)
GSR_int = 1'b0;
PRLD_int = 1'b0;
end
initial begin
GTS_int = 1'b1;
#(TOC_WIDTH)
GTS_int = 1'b0;
end
endmodule
/**************************************
* Module: simul_axi_fifo
* Date:2014-03-23
* Author: Andrey Filippov
*
* Description:
***************************************/
`timescale 1ns/1ps
module simul_axi_fifo
#(
parameter integer WIDTH= 64, // total number of output bits
parameter integer LATENCY=0, // minimal delay between inout and output ( 0 - next cycle)
parameter integer DEPTH=8, // maximal number of commands in FIFO
// parameter OUT_DELAY = 3.5,
parameter integer FIFO_DEPTH=LATENCY+DEPTH+1
// parameter integer DATA_2DEPTH=(1<<DATA_DEPTH)-1
)(
input clk,
input reset,
input [WIDTH-1:0] data_in,
input load,
output input_ready,
output [WIDTH-1:0] data_out,
output valid,
input ready);
reg [WIDTH-1:0] fifo [0:FIFO_DEPTH-1];
integer in_address;
integer out_address;
integer in_count;
integer out_count;
reg [LATENCY:0] latency_delay_r;
wire [LATENCY+1:0] latency_delay={latency_delay_r,load};
wire out_inc=latency_delay[LATENCY];
assign data_out= fifo[out_address];
assign valid= out_count!=0;
assign input_ready= in_count<DEPTH;
// assign out_inc={
always @ (posedge clk or posedge reset) begin
if (reset) latency_delay_r <= 0;
else latency_delay_r <= latency_delay[LATENCY:0];
if (reset) in_address <= 0;
else if (load) in_address <= (in_address==(FIFO_DEPTH-1))?0:in_address+1;
if (reset) out_address <= 0;
else if (valid && ready) out_address <= (out_address==(FIFO_DEPTH-1))?0:out_address+1;
if (reset) in_count <= 0;
else if (!(valid && ready) && load) in_count <= in_count+1;
else if (valid && ready && !load) in_count <= in_count-1;
if (reset) out_count <= 0;
else if (!(valid && ready) && out_inc) out_count <= out_count+1;
else if (valid && ready && !out_inc) out_count <= out_count-1;
end
always @ (posedge clk) begin
if (load) fifo[in_address] <= data_in;
end
endmodule
\ No newline at end of file
/*******************************************************************************
* Module: simul_axi_hp_rd
* Date:2015-04-25
* Author: Andrey Filippov
* Description: Simplified model of AXI_HP read channel (64-bit only)
*
* Copyright (c) 2015 Elphel, Inc.
* simul_axi_hp_rd.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.
*
* simul_axi_hp_rd.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_hp_rd #(
parameter [1:0] HP_PORT=0
)(
input rst,
// AXI signals
input aclk,
output aresetn, // do not use?
// read address
input [31:0] araddr,
input arvalid,
output arready,
input [ 5:0] arid,
input [ 1:0] arlock,
input [ 3:0] arcache,
input [ 2:0] arprot,
input [ 3:0] arlen,
input [ 1:0] arsize,
input [ 1:0] arburst,
input [ 3:0] arqos,
// read data
output [63:0] rdata,
output rvalid,
input rready,
output [ 5:0] rid,
output rlast,
output [ 1:0] rresp,
// PL extra (non-AXI) signals
output [ 7:0] rcount,
output [ 2:0] racount,
input rdissuecap1en,
// Simulation signals - use same aclk
output [31:0] sim_rd_address,
output [ 5:0] sim_rid,
input sim_rd_valid,
output sim_rd_ready,
input [63:0] sim_rd_data,
output [ 2:0] sim_rd_cap,
output [ 3:0] sim_rd_qos,
input [ 1:0] sim_rd_resp,
input [31:0] reg_addr,
input reg_wr,
input reg_rd,
input [31:0] reg_din,
output [31:0] reg_dout
);
localparam AFI_BASECTRL= 32'hf8008000+ (HP_PORT << 12);
localparam AFI_RDCHAN_CTRL= AFI_BASECTRL + 'h00;
localparam AFI_RDCHAN_ISSUINGCAP= AFI_BASECTRL + 'h4;
localparam AFI_RDQOS= AFI_BASECTRL + 'h8;
localparam AFI_RDDATAFIFO_LEVEL= AFI_BASECTRL + 'hc;
localparam AFI_RDDEBUG= AFI_BASECTRL + 'h10; // SuppressThisWarning VEditor - not yet used
localparam VALID_ARLOCK = 2'b0; // TODO
localparam VALID_ARCACHE = 4'b0011; //
localparam VALID_ARPROT = 3'b000;
localparam VALID_ARLOCK_MASK = 2'b11; // TODO
localparam VALID_ARCACHE_MASK = 4'b0011; //
localparam VALID_ARPROT_MASK = 3'b010;
assign aresetn= ~rst; // probably not needed at all - docs say "do not use"
reg rdQosHeadOfCmdQEn = 0;
reg rdFabricOutCmdEn = 0;
reg rdFabricQosEn = 0;
reg rd32BitEn = 0; // verify it i 0
reg [2:0] rdIssueCap1 = 0;
reg [2:0] rdIssueCap0 = 7;
reg [3:0] rdStaticQos = 0;
wire [3:0] rd_qos_in;
wire [3:0] rd_qos_out;
/*
wire aw_nempty;
wire w_nempty;
wire enough_data; // enough data to start a new burst
wire [11:3] next_wr_address; // bits that are incrtemented in 64-bit mode (higher are kept according to AXI 4KB inc. limit)
reg [31:0] write_address;
wire fifo_wd_rd; // read data fifo
wire last_confirmed_write;
*/
wire [5:0] arid_out; // verify it matches wid_out when outputting data
wire [1:0] arburst_out;
wire [1:0] arsize_out; // verify it is 3'h3
wire [3:0] arlen_out;
wire [31:0] araddr_out;
wire ar_nempty;
wire r_nempty;
reg [7:0] fifo_with_requested=0; // fill level of data FIFO if all the requested data will arrive and nothing read
wire fifo_data_rd;
wire [7:0] next_with_requested;
wire start_read_burst_w;
reg was_data_fifo_read; // previos cycle was reading data from FIFO
reg was_data_fifo_write;// previos cycle was writing data to FIFO
reg was_addr_fifo_write; // previos cycle was writing addressto FIFO
wire read_in_progress_w; // should go inactive last confirmed upstream cycle
reg read_in_progress;
reg [3:0] read_left;
reg [1:0] rburst;
reg [3:0] rlen;
wire [11:3] next_rd_address; // bits that are incrtemented in 64-bit mode (higher are kept according to AXI 4KB inc. limit)
reg [31:0] read_address;
wire last_confirmed_read;
wire last_read;
// sim_rd_address =
assign sim_rd_qos = (rdQosHeadOfCmdQEn && (rd_qos_in > rd_qos_out))? rd_qos_in : rd_qos_out;
assign sim_rd_cap = (rdFabricOutCmdEn && rdissuecap1en) ? rdIssueCap1 : rdIssueCap0;
assign rd_qos_in = rdFabricQosEn?(arqos & {4{arvalid}}) : rdStaticQos;
//awqos & {4{awvalid}}
assign aresetn= ~rst; // probably not needed at all - docs say "do not use"
//Supported control register fields
assign reg_dout=(reg_rd && (reg_addr==AFI_RDDATAFIFO_LEVEL))?
{24'b0,rcount}:
( (reg_rd && (reg_addr==AFI_RDCHAN_CTRL))?
{28'b0,rdQosHeadOfCmdQEn,rdFabricOutCmdEn,rdFabricQosEn,rd32BitEn}:
( (reg_rd && (reg_addr==AFI_RDCHAN_ISSUINGCAP))?
{25'b0,rdIssueCap1,1'b0,rdIssueCap0}:
( (reg_rd && (reg_addr==AFI_RDQOS))?
{28'b0,rdStaticQos}:32'bz)));
always @ (posedge aclk or posedge rst) begin
if (rst) begin
rdQosHeadOfCmdQEn <= 0;
rdFabricOutCmdEn <= 0;
rdFabricQosEn <= 1;
rd32BitEn <= 0;
end else if (reg_wr && (reg_addr==AFI_RDCHAN_CTRL)) begin
rdQosHeadOfCmdQEn <= reg_din[3];
rdFabricOutCmdEn <= reg_din[2];
rdFabricQosEn <= reg_din[1];
rd32BitEn <= reg_din[0];
end
if (rst) begin
rdIssueCap1 <= 0;
rdIssueCap0 <= 7;
end else if (reg_wr && (reg_addr==AFI_RDCHAN_ISSUINGCAP)) begin
rdIssueCap1 <= reg_din[6:4];
rdIssueCap0 <= reg_din[2:0];
end
if (rst) begin
rdStaticQos <= 0;
end else if (reg_wr && (reg_addr==AFI_RDQOS)) begin
rdStaticQos <= reg_din[3:0];
end
end
assign fifo_data_rd = rvalid && rready;
assign next_with_requested= fifo_with_requested + {4'b0,arlen_out[3:0]} + {7'h0,~fifo_data_rd};
assign start_read_burst_w= ar_nempty && (next_with_requested <= 8'h80) &&
(! read_in_progress || last_confirmed_read);
assign read_in_progress_w= ar_nempty && (next_with_requested <= 8'h80) ||
(read_in_progress && !last_confirmed_read);
// assign rvalid= (|rcount[7:1]) || (rcount[0] && !was_data_fifo_read);
assign rvalid= r_nempty && ((|rcount[7:1]) || !was_data_fifo_read);
assign arready= !racount[2] && (!racount[1] || !racount[0] || !was_addr_fifo_write);
assign last_read = (read_left==0);
assign last_confirmed_read = (read_left==0) && sim_rd_valid && sim_rd_ready;
// AXI: Bursts should not cross 4KB boundaries (... and to limit size of the address incrementer)
// in 64 bit mode - low 3 bits are preserved, next 9 are incremented
assign next_rd_address[11:3] =
rburst[1]?
(rburst[0]? {9'bx}:((read_address[11:3] + 1) & {5'h1f, ~rlen[3:0]})):
(rburst[0]? (read_address[11:3]+1):(read_address[11:3]));
assign sim_rd_address = read_address;
assign sim_rid = arid_out;
// Current model policy is not to initiate a new burst (read from simulation port) if it may overflow FIFO
// - maybe the real module is done this way to aggregate external accesses.
// So 'assign sim_rd_ready = read_in_progress;' should be sufficient, but if that will chnage - below is
// full vesion that does not depend on the assumption.
assign sim_rd_ready = read_in_progress &&
!rcount[7] && (!(&rcount[6:0]) || !was_data_fifo_write);
always @ (posedge aclk) begin
if (start_read_burst_w) begin
if (arsize_out != 2'h3) begin
$display ("%m: at time %t ERROR: arsize_out=%h, currently only 'h3 (8 bytes) is valid",$time,arsize_out);
$stop;
end
end
if (arvalid && arready) begin
if (((arlock ^ VALID_ARLOCK) & VALID_ARLOCK_MASK) != 0) begin
$display ("%m: at time %t ERROR: arlock = %h, valid %h with mask %h",$time, arlock, VALID_ARLOCK, VALID_ARLOCK_MASK);
$stop;
end
if (((arcache ^ VALID_ARCACHE) & VALID_ARCACHE_MASK) != 0) begin
$display ("%m: at time %t ERROR: arcache = %h, valid %h with mask %h",$time, arcache, VALID_ARCACHE, VALID_ARCACHE_MASK);
$stop;
end
if (((arprot ^ VALID_ARPROT) & VALID_ARPROT_MASK) != 0) begin
$display ("%m: at time %t ERROR: arprot = %h, valid %h with mask %h",$time, arprot, VALID_ARPROT, VALID_ARPROT_MASK);
$stop;
end
end
end
always @ (posedge aclk or posedge rst) begin
if (rst) fifo_with_requested <= 0;
else if (start_read_burst_w) fifo_with_requested <= next_with_requested;
else fifo_with_requested <= fifo_with_requested - {7'h0,fifo_data_rd};
if (rst) was_data_fifo_read <= 0;
else was_data_fifo_read <= rvalid && rready;
if (rst) was_addr_fifo_write <= 0;
else was_addr_fifo_write <= arvalid && arready;
if (rst) was_data_fifo_write <= 0;
else was_data_fifo_write <= sim_rd_valid && sim_rd_ready;
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_left <= 0;
else if (start_read_burst_w) read_left <= arlen_out[3:0]; // precedence over inc
else if (sim_rd_valid && sim_rd_ready) read_left <= read_left-1; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 4-bit target.
if (rst) read_address <= 32'bx;
else if (start_read_burst_w) read_address <= araddr_out; // precedence over inc
else if (sim_rd_valid && sim_rd_ready) read_address <= {read_address[31:12],next_rd_address[11:3],read_address[2:0]};
end
fifo_same_clock_fill #( .DATA_WIDTH(50),.DATA_DEPTH(2)) // read - 4, write - 32?
raddr_i (
.rst (rst),
.clk (aclk),
.sync_rst (1'b0),
.we (arvalid && arready),
.re (start_read_burst_w),
.data_in ({arid[5:0], arburst[1:0], arsize[1:0], arlen[3:0], araddr[31:0], rd_qos_in[3:0]}),
.data_out ({arid_out[5:0], arburst_out[1:0],arsize_out[1:0],arlen_out[3:0],araddr_out[31:0], rd_qos_out[3:0]}),
.nempty (ar_nempty),
.half_full (), //aw_half_full),
.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(racount) // output[3:0]
);
fifo_same_clock_fill #( .DATA_WIDTH(73),.DATA_DEPTH(7)) // read - 4, write - 32?
rdata_i (
.rst (rst),
.clk (aclk),
.sync_rst (1'b0),
.we (sim_rd_valid && sim_rd_ready),
.re (rvalid && rready),
.data_in ({last_read, arid_out[5:0], sim_rd_resp[1:0], sim_rd_data[63:0]}),
.data_out ({rlast, rid[5:0], rresp[1:0], rdata[63:0]}),
.nempty (r_nempty), //r_nempty),
.half_full (), //aw_half_full),
.under (), //waddr_under),
.over (), //waddr_over),
.wcount (), //waddr_wcount),
.rcount (), //waddr_rcount),
.num_in_fifo(rcount)
);
endmodule
/*******************************************************************************
* Module: simul_axi_hp_wr
* Date:2015-04-25
* Author: Andrey Filippov
* Description: Simplified model of AXI_HP write channel (64-bit only)
*
* Copyright (c) 2015 Elphel, Inc.
* simul_axi_hp_wr.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.
*
* simul_axi_hp_wr.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_hp_wr#(
parameter [1:0] HP_PORT=0
) (
input rst,
// AXI signals
input aclk,
output aresetn, // do not use?
// write address
input [31:0] awaddr,
input awvalid,
output awready,
input [ 5:0] awid,
input [ 1:0] awlock, // verify the correct values are here
input [ 3:0] awcache, // verify the correct values are here
input [ 2:0] awprot, // verify the correct values are here
input [ 3:0] awlen,
input [ 1:0] awsize,
input [ 1:0] awburst,
input [ 3:0] awqos, // verify the correct values are here
// write data
input [63:0] wdata,
input wvalid,
output wready,
input [ 5:0] wid,
input wlast,
input [ 7:0] wstrb,
// write response
output bvalid,
input bready,
output [ 5:0] bid,
output [ 1:0] bresp,
// PL extra (non-AXI) signals
output [ 7:0] wcount,
output [ 5:0] wacount, // racount has only 3 bits
input wrissuecap1en, // do not use yet
// Simulation signals - use same aclk
output [31:0] sim_wr_address,
output [ 5:0] sim_wid,
output sim_wr_valid, // ready to provide simulation data
input sim_wr_ready, // simulation may pause this channel by keeping this signal inactive
output [63:0] sim_wr_data,
output [ 7:0] sim_wr_stb,
input [ 3:0] sim_bresp_latency, // latency in writing data outside of the module
output [ 2:0] sim_wr_cap,
output [ 3:0] sim_wr_qos,
input [31:0] reg_addr,
input reg_wr,
input reg_rd,
input [31:0] reg_din,
output [31:0] reg_dout
);
// localparam ADDRESS_BITS=32;
localparam AFI_BASECTRL= 32'hf8008000+ (HP_PORT << 12);
localparam AFI_WRCHAN_CTRL= AFI_BASECTRL + 'h14;
localparam AFI_WRCHAN_ISSUINGCAP= AFI_BASECTRL + 'h18;
localparam AFI_WRQOS= AFI_BASECTRL + 'h1c;
localparam AFI_WRDATAFIFO_LEVEL= AFI_BASECTRL + 'h20;
localparam AFI_WRDEBUG= AFI_BASECTRL + 'h24; // SuppressThisWarning VEditor - not yet used
localparam VALID_AWLOCK = 2'b0; // TODO
localparam VALID_AWCACHE = 4'b0011; //
localparam VALID_AWPROT = 3'b000;
localparam VALID_AWLOCK_MASK = 2'b11; // TODO
localparam VALID_AWCACHE_MASK = 4'b0011; //
localparam VALID_AWPROT_MASK = 3'b010;
/*
http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Accessing-DDR-from-PL-on-Zynq/m-p/324877#M8413
Solved it!
To make it work, I set the (AR/AW)CACHE=0x11 and (AR/AW)PROT=0x00. In the CDMA datasheet, these were the recommended values, which I confirmed with ChipScope, when attached to CDMA's master port.
The default values set by VHLS were 0x00 and 0x10 respectively, which is also the case in the last post.
Alex
*/
reg [3:0] WrDataThreshold = 'hf;
reg [1:0] WrCmdReleaseMode = 0;
reg wrQosHeadOfCmdQEn = 0;
reg wrFabricOutCmdEn = 0;
reg wrFabricQosEn = 0;
reg wr32BitEn = 0; // verify it i 0
reg [2:0] wrIssueCap1 = 0;
reg [2:0] wrIssueCap0 = 7;
reg [3:0] staticQos = 0;
wire [3:0] wr_qos_in;
wire [3:0] wr_qos_out;
wire aw_nempty;
wire w_nempty;
wire enough_data; // enough data to start a new burst
wire [11:3] next_wr_address; // bits that are incrtemented in 64-bit mode (higher are kept according to AXI 4KB inc. limit)
reg [31:0] write_address;
reg [5:0] awid_r; // awid registered with write_address
wire fifo_wd_rd; // read data fifo
wire last_confirmed_write;
wire [5:0] awid_out; // verify it matches wid_out when outputting data
wire [1:0] awburst_out;
wire [1:0] awsize_out; // verify it is 3'h3
wire [3:0] awlen_out;
wire [31:0] awaddr_out;
wire [5:0] wid_out;
wire wlast_out;
wire [7:0] wstrb_out;
wire [63:0] wdata_out;
reg fifo_data_we_d;
reg fifo_addr_we_d;
reg [3:0] write_left;
reg [ 1:0] wburst; // registered burst type
reg [ 3:0] wlen; // registered awlen type (for wrapped over transfers)
wire start_write_burst_w;
reg start_write_burst_r; // next after start_write_burst_w
wire write_in_progress_w; // should go inactive last confirmed upstream cycle
reg write_in_progress;
reg [ 7:0] num_full_data = 0; // Number of full data bursts in FIFO
wire [5:0] wresp_num_in_fifo;
reg was_wresp_re=0;
wire wresp_re;
// documentation sais : "When set, allows the priority of a transaction at the head of the WrCmdQ to be promoted if higher
// priority transactions are backed up behind it." Whqt about demotion? Assuming it is not demoted
assign sim_wr_qos = (wrQosHeadOfCmdQEn && (wr_qos_in > wr_qos_out))? wr_qos_in : wr_qos_out;
assign sim_wr_cap = (wrFabricOutCmdEn && wrissuecap1en) ? wrIssueCap1 : wrIssueCap0;
assign wr_qos_in = wrFabricQosEn?(awqos & {4{awvalid}}) : staticQos;
//awqos & {4{awvalid}}
assign aresetn= ~rst; // probably not needed at all - docs say "do not use"
// Supported control register fields
assign reg_dout=(reg_rd && (reg_addr==AFI_WRDATAFIFO_LEVEL))?
{24'b0,wcount}:
( (reg_rd && (reg_addr==AFI_WRCHAN_CTRL))?
{20'b0,WrDataThreshold,2'b0,WrCmdReleaseMode,wrQosHeadOfCmdQEn,wrFabricOutCmdEn,wrFabricQosEn,wr32BitEn}:
( (reg_rd && (reg_addr==AFI_WRCHAN_ISSUINGCAP))?
{25'b0,wrIssueCap1,1'b0,wrIssueCap0}:
( (reg_rd && (reg_addr==AFI_WRQOS))?
{28'b0,staticQos}:32'bz)));
always @ (posedge aclk or posedge rst) begin
if (rst) begin
WrDataThreshold <= 'hf;
WrCmdReleaseMode <= 0;
wrQosHeadOfCmdQEn <= 0;
wrFabricOutCmdEn <= 0;
wrFabricQosEn <= 0;
wr32BitEn <= 0;
end else if (reg_wr && (reg_addr==AFI_WRCHAN_CTRL)) begin
WrDataThreshold <= reg_din[11:8];
WrCmdReleaseMode <= reg_din[5:4];
wrQosHeadOfCmdQEn <= reg_din[3];
wrFabricOutCmdEn <= reg_din[2];
wrFabricQosEn <= reg_din[1];
wr32BitEn <= reg_din[0];
end
if (rst) begin
wrIssueCap1 <= 0;
wrIssueCap0 <= 7;
end else if (reg_wr && (reg_addr==AFI_WRCHAN_ISSUINGCAP)) begin
wrIssueCap1 <= reg_din[6:4];
wrIssueCap0 <= reg_din[2:0];
end
if (rst) begin
staticQos <= 0;
end else if (reg_wr && (reg_addr==AFI_WRQOS)) begin
staticQos <= reg_din[3:0];
end
end
// generate ready signals for address and data
assign wready= !wcount[7] && (!(&wcount[6:0]) || !fifo_data_we_d);
always @ (posedge rst or posedge aclk) begin
if (rst) fifo_data_we_d<=0;
else fifo_data_we_d <= wready && wvalid;
end
assign awready= !wacount[5] && (!(&wacount[4:0]) || !fifo_addr_we_d);
always @ (posedge rst or posedge aclk) begin
if (rst) fifo_addr_we_d<=0;
else fifo_addr_we_d <= awready && awvalid;
end
// Count full data bursts ready in FIFO
always @ (posedge rst or posedge aclk) begin
if (rst) num_full_data <=0;
else if (wvalid && wready && wlast && !start_write_burst_w) num_full_data <= num_full_data + 1;
else if (!(wvalid && wready && wlast) && start_write_burst_w) num_full_data <= num_full_data - 1;
end
assign sim_wr_address= write_address;
assign enough_data=|num_full_data || ((WrCmdReleaseMode==2'b01) && (wcount > {4'b0,WrDataThreshold}));
assign fifo_wd_rd= write_in_progress && w_nempty && sim_wr_ready;
assign sim_wr_valid= write_in_progress && w_nempty; // for continuing writes
assign last_confirmed_write = (write_left==0) && fifo_wd_rd && wlast_out; // wlast_out should take precedence over write_left?
assign start_write_burst_w=
aw_nempty && enough_data &&
(! write_in_progress || last_confirmed_write);
assign write_in_progress_w=
(aw_nempty && enough_data) || (write_in_progress && !last_confirmed_write);
// AXI: Bursts should not cross 4KB boundaries (... and to limit size of the address incrementer)
// in 64 bit mode - low 3 bits are preserved, next 9 are incremented
assign next_wr_address[11:3] =
wburst[1]?
(wburst[0]? {9'bx}:((write_address[11:3] + 1) & {5'h1f, ~wlen[3:0]})):
(wburst[0]? (write_address[11:3]+1):(write_address[11:3]));
assign sim_wr_data= wdata_out;
assign sim_wid= wid_out;
assign sim_wr_stb=wstrb_out;
always @ (posedge aclk) begin
start_write_burst_r <= start_write_burst_w;
if (start_write_burst_r) begin
if (awid_r != wid_out) begin
$display ("%m: at time %t ERROR: awid=%h, wid=%h",$time,awid_out,wid_out);
$stop;
end
end
if (start_write_burst_w) begin
if (awsize_out != 2'h3) begin
$display ("%m: at time %t ERROR: awsize_out=%h, currently only 'h3 (8 bytes) is valid",$time,awsize_out);
$stop;
end
end
if (awvalid && awready) begin
if (((awlock ^ VALID_AWLOCK) & VALID_AWLOCK_MASK) != 0) begin
$display ("%m: at time %t ERROR: awlock = %h, valid %h with mask %h",$time, awlock, VALID_AWLOCK, VALID_AWLOCK_MASK);
$stop;
end
if (((awcache ^ VALID_AWCACHE) & VALID_AWCACHE_MASK) != 0) begin
$display ("%m: at time %t ERROR: awcache = %h, valid %h with mask %h",$time, awcache, VALID_AWCACHE, VALID_AWCACHE_MASK);
$stop;
end
if (((awprot ^ VALID_AWPROT) & VALID_AWPROT_MASK) != 0) begin
$display ("%m: at time %t ERROR: awprot = %h, valid %h with mask %h",$time, awprot, VALID_AWPROT, VALID_AWPROT_MASK);
$stop;
end
end
end
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 (fifo_wd_rd) write_left <= write_left-1; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 4-bit target.
if (rst) write_address <= 32'bx;
else if (start_write_burst_w) write_address <= awaddr_out; // precedence over inc
else if (fifo_wd_rd) write_address <= {write_address[31:12],next_wr_address[11:3],write_address[2:0]};
if (rst) awid_r <= 6'bx;
else if (start_write_burst_w) awid_r <= awid_out; // precedence over inc
end
fifo_same_clock_fill #( .DATA_WIDTH(50),.DATA_DEPTH(5)) // read - 4, write - 32?
waddr_i (
.rst (rst),
.clk (aclk),
.sync_rst (1'b0),
.we (awvalid && awready),
.re (start_write_burst_w),
.data_in ({awid[5:0], awburst[1:0], awsize[1:0], awlen[3:0], awaddr[31:0], wr_qos_in[3:0]}),
.data_out ({awid_out[5:0], awburst_out[1:0],awsize_out[1:0],awlen_out[3:0],awaddr_out[31:0], wr_qos_out[3:0]}),
.nempty (aw_nempty),
.half_full (), //aw_half_full),
.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(wacount) // output[3:0]
);
fifo_same_clock_fill #( .DATA_WIDTH(79),.DATA_DEPTH(7))
wdata_i (
.rst(rst),
.clk(aclk),
.sync_rst (1'b0),
.we(wvalid && wready),
.re(fifo_wd_rd), //start_write_burst_w), // wrong
.data_in({wlast, wid[5:0], wstrb[7:0], wdata[63:0]}),
.data_out({wlast_out,wid_out[5:0], wstrb_out[7:0], wdata_out[63:0]}),
.nempty(w_nempty),
.half_full(), //w_half_full),
.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(wcount) // output[3:0]
);
// **** Write response channel ****
wire [ 1:0] bresp_value=2'b0;
wire [ 1:0] bresp_in;
wire fifo_wd_rd_dly;
wire [5:0] bid_in;
// input [ 3:0] sim_bresp_latency, // latency in writing data outside of the module
dly_16 #(
.WIDTH(1)
) bresp_dly_16_i (
.clk(aclk), // input
.rst(rst), // input
.dly(sim_bresp_latency[3:0]), // input[3:0]
.din(last_confirmed_write), //fifo_wd_rd), // input[0:0]
.dout(fifo_wd_rd_dly) // output[0:0]
);
// first FIFO for bresp - latency outside of the module
// wresp per burst, not per item !
fifo_same_clock_fill #( .DATA_WIDTH(8),.DATA_DEPTH(5))
wresp_ext_i (
.rst(rst),
.clk(aclk),
.sync_rst (1'b0),
.we(last_confirmed_write), // fifo_wd_rd),
.re(fifo_wd_rd_dly), // not allowing RE next cycle after bvalid
.data_in({wid_out[5:0],bresp_value[1:0]}),
.data_out({bid_in[5:0],bresp_in[1:0]}),
.nempty(),
.half_full(), //),
.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]
);
assign wresp_re=bready && bvalid; // && !was_wresp_re;
always @ (posedge rst or posedge aclk) begin
if (rst) was_wresp_re<=0;
else was_wresp_re <= wresp_re;
end
assign bvalid=|wresp_num_in_fifo[5:1] || (!was_wresp_re && wresp_num_in_fifo[0]);
// second wresp FIFO (does it exist in the actual module)?
fifo_same_clock_fill #( .DATA_WIDTH(8),.DATA_DEPTH(5))
wresp_i (
.rst(rst),
.clk(aclk),
.sync_rst (1'b0),
.we(fifo_wd_rd_dly),
.re(wresp_re), // not allowing RE next cycle after bvalid
.data_in({bid_in[5:0],bresp_in[1:0]}),
.data_out({bid[5:0],bresp[1:0]}),
.nempty(), //bvalid),
.half_full(), //),
.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) // wresp_num_in_fifo) // output[3:0]
);
endmodule
/*******************************************************************************
* Module: simul_axi_master_rdaddr
* Date:2014-03-23
* Author: Andrey Filippov
* Description: Simulation model for AXI read address channel
*
* Copyright (c) 2014 Elphel, Inc.
* simul_axi_master_rdaddr.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.
*
* simul_axi_master_rdaddr.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_master_rdaddr
#(
parameter integer ID_WIDTH=12,
parameter integer ADDRESS_WIDTH=32,
parameter integer LATENCY=0, // minimal delay between inout and output ( 0 - next cycle)
parameter integer DEPTH=8, // maximal number of commands in FIFO
parameter DATA_DELAY = 3.5,
parameter VALID_DELAY = 4.0
// parameter integer DATA_2DEPTH=(1<<DATA_DEPTH)-1
)(
input clk,
input reset,
input [ID_WIDTH-1:0] arid_in,
input [ADDRESS_WIDTH-1:0] araddr_in,
input [3:0] arlen_in,
input [1:0] arsize_in,
input [1:0] arburst_in,
input [3:0] arcache_in,
input [2:0] arprot_in,
output [ID_WIDTH-1:0] arid,
output [ADDRESS_WIDTH-1:0] araddr,
output [3:0] arlen,
output [1:0] arsize,
output [1:0] arburst,
output [3:0] arcache,
output [2:0] arprot,
output arvalid,
input arready,
input set_cmd, // latch all other input data at posedge of clock
output ready // command/data FIFO can accept command
);
wire [ID_WIDTH-1:0] arid_out;
wire [ADDRESS_WIDTH-1:0] araddr_out;
wire [3:0] arlen_out;
wire [1:0] arsize_out;
wire [1:0] arburst_out;
wire [3:0] arcache_out;
wire [2:0] arprot_out;
wire arvalid_out;
assign #(DATA_DELAY) arid= arid_out;
assign #(DATA_DELAY) araddr= araddr_out;
assign #(DATA_DELAY) arlen= arlen_out;
assign #(DATA_DELAY) arsize= arsize_out;
assign #(DATA_DELAY) arburst= arburst_out;
assign #(DATA_DELAY) arcache= arcache_out;
assign #(DATA_DELAY) arprot= arprot_out;
assign #(VALID_DELAY) arvalid=arvalid_out;
simul_axi_fifo
#(
.WIDTH(ID_WIDTH+ADDRESS_WIDTH+15), // total number of output bits
.LATENCY(LATENCY), // minimal delay between inout and output ( 0 - next cycle)
.DEPTH(DEPTH) // maximal number of commands in FIFO
// parameter OUT_DELAY = 3.5,
) simul_axi_fifo_i (
.clk(clk), // input clk,
.reset(reset), // input reset,
.data_in({arid_in,araddr_in,arlen_in,arsize_in,arburst_in,arcache_in,arprot_in}), // input [WIDTH-1:0] data_in,
.load(set_cmd), // input load,
.input_ready(ready), // output input_ready,
.data_out({arid_out,araddr_out,arlen_out,arsize_out,arburst_out,arcache_out,arprot_out}), // output [WIDTH-1:0] data_out,
.valid(arvalid_out), // output valid,
.ready(arready)); // input ready);
endmodule
/*******************************************************************************
* Module: simul_axi_master_wdata
* Date:2014-03-24
* Author: Andrey Filippov
* Description: Simulation model for AXI write data channel
*
* Copyright (c) 2014 Elphel, Inc..
* simul_axi_master_wdata.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.
*
* simul_axi_master_wdata.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_master_wdata#(
parameter integer ID_WIDTH=12,
parameter integer DATA_WIDTH=32,
parameter integer WSTB_WIDTH= 4,
parameter integer LATENCY=0, // minimal delay between inout and output ( 0 - next cycle)
parameter integer DEPTH=8, // maximal number of commands in FIFO
parameter DATA_DELAY = 3.5,
parameter VALID_DELAY = 4.0
)(
input clk,
input reset,
input [ID_WIDTH-1:0] wid_in,
input [DATA_WIDTH-1:0] wdata_in,
input [WSTB_WIDTH-1:0] wstrb_in,
input wlast_in,
output [ID_WIDTH-1:0] wid,
output [DATA_WIDTH-1:0] wdata,
output [WSTB_WIDTH-1:0] wstrb,
output wlast,
output wvalid,
input wready,
input set_cmd, // latch all other input data at posedge of clock
output ready // command/data FIFO can accept command
);
wire [ID_WIDTH-1:0] wid_out;
wire [DATA_WIDTH-1:0] wdata_out;
wire [WSTB_WIDTH-1:0] wstrb_out;
wire wlast_out;
wire wvalid_out;
assign #(DATA_DELAY) wid= wid_out;
assign #(DATA_DELAY) wdata= wdata_out;
assign #(DATA_DELAY) wstrb= wstrb_out;
assign #(DATA_DELAY) wlast= wlast_out;
assign #(VALID_DELAY) wvalid= wvalid_out;
simul_axi_fifo
#(
.WIDTH(ID_WIDTH+DATA_WIDTH+WSTB_WIDTH+1), // total number of output bits
.LATENCY(LATENCY), // minimal delay between inout and output ( 0 - next cycle)
.DEPTH(DEPTH) // maximal number of commands in FIFO
) simul_axi_fifo_i (
.clk(clk), // input clk,
.reset(reset), // input reset,
.data_in({wid_in, wdata_in, wstrb_in, wlast_in}), // input [WIDTH-1:0] data_in,
.load(set_cmd), // input load,
.input_ready(ready), // output input_ready,
.data_out({wid_out, wdata_out, wstrb_out, wlast_out}), // output [WIDTH-1:0] data_out,
.valid(wvalid_out), // output valid,
.ready(wready)); // input ready);
endmodule
/*******************************************************************************
* Module: simul_axi_master_wraddr
* Date:2014-03-24
* Author: Andrey Filippov
* Description: Simulation model for AXI write address channel
*
* Copyright (c) 2014 Elphel, Inc..
* simul_axi_master_wraddr.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.
*
* simul_axi_master_wraddr.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_master_wraddr
#(
parameter integer ID_WIDTH=12,
parameter integer ADDRESS_WIDTH=32,
parameter integer LATENCY=0, // minimal delay between inout and output ( 0 - next cycle)
parameter integer DEPTH=8, // maximal number of commands in FIFO
parameter DATA_DELAY = 3.5,
parameter VALID_DELAY = 4.0
)(
input clk,
input reset,
input [ID_WIDTH-1:0] awid_in,
input [ADDRESS_WIDTH-1:0] awaddr_in,
input [3:0] awlen_in,
input [1:0] awsize_in,
input [1:0] awburst_in,
input [3:0] awcache_in,
input [2:0] awprot_in,
output [ID_WIDTH-1:0] awid,
output [ADDRESS_WIDTH-1:0] awaddr,
output [3:0] awlen,
output [1:0] awsize,
output [1:0] awburst,
output [3:0] awcache,
output [2:0] awprot,
output awvalid,
input awready,
input set_cmd, // latch all other input data at posedge of clock
output ready // command/data FIFO can accept command
);
wire [ID_WIDTH-1:0] awid_out;
wire [ADDRESS_WIDTH-1:0] awaddr_out;
wire [3:0] awlen_out;
wire [1:0] awsize_out;
wire [1:0] awburst_out;
wire [3:0] awcache_out;
wire [2:0] awprot_out;
wire awvalid_out;
assign #(DATA_DELAY) awid= awid_out;
assign #(DATA_DELAY) awaddr= awaddr_out;
assign #(DATA_DELAY) awlen= awlen_out;
assign #(DATA_DELAY) awsize= awsize_out;
assign #(DATA_DELAY) awburst= awburst_out;
assign #(DATA_DELAY) awcache= awcache_out;
assign #(DATA_DELAY) awprot= awprot_out;
assign #(VALID_DELAY) awvalid= awvalid_out;
simul_axi_fifo
#(
.WIDTH(ID_WIDTH+ADDRESS_WIDTH+15), // total number of output bits
.LATENCY(LATENCY), // minimal delay between inout and output ( 0 - next cycle)
.DEPTH(DEPTH) // maximal number of commands in FIFO
// parameter OUT_DELAY = 3.5,
) simul_axi_fifo_i (
.clk(clk), // input clk,
.reset(reset), // input reset,
.data_in({awid_in,awaddr_in,awlen_in,awsize_in,awburst_in,awcache_in,awprot_in}), // input [WIDTH-1:0] data_in,
.load(set_cmd), // input load,
.input_ready(ready), // output input_ready,
.data_out({awid_out,awaddr_out,awlen_out,awsize_out,awburst_out,awcache_out,awprot_out}), // output [WIDTH-1:0] data_out,
.valid(awvalid_out), // output valid,
.ready(awready)); // input ready);
endmodule
/*******************************************************************************
* Module: simul_axi_read
* Date:2014-04-06
* Author: Andrey Filippov
* Description: simulation of read data through maxi channel
*
* Copyright (c) 2014 Elphel, Inc.
* simul_axi_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.
*
* simul_axi_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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_read #(
parameter ADDRESS_WIDTH=10
)(
input clk,
input reset,
input last, // last data word in burst
input data_stb, // data strobe (RVALID & RREADY) genearted externally
input [ADDRESS_WIDTH-1:0] raddr, // read burst address as written by axi master, 10 significant bits [11:2], valid at rcmd
input [ 3:0] rlen, // burst length as written by axi master, valid at rcmd
input rcmd, // read command (address+length) strobe
output [ADDRESS_WIDTH-1:0] addr_out, // output address
output burst, // burst in progress
output reg err_out); // data last does not match predicted or FIFO over/under run
wire [ADDRESS_WIDTH-1:0] raddr_fifo; // raddr after fifo
wire [ 3:0] rlen_fifo; // rlen after fifo
wire fifo_valid; // fifo out valid
reg burst_r=0;
reg [ 3:0] left_plus_1;
wire start_burst=fifo_valid && data_stb && !burst_r;
wire generated_last= burst?(left_plus_1==1): ( fifo_valid && (rlen_fifo==0)) ;
wire fifo_in_rdy;
wire error_w= (data_stb && (last != generated_last)) || (rcmd && !fifo_in_rdy) || (start_burst && !fifo_valid);
reg [ADDRESS_WIDTH-1:0] adr_out_r;
assign burst=burst_r || start_burst;
assign addr_out=start_burst?raddr_fifo:adr_out_r;
always @ (posedge reset or posedge clk) begin
if (reset) burst_r <= 0;
else if (start_burst) burst_r <= rlen_fifo!=0;
// else if (last && data_stb) burst_r <= 0;
else if (generated_last && data_stb) burst_r <= 0;
if (reset) left_plus_1 <= 0;
else if (start_burst) left_plus_1 <= rlen_fifo;
else if (data_stb) left_plus_1 <= left_plus_1-1;
if (reset) err_out <= 0;
else err_out <= error_w;
// if (reset) was_last <= 0;
// else if (data_stb) was_last <= last;
end
always @ (posedge clk) begin
if (start_burst) adr_out_r <= raddr_fifo+1; // simulating only address incremental mode
else if (data_stb) adr_out_r <= adr_out_r + 1;
end
simul_fifo
#(
.WIDTH(ADDRESS_WIDTH+4),
.DEPTH(64)
)simmul_fifo_i(
.clk(clk),
.reset(reset),
// .data_in({rlen[3:0],raddr[11:2]}), // did not detect raddr[11:2] for input [ 9:0] raddr
.data_in({rlen[3:0],raddr}),
.load(rcmd),
.input_ready(fifo_in_rdy),
.data_out({rlen_fifo, raddr_fifo}),
.valid(fifo_valid),
.ready(start_burst));
endmodule
/*******************************************************************************
* Module: simul_axi_slow_ready
* Date:2014-03-24
* Author: Andrey Filippov
* Description: Simulation model for AXI: slow ready generation
*
* Copyright (c) 2014 Elphel, Inc..
* simul_axi_slow_ready.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.
*
* simul_axi_slow_ready.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_axi_slow_ready(
input clk,
input reset,
input [3:0] delay,
input valid,
output ready
);
reg [14:0] rdy_reg;
assign ready=(delay==0)?1'b1: ((((rdy_reg[14:0] >> (delay-1)) & 1) != 0)?1'b1:1'b0);
always @ (posedge clk or posedge reset) begin
if (reset) rdy_reg <=0;
else if (!valid || ready) rdy_reg <=0;
else rdy_reg <={rdy_reg[13:0],valid};
end
endmodule
/*******************************************************************************
* Module: simul_fifo
* Date:2014-04-06
* Author: Andrey Filippov
* Description: simple fifo for simulation
*
* Copyright (c) 2014 Elphel, Inc.
* simul_fifo.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.
*
* simul_fifo.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module simul_fifo
#(
parameter integer WIDTH= 32, // total number of output bits
parameter integer DEPTH= 64, // maximal number of words in FIFO
// parameter OUT_DELAY = 3.5,
parameter integer FIFO_DEPTH=DEPTH+1
// parameter integer DATA_2DEPTH=(1<<DATA_DEPTH)-1
)(
input clk,
input reset,
input [WIDTH-1:0] data_in,
input load,
output input_ready,
output [WIDTH-1:0] data_out,
output valid,
input ready);
reg [WIDTH-1:0] fifo [0:FIFO_DEPTH-1];
integer in_address;
integer out_address;
integer count;
assign data_out= fifo[out_address];
assign valid= count!=0;
assign input_ready= count<DEPTH;
always @ (posedge clk or posedge reset) begin
if (reset) in_address <= 0;
else if (load) in_address <= (in_address==(FIFO_DEPTH-1))?0:in_address+1;
if (reset) out_address <= 0;
else if (valid && ready) out_address <= (out_address==(FIFO_DEPTH-1))?0:out_address+1;
if (reset) count <= 0;
else if (!(valid && ready) && load) count <= count+1;
else if (valid && ready && !load) count <= count-1;
end
always @ (posedge clk) begin
if (load) fifo[in_address] <= data_in;
end
endmodule
\ No newline at end of file
/*******************************************************************************
* Module: axi_hp_clk
* Date:2015-04-27
* Author: Andrey Filippov
* Description: Generate global clock for axi_hp
*
* Copyright (c) 2015 Elphel, Inc.
* axi_hp_clk.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.
*
* axi_hp_clk.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module axi_hp_clk#(
parameter CLKIN_PERIOD = 20, //ns >1.25, 600<Fvco<1200
parameter CLKFBOUT_MULT_AXIHP = 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
parameter CLKFBOUT_DIV_AXIHP = 6 // To get 150MHz for the reference clock
)(
input rst,
input clk_in,
output clk_axihp,
output locked_axihp
);
wire clkfb_axihp, clk_axihp_pre;
BUFG clk_axihp_i (.O(clk_axihp), .I(clk_axihp_pre));
pll_base #(
.CLKIN_PERIOD(CLKIN_PERIOD), // 20
.BANDWIDTH("OPTIMIZED"),
.CLKFBOUT_MULT(CLKFBOUT_MULT_AXIHP), // 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
.CLKOUT0_DIVIDE(CLKFBOUT_DIV_AXIHP), // 6, // To get 300MHz for the reference clock
.REF_JITTER1(0.010),
.STARTUP_WAIT("FALSE")
) pll_base_i (
.clkin(clk_in), // input
.clkfbin(clkfb_axihp), // input
// .rst(rst), // input
.rst(rst), // input
.pwrdwn(1'b0), // input
.clkout0(clk_axihp_pre), // output
.clkout1(), // output
.clkout2(), // output
.clkout3(), // output
.clkout4(), // output
.clkout5(), // output
.clkfbout(clkfb_axihp), // output
.locked(locked_axihp) // output
);
endmodule
/*******************************************************************************
* Module: dly01_16
* Date:2014-05-30
* Author: Andrey Filippov
* Description: Synchronous delay by 1-16 clock cycles with reset (will map to primitive)
*
* Copyright (c) 2014 Elphel, Inc.
* dly01_16.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.
*
* dly01_16.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module dly01_16(
input clk,
input rst,
input [3:0] dly,
input din,
output dout
);
reg [15:0] sr=0;
`ifdef SHREG_SEQUENTIAL_RESET
always @ (posedge clk) begin
sr <= {sr[14:0], din & ~rst};
end
`else
// always @ (posedge rst or posedge clk) begin
always @ (posedge clk) begin
if (rst) sr <=0;
else sr <= {sr[14:0],din};
end
`endif
`ifdef SIMULATION
assign dout = (|sr) ? ((&sr) ? 1'b1 : sr[dly]) : 1'b0 ;
`else
assign dout =sr[dly];
`endif
endmodule
/*******************************************************************************
* Module: dly_16
* Date:2014-05-30
* Author: Andrey Filippov
* Description: Synchronous delay by 1-16 clock cycles with reset (will map to primitives)
*
* Copyright (c) 2014 Elphel, Inc.
* dly_16.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.
*
* dly_16.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module dly_16 #(
parameter WIDTH=1
)(
input clk,
input rst,
input [3:0] dly,
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
generate
genvar i;
for (i=0; i < WIDTH; i=i+1) begin: bit_block
dly01_16 dly01_16_i (
.clk(clk), // input
.rst(rst), // input
.dly(dly), // input[3:0]
.din(din[i]), // input
.dout(dout[i]) // output reg
);
end
endgenerate
endmodule
/*******************************************************************************
* Module: fifo_cross_clocks
* Date:2014-05-20
* Author: Andrey Filippov
* Description: Configurable FIFO with separate read and write clocks
*
* Copyright (c) 2014 Elphel, Inc.
* fifo_cross_clocks.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.
*
* fifo_cross_clocks.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module fifo_cross_clocks
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4 // >=3
) (
input rst, // async reset, active high (global)
input rrst, // @ posedge rclk - sync reset
input wrst, // @ posedge wclk - sync reset
input rclk, // read clock - positive edge
input wclk, // write 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 nempty, // FIFO has some data (sync to rclk)
output half_empty // FIFO half full (wclk) -(not more than 5/8 full)
);
localparam integer DATA_2DEPTH=(1<<DATA_DEPTH)-1;
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
reg [DATA_DEPTH-1:0] raddr;
reg [DATA_DEPTH-1:0] waddr;
reg [DATA_DEPTH-1:0] waddr_gray; //SuppressThisWarning ISExst VivadoSynthesis : MSB(waddr_gray) == MSB(waddr)
reg [DATA_DEPTH-1:0] waddr_gray_rclk;
wire [DATA_DEPTH-1:0] waddr_plus1 = waddr +1;
wire [DATA_DEPTH-1:0] waddr_plus1_gray = waddr_plus1 ^ {1'b0,waddr_plus1[DATA_DEPTH-1:1]};
wire [DATA_DEPTH-1:0] raddr_gray = raddr ^ {1'b0,raddr[DATA_DEPTH-1:1]};
wire [DATA_DEPTH-1:0] raddr_plus1 = raddr +1;
wire [2:0] raddr_plus1_gray_top3 = raddr_plus1[DATA_DEPTH-1:DATA_DEPTH-3] ^ {1'b0,raddr_plus1[DATA_DEPTH-1:DATA_DEPTH-2]};
reg [2:0] raddr_gray_top3; //SuppressThisWarning ISExst VivadoSynthesis : MSB(raddr_gray_top3) == MSB(raddr)
reg [2:0] raddr_gray_top3_wclk;
wire [2:0] raddr_top3_wclk = {
raddr_gray_top3_wclk[2],
raddr_gray_top3_wclk[2]^raddr_gray_top3_wclk[1],
raddr_gray_top3_wclk[2]^raddr_gray_top3_wclk[1]^raddr_gray_top3_wclk[0]};
wire [2:0] waddr_top3=waddr[DATA_DEPTH-1:DATA_DEPTH-3];
wire [2:0] addr_diff=waddr_top3[2:0]-raddr_top3_wclk[2:0];
// half-empty does not need to be precise, it uses 3 MSBs of the write address
// converting to Gray code (easy) and then back (can not be done parallel easily).
// Comparing to 1/8'th of the depth with one-bit Gray code error results in uncertainty
// of +/-1/8, so half_empty means "no more than 5/8 full"
assign half_empty=~addr_diff[2];
// False positive in nempty can only happen if
// a) it is transitioning from empty to non-empty due to we pulse
// b) it is transitioning to overrun - too bad already
// false negative - OK, just wait for the next rclk
// assign nempty=waddr_gray_rclk != raddr_gray;
// assign nempty=waddr_gray_rclk[3:0] != raddr_gray[3:0];
assign nempty= (waddr_gray_rclk[3:0] ^ raddr_gray[3:0]) != 4'b0;
assign data_out=ram[raddr];
always @ (posedge wclk or posedge rst) begin
if (rst) waddr <= 0;
else if (wrst) waddr <= 0;
else if (we) waddr <= waddr_plus1;
if (rst) waddr_gray <= 0;
else if (wrst) waddr_gray <= 0;
else if (we) waddr_gray [3:0] <= waddr_plus1_gray[3:0];
end
always @ (posedge rclk or posedge rst) begin
// making rrst set FIFO to empty regardless of current waddr (write should be stopped)
if (rst) raddr <= waddr; // 0;
else if (rrst) raddr <= waddr; // 0;
else if (re) raddr <= raddr_plus1;
if (rst) raddr_gray_top3 <= waddr[DATA_DEPTH-1 -: 3] ^ {1'b0,waddr[DATA_DEPTH-1 -: 2]}; // 0;
else if (rrst) raddr_gray_top3 <= waddr[DATA_DEPTH-1 -: 3] ^ {1'b0,waddr[DATA_DEPTH-1 -: 2]}; // 0;
else if (re) raddr_gray_top3 <= raddr_plus1_gray_top3;
end
always @ (posedge rclk) begin
waddr_gray_rclk[3:0] <= waddr_gray[3:0];
end
always @ (posedge wclk) begin
raddr_gray_top3_wclk[2:0] <= raddr_gray_top3[2:0];
if (we) ram[waddr] <= data_in;
end
endmodule
/*******************************************************************************
* Module: fifo_same_clock
* Date:2014-05-20
* Author: Andrey Filippov
* Description: Configurable synchronous FIFO using the same clock for read and write
*
* Copyright (c) 2014 Elphel, Inc.
* fifo_same_clock.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.
*
* fifo_same_clock.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
`include "system_defines.vh"
//`define DEBUG_FIFO 1
module fifo_same_clock
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4
)
(
input rst, // reset, active high
input clk, // clock - positive edge
input sync_rst, // synchronously reset fifo;
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 nempty, // FIFO has some data
output reg half_full // FIFO half full
`ifdef DEBUG_FIFO
,output reg under, // debug outputs - under - attempt to read from empty
output reg over, // overwritten
output reg [DATA_DEPTH-1:0] wcount,
output reg [DATA_DEPTH-1:0] rcount,
output [DATA_DEPTH-1:0] num_in_fifo
`endif
);
localparam integer DATA_2DEPTH=(1<<DATA_DEPTH)-1;
//ISExst: FF/Latch ddrc_test01.axibram_write_i.waddr_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
//ISExst: FF/Latch ddrc_test01.axibram_read_i.raddr_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
//ISExst: FF/Latch ddrc_test01.axibram_write_i.wdata_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
// Do not understand - why?
reg [DATA_DEPTH-1:0] fill=0; // RAM fill
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-1:0] next_fill;
reg wem;
wire rem;
reg out_full=0; //output register full
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
reg ram_nempty;
// assign next_fill = fill[DATA_DEPTH-1:0]+((wem && ~rem)?1:((~wem && rem && ram_nempty)?-1:0));
assign rem= ram_nempty && (re || !out_full);
assign data_out=outreg;
assign nempty=out_full;
`ifdef DEBUG_FIFO
assign num_in_fifo=fill[DATA_DEPTH-1:0];
`endif
always @ (posedge clk or posedge rst) begin
if (rst) fill <= 0;
else if (sync_rst) fill <= 0;
// else fill <= next_fill;
else if ( wem && ~rem) fill <= fill + 1;
else if (~wem && rem) fill <= fill - 1;
if (rst) wem <= 0;
else if (sync_rst) wem <= 0;
else wem <= we;
if (rst) ram_nempty <= 0;
else if (sync_rst) ram_nempty <= 0;
// else ram_nempty <= (next_fill != 0);
// else ram_nempty <= wem || (|fill[DATA_DEPTH-1:1]) || (fill[0] && !rem);
else ram_nempty <= (|fill[DATA_DEPTH-1:1]) || (fill[0] && wem) || ((fill[0] || wem) && !rem) ;
if (rst) wa <= 0;
else if (sync_rst) wa <= 0;
else if (wem) wa <= wa+1;
if (rst) ra <= 0;
else if (sync_rst) ra <= 0;
else if (rem) ra <= ra+1;
else if (!ram_nempty) ra <= wa; // Just recover from bit errors
if (rst) out_full <= 0;
else if (sync_rst) out_full <= 0;
else if (rem && ~re) out_full <= 1;
else if (re && ~rem) out_full <= 0;
`ifdef DEBUG_FIFO
if (rst) wcount <= 0;
else if (sync_rst) wcount <= 0;
else if (we) wcount <= wcount + 1;
if (rst) rcount <= 0;
else if (sync_rst) rcount <= 0;
else if (re) rcount <= rcount + 1;
`endif
end
// no reset elements
always @ (posedge clk) begin
half_full <=(fill & (1<<(DATA_DEPTH-1)))!=0;
if (wem) ram[wa] <= inreg;
if (we) inreg <= data_in;
if (rem) outreg <= ram[ra];
`ifdef DEBUG_FIFO
under <= ~we & re & ~nempty; // underrun error
over <= we & ~re & (fill == (1<< (DATA_DEPTH-1))); // overrun error
`endif
end
endmodule
/*******************************************************************************
* Module: fifo_same_clock_fill
* Date:2014-05-20
* Author: Andrey Filippov
* Description: Configurable synchronous FIFO using the same clock for read and write.
* Provides fill level - number of words currently in FIFO
*
* Copyright (c) 2014 Elphel, Inc.
* fifo_same_clock_fill.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.
*
* fifo_same_clock_fill.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
`include "system_defines.vh"
module fifo_same_clock_fill
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4
)
(
input rst, // reset, active high
input clk, // clock - positive edge
input sync_rst, // synchronously reset fifo;
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 nempty, // FIFO has some data
output reg half_full, // FIFO half full
output reg under, // debug outputs - under - attempt to read from empty
output reg over, // overwritten
output reg [DATA_DEPTH-1:0] wcount,
output reg [DATA_DEPTH-1:0] rcount,
output [DATA_DEPTH: 0] num_in_fifo
);
localparam integer DATA_2DEPTH=(1<<DATA_DEPTH)-1;
//ISExst: FF/Latch ddrc_test01.axibram_write_i.waddr_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
//ISExst: FF/Latch ddrc_test01.axibram_read_i.raddr_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
//ISExst: FF/Latch ddrc_test01.axibram_write_i.wdata_i.fill[4] has a constant value of 0 in block <ddrc_test01>. This FF/Latch will be trimmed during the optimization process.
// Do not understand - why?
reg [DATA_DEPTH: 0] fill=0; // RAM fill
reg [DATA_DEPTH: 0] fifo_fill=0; // FIFO (RAM+reg) fill
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 out_full=0; //output register full
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
reg ram_nempty;
assign next_fill = fill[DATA_DEPTH:0]+((wem && ~rem)?1:((~wem && rem && ram_nempty)?-1:0));
assign rem= ram_nempty && (re || !out_full);
assign data_out=outreg;
assign nempty=out_full;
// assign num_in_fifo=fill[DATA_DEPTH:0];
assign num_in_fifo=fifo_fill[DATA_DEPTH:0];
always @ (posedge clk or posedge rst) begin
if (rst) fill <= 0;
else if (sync_rst) fill <= 0;
else fill <= next_fill;
if (rst) fifo_fill <= 0;
else if (sync_rst) fifo_fill <= 0;
else if ( we && !re) fifo_fill <= fifo_fill+1;
else if (!we && re) fifo_fill <= fifo_fill-1;
if (rst) wem <= 0;
else if (sync_rst) wem <= 0;
else wem <= we;
if (rst) ram_nempty <= 0;
else if (sync_rst) ram_nempty <= 0;
else ram_nempty <= (next_fill != 0);
if (rst) wa <= 0;
else if (sync_rst) wa <= 0;
else if (wem) wa <= wa+1;
if (rst) ra <= 0;
else if (sync_rst) ra <= 0;
else if (rem) ra <= ra+1;
else if (!ram_nempty) ra <= wa; // Just recover from bit errors
if (rst) out_full <= 0;
else if (sync_rst) out_full <= 0;
else if (rem && ~re) out_full <= 1;
else if (re && ~rem) out_full <= 0;
if (rst) wcount <= 0;
else if (sync_rst) wcount <= 0;
else if (we) wcount <= wcount + 1;
if (rst) rcount <= 0;
else if (sync_rst) rcount <= 0;
else if (re) rcount <= rcount + 1;
end
// no reset elements
always @ (posedge clk) begin
half_full <=(fill & (1<<(DATA_DEPTH-1)))!=0;
if (wem) ram[wa] <= inreg;
if (we) inreg <= data_in;
if (rem) outreg <= ram[ra];
// under <= ~we & re & ~nempty; // underrun error
// over <= we & ~re & (fill == (1<< (DATA_DEPTH-1))); // overrun error
under <= re & ~nempty; // underrun error
over <= wem & ~rem & fill[DATA_DEPTH] & ~fill[DATA_DEPTH-1]; // overrun error
end
endmodule
/*******************************************************************************
* Module: fifo_sameclock_control
* Date:2016-01-20
* Author: andrey
* Description: BRAM-based fifo control, uses BARM output registers
*
* Copyright (c) 2016 Elphel, Inc .
* fifo_sameclock_control.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.
*
* fifo_sameclock_control.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/> .
*******************************************************************************/
`timescale 1ns/1ps
module fifo_sameclock_control#(
parameter WIDTH = 9
)(
input clk,
input rst, // clock-sync reset
input wr, // write to FIFO (also applied directly to memory)
input rd, // read from FIFO, internally masked by nempty
output nempty, // at read side
output [WIDTH:0] fill_in, // valid at write side, latency 1 for read
output reg [WIDTH-1:0] mem_wa,
output reg [WIDTH-1:0] mem_ra,
output mem_re,
output mem_regen,
output reg over,
output reg under
);
reg [WIDTH:0] fill_ram;
reg ramo_full;
reg rreg_full;
assign mem_re = (|fill_ram) && (!ramo_full || !rreg_full || rd);
assign mem_regen = ramo_full && (!rreg_full || rd);
assign nempty = rreg_full;
assign fill_in = fill_ram;
always @ (posedge clk) begin
if (rst) mem_wa <= 0;
else if (wr) mem_wa <= mem_wa + 1;
if (rst) mem_ra <= 0;
else if (mem_re) mem_ra <= mem_ra + 1;
if (rst) fill_ram <= 0;
else if (wr ^ mem_re) fill_ram <= mem_re ? (fill_ram - 1) : (fill_ram + 1);
if (rst) ramo_full <= 0;
else if (mem_re ^ mem_regen) ramo_full <= mem_re;
if (rst) rreg_full <= 0;
else if (mem_regen ^ (rd && rreg_full)) rreg_full <= mem_regen;
if (rst) under <= 0;
else under <= rd && ! rreg_full;
if (rst) over <= 0;
else over <= wr && fill_ram[WIDTH] && !fill_ram[WIDTH-1];
end
endmodule
/*******************************************************************************
* Module: pulse_cross_clock
* Date:2015-04-27
* Author: Andrey Filippov
* Description: Propagate a single pulse through clock domain boundary
* For same frequencies input pulses can have 1:3 duty cycle EXTRA_DLY=0
* and 1:5 for EXTRA_DLY=1
*
* Copyright (c) 2015 Elphel, Inc.
* pulse_cross_clock.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.
*
* pulse_cross_clock.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module pulse_cross_clock#(
parameter EXTRA_DLY=0 // for
)(
input rst,
input src_clk,
input dst_clk,
input in_pulse, // single-cycle positive pulse
output out_pulse,
output busy
);
localparam EXTRA_DLY_SAFE=EXTRA_DLY ? 1 : 0;
`ifndef IGNORE_ATTR
(* KEEP = "TRUE" *)
`endif
reg in_reg = 0; // can not be ASYNC_REG as it can not be put together with out_reg
//WARNING: [Constraints 18-1079] Register sensors393_i/sensor_channel_block[0].sensor_channel_i/sens_sync_i/pulse_cross_clock_trig_in_pclk_i/in_reg_reg
// and sensors393_i/sensor_channel_block[0].sensor_channel_i/sens_sync_i/pulse_cross_clock_trig_in_pclk_i/out_reg_reg[0] are
//from the same synchronizer and have the ASYNC_REG property set, but could not be placed into the same slice due to constraints
// or mismatched control signals on the registers.
`ifndef IGNORE_ATTR
(* ASYNC_REG = "TRUE" *)
`endif
reg [2:0] out_reg = 0;
`ifndef IGNORE_ATTR
(* ASYNC_REG = "TRUE" *)
`endif
reg busy_r = 0;
assign out_pulse=out_reg[2];
assign busy=busy_r; // in_reg;
always @(posedge src_clk or posedge rst) begin
if (rst) in_reg <= 0;
else in_reg <= in_pulse || (in_reg && !out_reg[EXTRA_DLY_SAFE]);
if (rst) busy_r <= 0;
else busy_r <= in_pulse || in_reg || (busy_r && (|out_reg[EXTRA_DLY_SAFE:0]));
end
// always @(posedge dst_clk or posedge rst) begin
always @(posedge dst_clk) begin
out_reg <= {out_reg[0] & ~out_reg[1],out_reg[0],in_reg};
end
endmodule
/*******************************************************************************
* Module: resync_data
* Date:2015-12-22
* Author: Andrey Filippov
* Description: Resynchronize data between clock domains. No over/underruns
* are checker, start with half FIFO full. Async reset sets
* specifies output values regardless of the clocks
*
* Copyright (c) 2014 Elphel, Inc.
* resync_data.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.
*
* resync_data.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module resync_data
#(
parameter integer DATA_WIDTH=16,
parameter integer DATA_DEPTH=4, // >= 2
parameter INITIAL_VALUE = 0
) (
input arst, // async reset, active high (global)
input srst, // same as arst, but relies on the clocks
input wclk, // write clock - positive edge
input rclk, // read clock - positive edge
input we, // write enable
input re, // read enable
input [DATA_WIDTH-1:0] data_in, // input data
output reg [DATA_WIDTH-1:0] data_out, // output data
output reg valid // data valid @ rclk
);
localparam integer DATA_2DEPTH=(1<<DATA_DEPTH)-1;
reg [DATA_WIDTH-1:0] ram [0:DATA_2DEPTH];
reg [DATA_DEPTH-1:0] raddr;
reg [DATA_DEPTH-1:0] waddr;
reg [1:0] rrst = 3;
always @ (posedge rclk or posedge arst) begin
if (arst) valid <= 0;
else if (srst) valid <= 0;
else if (&waddr[DATA_DEPTH-2:0] && we) valid <= 1; // just once set and stays until reset
end
always @ (posedge wclk or posedge arst) begin
if (arst) waddr <= 0;
else if (srst) waddr <= 0;
else if (we) waddr <= waddr + 1;
end
always @ (posedge rclk or posedge arst) begin
if (arst) rrst <= 3;
else if (srst) rrst <= 3; // resync to rclk
else rrst <= rrst << 1;
if (arst) raddr <= 0;
else if (rrst[0]) raddr <= 0;
else if (re || rrst[1]) raddr <= raddr + 1;
if (arst) data_out <= INITIAL_VALUE;
else if (rrst[0]) data_out <= INITIAL_VALUE;
else if (re || rrst[1]) data_out <= ram[raddr];
end
always @ (posedge wclk) begin
if (we) ram[waddr] <= data_in;
end
endmodule
/*******************************************************************************
* Module: pll_base
* Date:2014-05-01
* Author: Andrey Filippov
* Description: PLLE2_BASE wrapper
*
* Copyright (c) 2014 Elphel, Inc.
* pll_base.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.
*
* pll_base.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
module pll_base#(
parameter CLKIN_PERIOD = 0.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
parameter BANDWIDTH = "OPTIMIZED", // "OPTIMIZED", "HIGH","LOW"
parameter CLKFBOUT_MULT = 1, // integer 1 to 64 . Together with CLKOUT#_DIVIDE and DIVCLK_DIVIDE
parameter CLKFBOUT_PHASE = 0.000, // CLOCK FEEDBACK phase in degrees (3 significant digits, -360.000...+360.000)
parameter CLKOUT0_PHASE = 0.000, // CLOCK0 phase in degrees (3 significant digits, -360.000...+360.000)
parameter CLKOUT1_PHASE = 0.000, // Initial/static fine phase shift, 1/(56*Fvco) actual step
parameter CLKOUT2_PHASE = 0.000,
parameter CLKOUT3_PHASE = 0.000,
parameter CLKOUT4_PHASE = 0.000,
parameter CLKOUT5_PHASE = 0.000,
parameter CLKOUT0_DUTY_CYCLE= 0.5, // CLOCK 0 output duty factor, 3 significant digits
parameter CLKOUT1_DUTY_CYCLE= 0.5,
parameter CLKOUT2_DUTY_CYCLE= 0.5,
parameter CLKOUT3_DUTY_CYCLE= 0.5,
parameter CLKOUT4_DUTY_CYCLE= 0.5,
parameter CLKOUT5_DUTY_CYCLE= 0.5,
parameter CLKOUT0_DIVIDE = 1, // CLK0 outout divide, integer 1..128
parameter CLKOUT1_DIVIDE = 1, // CLK1 outout divide, integer 1..128 (determins a phase step as a fraction of pi/4)
parameter CLKOUT2_DIVIDE = 1,
parameter CLKOUT3_DIVIDE = 1,
parameter CLKOUT4_DIVIDE = 1,
parameter CLKOUT5_DIVIDE = 1,
parameter DIVCLK_DIVIDE = 1, // Integer 1..106. Divides all outputs with respect to CLKIN
parameter REF_JITTER1 = 0.010, // Expected jitter on CLKIN1 (0.000..0.999)
parameter STARTUP_WAIT = "FALSE" // Delays "DONE" signal until MMCM is locked
)
(
input clkin, // General clock input
input clkfbin, // Feedback clock input
input rst, // asynchronous reset input
input pwrdwn, // power down input
output clkout0, // output 0, HPC BUFR/BUFIO capable
output clkout1, // output 1, HPC BUFR/BUFIO capable
output clkout2, // output 2, HPC BUFR/BUFIO capable
output clkout3, // output 3, HPC BUFR/BUFIO capable
output clkout4, // output 4, HPC BUFR/BUFIO not capable
output clkout5, // output 5, HPC BUFR/BUFIO not capable
output clkfbout, // dedicate feedback output
output locked // PLL locked output
);
PLLE2_BASE #(
.BANDWIDTH (BANDWIDTH),
.CLKFBOUT_MULT (CLKFBOUT_MULT),
.CLKFBOUT_PHASE (CLKFBOUT_PHASE),
.CLKIN1_PERIOD (CLKIN_PERIOD),
.CLKOUT0_DIVIDE (CLKOUT0_DIVIDE),
.CLKOUT0_DUTY_CYCLE (CLKOUT0_DUTY_CYCLE),
.CLKOUT0_PHASE (CLKOUT0_PHASE),
.CLKOUT1_DIVIDE (CLKOUT1_DIVIDE),
.CLKOUT1_DUTY_CYCLE (CLKOUT1_DUTY_CYCLE),
.CLKOUT1_PHASE (CLKOUT1_PHASE),
.CLKOUT2_DIVIDE (CLKOUT2_DIVIDE),
.CLKOUT2_DUTY_CYCLE (CLKOUT2_DUTY_CYCLE),
.CLKOUT2_PHASE (CLKOUT2_PHASE),
.CLKOUT3_DIVIDE (CLKOUT3_DIVIDE),
.CLKOUT3_DUTY_CYCLE (CLKOUT3_DUTY_CYCLE),
.CLKOUT3_PHASE (CLKOUT3_PHASE),
.CLKOUT4_DIVIDE (CLKOUT4_DIVIDE),
.CLKOUT4_DUTY_CYCLE (CLKOUT4_DUTY_CYCLE),
.CLKOUT4_PHASE (CLKOUT4_PHASE),
.CLKOUT5_DIVIDE (CLKOUT5_DIVIDE),
.CLKOUT5_DUTY_CYCLE (CLKOUT5_DUTY_CYCLE),
.CLKOUT5_PHASE (CLKOUT5_PHASE),
.DIVCLK_DIVIDE (DIVCLK_DIVIDE),
.REF_JITTER1 (REF_JITTER1),
.STARTUP_WAIT (STARTUP_WAIT)
) PLLE2_BASE_i (
.CLKFBOUT (clkfbout), // output
.CLKOUT0 (clkout0), // output
.CLKOUT1 (clkout1), // output
.CLKOUT2 (clkout2), // output
.CLKOUT3 (clkout3), // output
.CLKOUT4 (clkout4), // output
.CLKOUT5 (clkout5), // output
.LOCKED (locked), // output
.CLKFBIN (clkfbin), // input
.CLKIN1 (clkin), // input
.PWRDWN (pwrdwn), // input
.RST (rst) // input
);
endmodule
/*******************************************************************************
* Copyright (c) 2015 Elphel, Inc.
* Dual port memory wrapper, with variable width write and variable width read
* using "SDP" or "TDP" mode of RAMB18E1 (half of RAMB18E1)
* Uses parity bits to extend total data width (minimal width should be >=8).
* ram18p_var_w_var_r.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.
*
* ram18p_var_w_var_r.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/>.
*******************************************************************************/
`include "system_defines.vh"
/*
Address/data widths
Connect unused data to 1b0, unused addresses - to 1'b1
RAMB18E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[13:0] | D[0] | --- |
| 2 | A[13:1] | D[1:0] | --- |
| 4 | A[13:2] | D[3:0[ | --- |
| 9 | A[13:3] | D[7:0] | DP[0] |
| 18 | A[13:4] | D[15:0] | DP[1:0] |
+-----------+---------+---------+---------+
RAMB18E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 32/36 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 32/ 1 | A[13:0] | D[0] | --- |
| 32/ 2 | A[13:1] | D[1:0] | --- |
| 32/ 4 | A[13:2] | D[3:0[ | --- |
| 36/ 9 | A[13:3] | D[7:0] | DP[0] |
| 36/ 18 | A[13:4] | D[15:0] | DP[1:0] |
| 36/ 36 | A[13:5] | D[31:0] | DP[3:0] |
+------------+---------+---------+---------+
RAMB36E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[14:0] | D[0] | --- |
| 2 | A[14:1] | D[1:0] | --- |
| 4 | A[14:2] | D[3:0[ | --- |
| 9 | A[14:3] | D[7:0] | DP[0] |
| 18 | A[14:4] | D[15:0] | DP[1:0] |
| 36 | A[14:5] | D[31:0] | DP[3:0] |
|1(Cascade) | A[15:0] | D[0] | --- |
+-----------+---------+---------+---------+
RAMB36E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 64/72 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 64/ 1 | A[14:0] | D[0] | --- |
| 64/ 2 | A[14:1] | D[1:0] | --- |
| 64/ 4 | A[14:2] | D[3:0[ | --- |
| 64/ 9 | A[14:3] | D[7:0] | DP[0] |
| 64/ 18 | A[14:4] | D[15:0] | DP[1:0] |
| 64/ 36 | A[14:5] | D[31:0] | DP[3:0] |
| 64/ 72 | A[14:6] | D[63:0] | DP[7:0] |
+------------+---------+---------+---------+
*/
module ram18p_var_w_var_r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter integer LOG2WIDTH_RD = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter DUMMY = 0
`ifdef PRELOAD_BRAMS
,
`include "includes/ram18_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
generate
if (DUMMY)
ram18p_dummy #(
.LOG2WIDTH_RD(LOG2WIDTH_RD)
) ram18p_dummy_i (
.data_out(data_out)
);
else if ((LOG2WIDTH_WR == 5) && (LOG2WIDTH_RD == 5))
ram18p_32w_32r #(
.REGISTERS (REGISTERS)
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[35:0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[35:0]
);
else if ((LOG2WIDTH_WR == 5) && (LOG2WIDTH_RD < 5))
ram18p_32w_lt32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<35):0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[35:0]
);
else if ((LOG2WIDTH_WR < 5) && (LOG2WIDTH_RD == 5))
ram18p_lt32w_32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR)
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[35:0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[3:0]
.data_in (data_in) // input[(<35):0]
);
else if ((LOG2WIDTH_WR < 5) && (LOG2WIDTH_RD < 5))
ram18p_lt32w_lt32r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<35):0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[(<35):0]
);
endgenerate
endmodule
// Both ports with 32 bit widths
module ram18p_32w_32r
#(
parameter integer REGISTERS = 0 // 1 - registered output
`ifdef PRELOAD_BRAMS
,
`include "includes/ram18_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
input [8:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [35:0] data_out, // data out
input wclk, // clock for read port
input [ 8:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [35:0] data_in // data out
);
localparam PWIDTH_WR=36;
localparam PWIDTH_RD=36;
RAMB18E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES") // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[15:0]), // Port A data/LSB data[15:0], output
.DOPADOP (data_out[17:16]),// Port A parity/LSB parity[2:0], output
.DIADI (data_in[15:0]), // Port A data/LSB data[15:0], input
.DIPADIP (data_in[17:16]), // Port A parity/LSB parity[2:0], input
.ADDRARDADDR ({raddr[8:0],5'b11111}), // Port A (read port in SDP) address [13:0], unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (2'b0), // Port A (read port in SDP) Write Enable[2:0], input
// Port B
.DOBDO (data_out[33:18]),// Port B data/MSB data[15:0], output
.DOPBDOP (data_out[35:34]),// Port B parity/MSB parity[2:0], output
.DIBDI (data_in[33:18]), // Port B data/MSB data[31:0], input
.DIPBDIP (data_in[35:34]), // Port B parity/MSB parity[1:0], input
.ADDRBWRADDR ({waddr[8:0],5'b11111}), // Port B (write port in SDP) address [13:0], unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
// Both ports with less than 32 bit widths
module ram18p_lt32w_lt32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 4, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram18_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
localparam WIDTH_WRP = 1 << (LOG2WIDTH_WR-3);
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
localparam WIDTH_RDP = 1 << (LOG2WIDTH_RD-3);
wire [15:0] data_out16;
wire [ 1:0] datap_out2;
assign data_out={datap_out2[WIDTH_RDP-1:0], data_out16[WIDTH_RD-1:0]};
wire [WIDTH_WR+15:0] data_in_ext = {16'b0,data_in[WIDTH_WR-1:0]};
wire [15:0] data_in16=data_in_ext[15:0];
wire [WIDTH_WRP+1:0] datap_in_ext = {2'b0,data_in[WIDTH_WR+:WIDTH_WRP]};
wire [1:0] datap_in2= datap_in_ext[1:0];
RAMB18E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.RAM_MODE ("TDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES") // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out16), // Port A data/LSB data[15:0], output
.DOPADOP (datap_out2), // Port A parity/LSB parity[1:0], output
.DIADI (16'h0), // Port A data/LSB data[15:0], input
.DIPADIP (2'h0), // Port A parity/LSB parity[1:0], input
.ADDRARDADDR ({raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [13:0], unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (2'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in16), // Port B data/MSB data[31:0], input
.DIPBDIP (datap_in2), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({waddr,{LOG2WIDTH_WR{1'b1}}}), // Port B (write port in SDP) address [13:0], unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[3:0]) // Port B (write port in SDP) Write Enable[3:0], input
);
endmodule
// Write port less than 32bits, read port 32 bit widths
module ram18p_lt32w_32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 4 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram18_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
input [8:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [35:0] data_out, // data out
input wclk, // clock for read port
input [13-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [(9 << (LOG2WIDTH_WR-3))-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = 36;
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
localparam WIDTH_WRP = 1 << (LOG2WIDTH_WR-3);
wire [WIDTH_WR+15:0] data_in_ext = {16'b0,data_in[WIDTH_WR-1:0]};
wire [15:0] data_in16=data_in_ext[15:0];
wire [WIDTH_WRP+1:0] datap_in_ext = {2'b0,data_in[WIDTH_WR+:WIDTH_WRP]};
wire [1:0] datap_in2= datap_in_ext[1:0];
RAMB18E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES") // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[15:0]), // Port A data/LSB data[15:0], output
.DOPADOP (data_out[17:16]),// Port A parity/LSB parity[3:0], output
.DIADI (16'h0), // Port A data/LSB data[31:0], input
.DIPADIP (2'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({raddr[8:0],5'b11111}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (2'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out[33:18]),// Port B data/MSB data[31:0], output
.DOPBDOP (data_out[35:34]),// Port B parity/MSB parity[3:0], output
.DIBDI (data_in16), // Port B data/MSB data[31:0], input
.DIPBDIP (datap_in2), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({waddr,{LOG2WIDTH_WR{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[3:0]) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
// Write port 64 bita, read port - less than 64 bits
module ram18p_32w_lt32r
#(
parameter integer REGISTERS = 0, // 1 - registered output
// parameter integer LOG2WIDTH_WR = 4, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram18_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
input [13-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out, // data out
input wclk, // clock for read port
input [8:0] waddr, // write address
input we, // write port enable
input [ 3:0] web, // write byte enable
input [35:0] data_in // data out
);
localparam PWIDTH_WR = 36;
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
localparam WIDTH_RDP = 1 << (LOG2WIDTH_RD-3);
wire [15:0] data_out16;
wire [ 1:0] datap_out2;
assign data_out={datap_out2[WIDTH_RDP-1:0], data_out16[WIDTH_RD-1:0]};
RAMB18E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 18)
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18 and in SDP mode - 36 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES") // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
`ifdef PRELOAD_BRAMS
`include "includes/ram18_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out16), // Port A data/LSB data[15:0], output
.DOPADOP (datap_out2), // Port A parity/LSB parity[1:0], output
.DIADI (data_in[15:0]), // Port A data/LSB data[15:0], input
.DIPADIP (data_in[17:16]), // Port A parity/LSB parity[1:0], input
.ADDRARDADDR ({raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [13:0], unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (2'b0), // Port A (read port in SDP) Write Enable[1:0], input
// Port B
.DOBDO (), // Port B data/MSB data[15:0], output
.DOPBDOP (), // Port B parity/MSB parity[1:0], output
.DIBDI (data_in[33:18]), // Port B data/MSB data[15:0], input
.DIPBDIP (data_in[35:34]), // Port B parity/MSB parity[1:0], input
.ADDRBWRADDR({waddr[8:0],5'b11111}), // Port B (write port in SDP) address [13:0], unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[3:0]) // Port B (write port in SDP) Write Enable[7:0], input
);
endmodule
module ram18p_dummy
#(
parameter integer LOG2WIDTH_RD = 4 // WIDTH= 1 << LOG2WIDTH
)
(
output [(9 << (LOG2WIDTH_RD-3))-1:0] data_out // data out
);
assign data_out=0;
endmodule
/*******************************************************************************
* Copyright (c) 2014 Elphel, Inc.
* Dual port memory wrapper, with variable width write and variable width read
* using "SDP" ot "TDP" modes of RAMB36E1
* ram_var_w_var_r.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.
*
* ram_var_w_var_r.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/>.
*******************************************************************************/
/*
Address/data widths
Connect unused data to 1b0, unused addresses - to 1'b1
RAMB18E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[13:0] | D[0] | --- |
| 2 | A[13:1] | D[1:0] | --- |
| 4 | A[13:2] | D[3:0[ | --- |
| 9 | A[13:3] | D[7:0] | DP[0] |
| 18 | A[13:4] | D[15:0] | DP[1:0] |
+-----------+---------+---------+---------+
RAMB18E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 32/36 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 32/ 1 | A[13:0] | D[0] | --- |
| 32/ 2 | A[13:1] | D[1:0] | --- |
| 32/ 4 | A[13:2] | D[3:0[ | --- |
| 36/ 9 | A[13:3] | D[7:0] | DP[0] |
| 36/ 18 | A[13:4] | D[15:0] | DP[1:0] |
| 36/ 36 | A[13:5] | D[31:0] | DP[3:0] |
+------------+---------+---------+---------+
RAMB36E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[14:0] | D[0] | --- |
| 2 | A[14:1] | D[1:0] | --- |
| 4 | A[14:2] | D[3:0[ | --- |
| 9 | A[14:3] | D[7:0] | DP[0] |
| 18 | A[14:4] | D[15:0] | DP[1:0] |
| 36 | A[14:5] | D[31:0] | DP[3:0] |
|1(Cascade) | A[15:0] | D[0] | --- |
+-----------+---------+---------+---------+
RAMB36E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 64/72 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 64/ 1 | A[14:0] | D[0] | --- |
| 64/ 2 | A[14:1] | D[1:0] | --- |
| 64/ 4 | A[14:2] | D[3:0[ | --- |
| 64/ 9 | A[14:3] | D[7:0] | DP[0] |
| 64/ 18 | A[14:4] | D[15:0] | DP[1:0] |
| 64/ 36 | A[14:5] | D[31:0] | DP[3:0] |
| 64/ 72 | A[14:6] | D[63:0] | DP[7:0] |
+------------+---------+---------+---------+
*/
module ram_var_w_var_r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 6, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 6, // WIDTH= 1 << LOG2WIDTH
parameter DUMMY = 0
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [14-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(1 << LOG2WIDTH_RD)-1:0] data_out, // data out
input wclk, // clock for read port
input [14-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 7:0] web, // write byte enable
input [(1 << LOG2WIDTH_WR)-1:0] data_in // data out
);
generate
if (DUMMY)
ram_dummy #(
.LOG2WIDTH_RD(LOG2WIDTH_RD)
) ramp_dummy_i (
.data_out(data_out)
);
else if ((LOG2WIDTH_WR == 6) && (LOG2WIDTH_RD == 6))
ram_64w_64r #(
.REGISTERS (REGISTERS)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[63:0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[63:0]
);
else if ((LOG2WIDTH_WR == 6) && (LOG2WIDTH_RD < 6))
ram_64w_lt64r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<32):0]
.wclk (wclk), // input
.waddr (waddr), // input[8:0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[63:0]
);
else if ((LOG2WIDTH_WR < 6) && (LOG2WIDTH_RD == 6))
ram_lt64w_64r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[8:0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[63:0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[(<32):0]
);
else if ((LOG2WIDTH_WR < 6) && (LOG2WIDTH_RD < 6))
ram_lt64w_lt64r #(
.REGISTERS (REGISTERS),
.LOG2WIDTH_WR (LOG2WIDTH_WR),
.LOG2WIDTH_RD (LOG2WIDTH_RD)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) ram_i (
.rclk (rclk), // input
.raddr (raddr), // input[(>8):0]
.ren (ren), // input
.regen (regen), // input
.data_out (data_out), // output[(<32):0]
.wclk (wclk), // input
.waddr (waddr), // input[(>8):0]
.we (we), // input
.web (web), // input[7:0]
.data_in (data_in) // input[(<32):0]
);
endgenerate
endmodule
// Both ports with 64 bit widths
module ram_64w_64r
#(
parameter integer REGISTERS = 0 // 1 - registered output
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
input [8:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [63:0] data_out, // data out
input wclk, // clock for read port
input [ 8:0] waddr, // write address
input we, // write port enable
input [ 7:0] web, // write byte enable
input [63:0] data_in // data out
);
localparam PWIDTH_WR=72;
localparam PWIDTH_RD=72;
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[31:0]), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (data_in[31:0]), // Port A data/LSB data[31:0], input
.DIPADIP (4'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,raddr[8:0],6'b111111}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (4'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out[63:32]),// Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in[63:32]), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({1'b1,waddr[8:0],6'b111111}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web), // Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
// Both ports with less than 64 bit widths - TODO: see if it is still possible to use SDP
module ram_lt64w_lt64r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 5, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 5 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [14-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(1 << LOG2WIDTH_RD)-1:0] data_out, // data out
input wclk, // clock for read port
input [14-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 7:0] web, // write byte enable
input [(1 << LOG2WIDTH_WR)-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
wire [31:0] data_out32;
wire [WIDTH_WR+31:0] data_in_ext = {32'b0,data_in};
wire [31:0] data_in32=data_in_ext[31:0];
assign data_out=data_out32[WIDTH_RD-1:0];
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("TDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
// .INIT_A(36'h0), // Output latches initialization data
// .INIT_B(36'h0), // Output latches initialization data
// .SRVAL_A(36'h0), // Output latches initialization data (copied at when RSTRAM/RSTREG activated)
// .SRVAL_B(36'h0) // Output latches initialization data (copied at when RSTRAM/RSTREG activated)
/*
parameter IS_CLKARDCLK_INVERTED = 1'b0;
parameter IS_CLKBWRCLK_INVERTED = 1'b0;
parameter IS_ENARDEN_INVERTED = 1'b0;
parameter IS_ENBWREN_INVERTED = 1'b0;
parameter IS_RSTRAMARSTRAM_INVERTED = 1'b0;
parameter IS_RSTRAMB_INVERTED = 1'b0;
parameter IS_RSTREGARSTREG_INVERTED = 1'b0;
parameter IS_RSTREGB_INVERTED = 1'b0;
*/
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out32), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (32'h0), // Port A data/LSB data[31:0], input
.DIPADIP (4'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (4'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in32), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({1'b1,waddr,{LOG2WIDTH_WR{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[7:0]), // Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
// Write port less than 64bits, read port 64 bit widths
module ram_lt64w_64r
#(
parameter integer REGISTERS = 0, // 1 - registered output
parameter integer LOG2WIDTH_WR = 5 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [8:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [63:0] data_out, // data out
input wclk, // clock for read port
input [14-LOG2WIDTH_WR:0] waddr, // write address
input we, // write port enable
input [ 7:0] web, // write byte enable
input [(1 << LOG2WIDTH_WR)-1:0] data_in // data out
);
localparam PWIDTH_WR = (LOG2WIDTH_WR > 2)? (9 << (LOG2WIDTH_WR - 3)): (1 << LOG2WIDTH_WR);
localparam PWIDTH_RD = 72;
localparam WIDTH_WR = 1 << LOG2WIDTH_WR;
// localparam WIDTH_RD = 64;
wire [WIDTH_WR+31:0] data_in_ext = {32'b0,data_in};
wire [31:0] data_in32=data_in_ext[31:0];
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out[31:0]), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (32'h0), // Port A data/LSB data[31:0], input
.DIPADIP (4'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,raddr[8:0],6'b111111}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (4'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out[63:32]), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in32), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({1'b1,waddr,{LOG2WIDTH_WR{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[7:0]), // Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
// Write port 64 bita, read port - less than 64 bits
module ram_64w_lt64r
#(
parameter integer REGISTERS = 0, // 1 - registered output
// parameter integer LOG2WIDTH_WR = 5, // WIDTH= 1 << LOG2WIDTH
parameter integer LOG2WIDTH_RD = 5 // WIDTH= 1 << LOG2WIDTH
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)
(
input rclk, // clock for read port
// input [ 9:0] raddr, // read address
input [14-LOG2WIDTH_RD:0] raddr, // read address
input ren, // read port enable
input regen, // output register enable
output [(1 << LOG2WIDTH_RD)-1:0] data_out, // data out
input wclk, // clock for read port
input [8:0] waddr, // write address
input we, // write port enable
input [ 7:0] web, // write byte enable
input [63:0] data_in // data out
);
localparam PWIDTH_WR = 72;
localparam PWIDTH_RD = (LOG2WIDTH_RD > 2)? (9 << (LOG2WIDTH_RD - 3)): (1 << LOG2WIDTH_RD);
localparam WIDTH_RD = 1 << LOG2WIDTH_RD;
wire [31:0] data_out32;
assign data_out=data_out32[WIDTH_RD-1:0];
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_RD), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (0), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_WR), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("SDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B ("WRITE_FIRST"), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out32), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (data_in[31:0]), // Port A data/LSB data[31:0], input
.DIPADIP (4'h0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,raddr,{LOG2WIDTH_RD{1'b1}}}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (rclk), // Port A (read port in SDP) clock, input
.ENARDEN (ren), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (4'b0), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in[63:32]), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR({1'b1,waddr[8:0],6'b111111}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (wclk), // Port B (write port in SDP) clock, input
.ENBWREN (we), // Port B (write port in SDP) Enable, input
.REGCEB (1'b0), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE (web[7:0]), // Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
module ram_dummy
#(
parameter integer LOG2WIDTH_RD = 5 // WIDTH= 1 << LOG2WIDTH
)
(
output [(1 << LOG2WIDTH_RD)-1:0] data_out // data out
);
assign data_out=0;
endmodule
/*******************************************************************************
* Module: ramt_var_w_var_r
* Date:2015-05-29
* Author: Andrey Filippov
* Description: Dual port memory wrapper, with variable width write and variable
* width read, using "TDP" mode of RAMB36E1. Same R/W widths in each port.
* Does not use parity bits to increase total data width, width down to 1 are valid.
*
* Copyright (c) 2015 Elphel, Inc.
* ramt_var_w_var_r.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.
*
* ramt_var_w_var_r.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
`include "system_defines.vh"
/*
Address/data widths
Connect unused data to 1b0, unused addresses - to 1'b1
RAMB18E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[13:0] | D[0] | --- |
| 2 | A[13:1] | D[1:0] | --- |
| 4 | A[13:2] | D[3:0[ | --- |
| 9 | A[13:3] | D[7:0] | DP[0] |
| 18 | A[13:4] | D[15:0] | DP[1:0] |
+-----------+---------+---------+---------+
RAMB18E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 32/36 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 32/ 1 | A[13:0] | D[0] | --- |
| 32/ 2 | A[13:1] | D[1:0] | --- |
| 32/ 4 | A[13:2] | D[3:0[ | --- |
| 36/ 9 | A[13:3] | D[7:0] | DP[0] |
| 36/ 18 | A[13:4] | D[15:0] | DP[1:0] |
| 36/ 36 | A[13:5] | D[31:0] | DP[3:0] |
+------------+---------+---------+---------+
RAMB36E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[14:0] | D[0] | --- |
| 2 | A[14:1] | D[1:0] | --- |
| 4 | A[14:2] | D[3:0[ | --- |
| 9 | A[14:3] | D[7:0] | DP[0] |
| 18 | A[14:4] | D[15:0] | DP[1:0] |
| 36 | A[14:5] | D[31:0] | DP[3:0] |
|1(Cascade) | A[15:0] | D[0] | --- |
+-----------+---------+---------+---------+
RAMB36E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 64/72 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 64/ 1 | A[14:0] | D[0] | --- |
| 64/ 2 | A[14:1] | D[1:0] | --- |
| 64/ 4 | A[14:2] | D[3:0[ | --- |
| 64/ 9 | A[14:3] | D[7:0] | DP[0] |
| 64/ 18 | A[14:4] | D[15:0] | DP[1:0] |
| 64/ 36 | A[14:5] | D[31:0] | DP[3:0] |
| 64/ 72 | A[14:6] | D[63:0] | DP[7:0] |
+------------+---------+---------+---------+
*/
module ramt_var_w_var_r
#(
parameter integer REGISTERS_A = 0, // 1 - registered output
parameter integer REGISTERS_B = 0, // 1 - registered output
parameter integer LOG2WIDTH_A = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter integer LOG2WIDTH_B = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter WRITE_MODE_A = "NO_CHANGE", //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
parameter WRITE_MODE_B = "NO_CHANGE" //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)(
input clk_a, // clock for port A
input [14-LOG2WIDTH_A:0] addr_a, // address port A
input en_a, // enable port A (read and write)
input regen_a, // output register enable port A
input we_a, // write port enable port A
output [(1 << LOG2WIDTH_A)-1:0] data_out_a,// data out port A
input [(1 << LOG2WIDTH_A)-1:0] data_in_a, // data in port A
input clk_b, // clock for port BA
input [14-LOG2WIDTH_B:0] addr_b, // address port B
input en_b, // read enable port B
input regen_b, // output register enable port B
input we_b, // write port enable port B
output [(1 << LOG2WIDTH_B)-1:0] data_out_b,// data out port B
input [(1 << LOG2WIDTH_B)-1:0] data_in_b // data in port B
);
localparam PWIDTH_A = (LOG2WIDTH_A > 2)? (9 << (LOG2WIDTH_A - 3)): (1 << LOG2WIDTH_A);
localparam PWIDTH_B = (LOG2WIDTH_B > 2)? (9 << (LOG2WIDTH_B - 3)): (1 << LOG2WIDTH_B);
localparam WIDTH_A = 1 << LOG2WIDTH_A;
localparam WIDTH_B = 1 << LOG2WIDTH_B;
wire [31:0] data_out32_a;
assign data_out_a=data_out32_a[WIDTH_A-1:0];
wire [31:0] data_out32_b;
assign data_out_b=data_out32_b[WIDTH_B-1:0];
wire [WIDTH_A+31:0] data_in_ext_a = {32'b0,data_in_a[WIDTH_A-1:0]};
wire [31:0] data_in32_a = data_in_ext_a[31:0];
wire [WIDTH_B+31:0] data_in_ext_b = {32'b0,data_in_b[WIDTH_B-1:0]};
wire [31:0] data_in32_b = data_in_ext_b[31:0];
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS_A), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS_B), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_A), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (PWIDTH_B), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (PWIDTH_A), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_B), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("TDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A (WRITE_MODE_A), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B (WRITE_MODE_B), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out32_a), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (data_in32_a), // Port A data/LSB data[31:0], input
.DIPADIP (4'b0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,addr_a,{LOG2WIDTH_A{1'b1}}}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (clk_a), // Port A (read port in SDP) clock, input
.ENARDEN (en_a), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen_a), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA ({4{we_a}}), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out32_b), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in32_b), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({1'b1,addr_b,{LOG2WIDTH_B{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (clk_b), // Port B (write port in SDP) clock, input
.ENBWREN (en_b), // Port B (write port in SDP) Enable, input
.REGCEB (regen_b), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE ({4'b0,{4{we_b}}}),// Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
/*******************************************************************************
* Module: ramt_var_wb_var_r
* Date:2015-05-29
* Author: Andrey Filippov
* Description: Dual port memory wrapper, with variable width write (with mask) and variable
* width read, using "TDP" mode of RAMB36E1. Same R/W widths in each port.
* Does not use parity bits to increase total data width, width down to 1 are valid.
*
* Copyright (c) 2015 Elphel, Inc.
* ramt_var_wb_var_r.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.
*
* ramt_var_wb_var_r.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/> .
*
* 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"
* files and/or simulating the code, the copyright holders of this Program give
* 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
* charge, and there is no dependence on any encrypted modules for simulating of
* 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.
*******************************************************************************/
`timescale 1ns/1ps
`include "system_defines.vh"
/*
Address/data widths
Connect unused data to 1b0, unused addresses - to 1'b1
RAMB18E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[13:0] | D[0] | --- |
| 2 | A[13:1] | D[1:0] | --- |
| 4 | A[13:2] | D[3:0[ | --- |
| 9 | A[13:3] | D[7:0] | DP[0] |
| 18 | A[13:4] | D[15:0] | DP[1:0] |
+-----------+---------+---------+---------+
RAMB18E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 32/36 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 32/ 1 | A[13:0] | D[0] | --- |
| 32/ 2 | A[13:1] | D[1:0] | --- |
| 32/ 4 | A[13:2] | D[3:0[ | --- |
| 36/ 9 | A[13:3] | D[7:0] | DP[0] |
| 36/ 18 | A[13:4] | D[15:0] | DP[1:0] |
| 36/ 36 | A[13:5] | D[31:0] | DP[3:0] |
+------------+---------+---------+---------+
RAMB36E1 in True Dual Port (TDP) Mode - each port individually
+-----------+---------+---------+---------+
|Data Width | Address | Data | Parity |
+-----------+---------+---------+---------+
| 1 | A[14:0] | D[0] | --- |
| 2 | A[14:1] | D[1:0] | --- |
| 4 | A[14:2] | D[3:0[ | --- |
| 9 | A[14:3] | D[7:0] | DP[0] |
| 18 | A[14:4] | D[15:0] | DP[1:0] |
| 36 | A[14:5] | D[31:0] | DP[3:0] |
|1(Cascade) | A[15:0] | D[0] | --- |
+-----------+---------+---------+---------+
RAMB36E1 in Simple Dual Port (SDP) Mode
one of the ports (r or w) - 64/72 bits, other - variable
+------------+---------+---------+---------+
|Data Widths | Address | Data | Parity |
+------------+---------+---------+---------+
| 64/ 1 | A[14:0] | D[0] | --- |
| 64/ 2 | A[14:1] | D[1:0] | --- |
| 64/ 4 | A[14:2] | D[3:0[ | --- |
| 64/ 9 | A[14:3] | D[7:0] | DP[0] |
| 64/ 18 | A[14:4] | D[15:0] | DP[1:0] |
| 64/ 36 | A[14:5] | D[31:0] | DP[3:0] |
| 64/ 72 | A[14:6] | D[63:0] | DP[7:0] |
+------------+---------+---------+---------+
*/
module ramt_var_wb_var_r
#(
parameter integer REGISTERS_A = 0, // 1 - registered output
parameter integer REGISTERS_B = 0, // 1 - registered output
parameter integer LOG2WIDTH_A = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter integer LOG2WIDTH_B = 5, // WIDTH= 9 << (LOG2WIDTH - 3)
parameter WRITE_MODE_A = "NO_CHANGE", //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
parameter WRITE_MODE_B = "NO_CHANGE" //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
`ifdef PRELOAD_BRAMS
,
`include "includes/ram36_declare_init.vh"
`endif
)(
input clk_a, // clock for port A
input [14-LOG2WIDTH_A:0] addr_a, // address port A
input en_a, // enable port A (read and write)
input regen_a, // output register enable port A
// input [((LOG2WIDTH_A > 3)? (LOG2WIDTH_A-3):0):0] we_a, // write port enable port A
input [((LOG2WIDTH_A > 3)? ((LOG2WIDTH_A > 4)?3:1):0):0] we_a, // write port enable port A
output [(1 << LOG2WIDTH_A)-1:0] data_out_a,// data out port A
input [(1 << LOG2WIDTH_A)-1:0] data_in_a, // data in port A
input clk_b, // clock for port BA
input [14-LOG2WIDTH_B:0] addr_b, // address port B
input en_b, // read enable port B
input regen_b, // output register enable port B
// input [((LOG2WIDTH_B > 3)? (LOG2WIDTH_B-3):0):0] we_b, // write port enable port B
input [((LOG2WIDTH_B > 3)? ((LOG2WIDTH_B > 4)?3:1):0):0] we_b, // write port enable port B
output [(1 << LOG2WIDTH_B)-1:0] data_out_b,// data out port B
input [(1 << LOG2WIDTH_B)-1:0] data_in_b // data in port B
);
localparam PWIDTH_A = (LOG2WIDTH_A > 2)? (9 << (LOG2WIDTH_A - 3)): (1 << LOG2WIDTH_A);
localparam PWIDTH_B = (LOG2WIDTH_B > 2)? (9 << (LOG2WIDTH_B - 3)): (1 << LOG2WIDTH_B);
localparam WIDTH_A = 1 << LOG2WIDTH_A;
localparam WIDTH_B = 1 << LOG2WIDTH_B;
wire [31:0] data_out32_a;
assign data_out_a=data_out32_a[WIDTH_A-1:0];
wire [31:0] data_out32_b;
assign data_out_b=data_out32_b[WIDTH_B-1:0];
wire [WIDTH_A+31:0] data_in_ext_a = {32'b0,data_in_a[WIDTH_A-1:0]};
wire [31:0] data_in32_a = data_in_ext_a[31:0];
wire [WIDTH_B+31:0] data_in_ext_b = {32'b0,data_in_b[WIDTH_B-1:0]};
wire [31:0] data_in32_b = data_in_ext_b[31:0];
wire [3:0] we_a4= (LOG2WIDTH_A > 3)? ((LOG2WIDTH_A > 4)? we_a : {2{we_a}} ):{4{we_a}};
wire [3:0] we_b4= (LOG2WIDTH_B > 3)? ((LOG2WIDTH_B > 4)? we_b : {2{we_b}} ):{4{we_b}};
RAMB36E1
#(
.RSTREG_PRIORITY_A ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.RSTREG_PRIORITY_B ("RSTREG"), // Valid: "RSTREG" or "REGCE"
.DOA_REG (REGISTERS_A), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.DOB_REG (REGISTERS_B), // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
.RAM_EXTENSION_A ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.RAM_EXTENSION_B ("NONE"), // Cascading, valid: "NONE","UPPER", LOWER"
.READ_WIDTH_A (PWIDTH_A), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.READ_WIDTH_B (PWIDTH_B), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_A (PWIDTH_A), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.WRITE_WIDTH_B (PWIDTH_B), // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
.RAM_MODE ("TDP"), // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
.WRITE_MODE_A (WRITE_MODE_A), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.WRITE_MODE_B (WRITE_MODE_B), // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
.RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
.SIM_COLLISION_CHECK ("ALL"), // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
.INIT_FILE ("NONE"), // "NONE" or filename with initialization data
.SIM_DEVICE ("7SERIES"), // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"
.EN_ECC_READ ("FALSE"), // Valid:"FALSE","TRUE" (ECC decoder circuitry)
.EN_ECC_WRITE ("FALSE") // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
`include "includes/ram36_pass_init.vh"
`endif
) RAMB36E1_i
(
// Port A (Read port in SDP mode):
.DOADO (data_out32_a), // Port A data/LSB data[31:0], output
.DOPADOP (), // Port A parity/LSB parity[3:0], output
.DIADI (data_in32_a), // Port A data/LSB data[31:0], input
.DIPADIP (4'b0), // Port A parity/LSB parity[3:0], input
.ADDRARDADDR ({1'b1,addr_a,{LOG2WIDTH_A{1'b1}}}), // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKARDCLK (clk_a), // Port A (read port in SDP) clock, input
.ENARDEN (en_a), // Port A (read port in SDP) Enable, input
.REGCEAREGCE (regen_a), // Port A (read port in SDP) register enable, input
.RSTRAMARSTRAM (1'b0), // Port A (read port in SDP) set/reset, input
.RSTREGARSTREG (1'b0), // Port A (read port in SDP) register set/reset, input
.WEA (we_a4), // Port A (read port in SDP) Write Enable[3:0], input
// Port B
.DOBDO (data_out32_b), // Port B data/MSB data[31:0], output
.DOPBDOP (), // Port B parity/MSB parity[3:0], output
.DIBDI (data_in32_b), // Port B data/MSB data[31:0], input
.DIPBDIP (4'b0), // Port B parity/MSB parity[3:0], input
.ADDRBWRADDR ({1'b1,addr_b,{LOG2WIDTH_B{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
.CLKBWRCLK (clk_b), // Port B (write port in SDP) clock, input
.ENBWREN (en_b), // Port B (write port in SDP) Enable, input
.REGCEB (regen_b), // Port B (write port in SDP) register enable, input
.RSTRAMB (1'b0), // Port B (write port in SDP) set/reset, input
.RSTREGB (1'b0), // Port B (write port in SDP) register set/reset, input
.WEBWE ({4'b0,we_b4}),// Port B (write port in SDP) Write Enable[7:0], input
// Error correction circuitry
.SBITERR (), // Single bit error status, output
.DBITERR (), // Double bit error status, output
.ECCPARITY (), // Genearted error correction parity [7:0], output
.RDADDRECC (), // ECC read address[8:0], output
.INJECTSBITERR (1'b0), // inject a single-bit error, input
.INJECTDBITERR (1'b0), // inject a double-bit error, input
// Cascade signals to create 64Kx1
.CASCADEOUTA (), // A-port cascade, output
.CASCADEOUTB (), // B-port cascade, output
.CASCADEINA (1'b0), // A-port cascade, input
.CASCADEINB (1'b0) // B-port cascade, input
);
endmodule
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