Commit 38eedfcf authored by Andrey Filippov's avatar Andrey Filippov

Added simulation model for SAXI GP (write channels only)

parent 1de3d68f
/*******************************************************************************
* Module: simul_saxi_gp_wr
* Date:2015-08-04
* Author: Andrey Filippov
* Description: Simplified model of AXI_GP write channel
*
* Copyright (c) 2015 Elphel, Inc.
* simul_saxi_gp_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_saxi_gp_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/> .
*******************************************************************************/
`timescale 1ns/1ps
module simul_saxi_gp_wr(
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 [31:0] wdata,
input wvalid,
output wready,
input [ 5:0] wid,
input wlast,
input [ 3:0] wstrb,
// write response
output bvalid,
input bready,
output [ 5:0] bid,
output [ 1:0] bresp,
// 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 [31:0] sim_wr_data,
output [ 3:0] sim_wr_stb,
output [ 1:0] sim_wr_size,
input [ 3:0] sim_bresp_latency, // latency in writing data outside of the module
output [ 3:0] sim_wr_qos
);
localparam AW_FIFO_DEPTH = 3; // FIFO number of address bits to fit AW_FIFO_NUM (number is one bit wider)
localparam W_FIFO_DEPTH = 3; // FIFO number of address bits to fit W_FIFO_NUM
localparam [AW_FIFO_DEPTH:0] AW_FIFO_NUM = 8; // Maximal number of words in AW FIFO 8-words
localparam [W_FIFO_DEPTH:0] W_FIFO_NUM = 8; // Maximal number of words in AW 8-words
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
*/
wire aw_nempty;
wire w_nempty;
reg [11:0] next_wr_address_w; // bits that are incremented in 32-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] awid_out; // verify it matches wid_out when outputting data
wire [1:0] awburst_out;
wire [1:0] awsize_out;
wire [3:0] awlen_out;
wire [31:0] awaddr_out;
wire [5:0] wid_out;
wire wlast_out;
wire [3:0] wstrb_out;
wire [31: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)
reg [ 1:0] wsize;
wire 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;
wire [AW_FIFO_DEPTH:0] wacount;
wire [W_FIFO_DEPTH:0] wcount;
// 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 aresetn= ~rst; // probably not needed at all - docs say "do not use"
// generate ready signals for address and data
// assign wready= !wcount[7] && (!(&wcount[6:0]) || !fifo_data_we_d);
assign wready = (wcount < W_FIFO_NUM) && ((wcount < (W_FIFO_NUM-1)) || !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);
assign awready = (wacount < AW_FIFO_NUM) && ((wacount < (AW_FIFO_NUM-1)) || !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 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 && w_nempty &&
(! write_in_progress || last_confirmed_write);
assign write_in_progress_w=
(aw_nempty && w_nempty) || (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
always @* begin
case (wburst)
2'h0: next_wr_address_w[11:0] <= write_address[11:0];
2'h1: next_wr_address_w[11:0] <= write_address[11:0] + (1 << wsize);
2'h2: case (wsize)
2'h3: next_wr_address_w[11:0] <= {(write_address[11:3] + 1) & {5'h1f, ~wlen[3:0]},write_address[2:0]};
2'h2: next_wr_address_w[11:0] <= {(write_address[11:2] + 1) & {6'h3f, ~wlen[3:0]},write_address[1:0]};
2'h1: next_wr_address_w[11:0] <= {(write_address[11:1] + 1) & {7'h7f, ~wlen[3:0]},write_address[0:0]};
2'h0: next_wr_address_w[11:0] <= (write_address[11:0] + 1) & {8'hff, ~wlen[3:0]};
endcase
2'h3: next_wr_address_w[11:0] <= 12'bx;
endcase
end
wire [3:0] sim_wr_mask = (awsize_out == 0)? 4'h1 : ((awsize_out == 1)? 4'h3 : 4'hf);
assign sim_wr_data= wdata_out;
assign sim_wid= wid_out;
assign sim_wr_stb=wstrb_out & sim_wr_mask; // limit by data size
assign sim_wr_size = awsize_out;
always @ (posedge aclk) begin
if (start_write_burst_w) begin
if (awid_out != wid_out) begin
$display ("%m: at time %t ERROR: awid=%h, awid=%h",$time,awid_out,wid_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) wsize[1:0] <= 0;
else if (start_write_burst_w) wsize[1:0] <= awsize_out[1: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_w[11:0]};
end
// localparam AW_FIFO_NUM = 8; // Maximal number of words in AW FIFO 8-words
// localparam W_FIFO_NUM = 8; // Maximal number of words in AW 8-words
fifo_same_clock_fill #( .DATA_WIDTH(50),.DATA_DEPTH(AW_FIFO_DEPTH)) // 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], awqos[3:0]}),
.data_out ({awid_out[5:0], awburst_out[1:0],awsize_out[1:0],awlen_out[3:0],awaddr_out[31:0], sim_wr_qos[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(43),.DATA_DEPTH(W_FIFO_DEPTH))
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[3:0], wdata[31:0]}),
.data_out({wlast_out,wid_out[5:0], wstrb_out[3:0], wdata_out[31: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
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