Basically I want to provide delay of 15 clock cycles for writing and reading through axi4 bus .Is it possible?
Hello,
Slave will then send wready (telling the CPU it is ready to accept more data).
This is not right. It has possibility of deadlock. The wvalid and wready should be independent.
Whereas we are working on the contrary.
No, we consider two cases which wvalid is faster than wready and wready is faster than wvalid.
wready is being masked and wvalid is being sent to the slave.
I'm sorry. You are right.assign WVALID_mask = mask_pre;would be alsoassign WVALID_mask = FIRST_WDATA_MASK | mask_pre;
Best regards,
Yasuhiko Koumoto.
Sir
It does not work .
Regards
Preet
I am very sorry for your inconvenience.
I have debugged and verified the codes on a real simulation environment.
I have observed that they had went very well,
I hope this will help you.
module AXI_W_DELAY15( CLK, ARESETN, AWVALID, // from a master AWREADY, // from a slave WVALID, // from a master WREADY, // from a slave BVALID, // from a slave BREADY, // from a master WLAST, // from a master masked_WVALID, // to a slave masked_WREADY, // to a master masked_AWREADY // to a master ); input CLK; input ARESETN; input AWVALID; input AWREADY; input WVALID; input WREADY; input BVALID; input BREADY; input WLAST; output masked_WVALID; output masked_WREADY; output masked_AWREADY; reg WADDR_DONE; reg FIRST_WDATA_MASK; reg [3:0] wcounter; wire mask_pre; wire WREADY_mask; wire WVALID_mask; always@(posedge CLK) begin if(~ARESETN) WADDR_DONE <= 0; else if(~WADDR_DONE & AWVALID & AWREADY) WADDR_DONE <= 1; else if(BVALID & BREADY) WADDR_DONE <= 0; end always@(posedge CLK) begin if(~ARESETN) FIRST_WDATA_MASK <= 1; else if(WADDR_DONE & (wcounter==4'hf)) FIRST_WDATA_MASK <= 0; else if(wcounter==4'h0) FIRST_WDATA_MASK <= 1; end always@(posedge CLK) begin if(~ARESETN) wcounter <= 4'h0; else if(wcounter!=4'h0) wcounter <= wcounter -1 ; else if(WADDR_DONE & WVALID & WREADY & ~(WLAST & masked_WREADY)) //!! wcounter <= 4'hf; end assign mask_pre = (wcounter != 4'h0); assign WREADY_mask = FIRST_WDATA_MASK | mask_pre; assign WVALID_mask = FIRST_WDATA_MASK | mask_pre; assign masked_WVALID = WVALID & ~WVALID_mask; // WVALID for master assign masked_WREADY = WREADY & ~WREADY_mask; // WREADY for slave assign masked_AWREADY = ~WADDR_DONE & AWREADY; // this make outstanding 1 endmodule module AXI_R_DELAY15( CLK, ARESETN, ARVALID, // from a master ARREADY, // from a slave RVALID, // from a slave RREADY, // from a master RLAST, // from a master masked_RVALID, // to a master masked_RREADY, // to a slave masked_ARVALID,// to a slave masked_ARREADY // to a master ); input CLK; input ARESETN; input ARVALID; input ARREADY; input RVALID; input RREADY; input RLAST; output masked_RVALID; output masked_RREADY; output masked_ARVALID; output masked_ARREADY; reg RADDR_DONE; reg FIRST_RDATA_MASK; reg [3:0] rcounter; reg next_rlast; reg next2_rlast; reg RVALID_delay; reg done_raddr; wire rmask_pre; wire RREADY_mask; wire RVALID_mask; always@(posedge CLK) begin if(~ARESETN) begin next_rlast <= 0; next2_rlast <= 0; done_raddr <= 0; end else begin next_rlast <= (rcounter == 4'h1); next2_rlast <= next_rlast; done_raddr <= RLAST & masked_RREADY; end end always@(posedge CLK) begin if(~ARESETN) RADDR_DONE <= 0; else if(~RADDR_DONE & ARVALID & masked_ARREADY) RADDR_DONE <= 1; else if(done_raddr & (next2_rlast & ~(RVALID & ARVALID & ARREADY))) //!!! RADDR_DONE <= 0; end always@(posedge CLK) begin if(~ARESETN) FIRST_RDATA_MASK <= 0; else if(ARVALID & masked_ARREADY) FIRST_RDATA_MASK <= 1; else if(rcounter==4'hf) FIRST_RDATA_MASK <= 0; end always@(posedge CLK) begin if(~ARESETN) rcounter <= 4'h0; else if(rcounter!=4'h0) rcounter <= rcounter -1 ; else if(RADDR_DONE & RVALID & RREADY & ~next_rlast) //!! rcounter <= 4'hf; end assign rmask_pre = (rcounter != 4'h0); assign RREADY_mask = FIRST_RDATA_MASK | rmask_pre | next2_rlast; assign RVALID_mask = FIRST_RDATA_MASK | rmask_pre | next2_rlast; assign masked_RVALID = RVALID & ~RVALID_mask; // WVALID for master assign masked_RREADY = RREADY & ~RREADY_mask; // WREADY for slave assign masked_ARREADY = ~RADDR_DONE & ARREADY; // this make outstanding 1 assign masked_ARVALID = ~RADDR_DONE & ARVALID; // this make outstanding 1 endmodule
The write does not seem to work for me. Which environment have you used? I have not tried read yet.
Preet Kaur Walia
the environment is CPU and Flash or L2 cache path of a certain actual SoC.
Why do you think the write does not work?
Can you show me the write channel behavior of your environment?
Do you have any timing diagram of the write transaction?
Doesn't it issue the write interleaving?
The write logic is not more difficult than the read.
The main bad point of my previous logic was the priority of set/reset for the wcounter.
I will attche the timing charts of 4 burst and 1 burst cases.Could you let me know if there are anything strange?
(1) 4 Burst
(2) 1 Burst
Best regards,Yasuhiko Koumoto.
I have reconsidered the situation.I guess that your master and slave would follow the rule of"an AXI interface that is receiving information can wait until it detects a VALID signal before it asserts its corresponding READY signal".Therefore, READY is not independent with VALID.In this case, my logics would fail.To solve this, we must use a latches instead of Flip-Flops to prevent the first WREADY.Regarding the read side, there are no modification.I revised my codes.Could you try them?
module AXI_W_DELAY15( CLK, ARESETN, AWVALID, // from a master AWREADY, // from a slave WVALID, // from a master WREADY, // from a slave BVALID, // from a slave BREADY, // from a master WLAST, // from a master masked_WVALID, // to a slave masked_WREADY, // to a master masked_AWREADY // to a master ); input CLK; input ARESETN; input AWVALID; input AWREADY; input WVALID; input WREADY; input BVALID; input BREADY; input WLAST; output masked_WVALID; output masked_WREADY; output masked_AWREADY; reg WADDR_DONE; reg FIRST_WDATA_MASK; reg [3:0] wcounter; wire mask_pre; wire WREADY_mask; wire WVALID_mask; reg WREADY_latch; reg WREADY_latch2; wire WREADY_latch_rst = WREADY | ~ARESETN; wire WREADY_latch_set = WADDR_DONE & WVALID; always@(posedge WREADY_latch_set or posedge WREADY_latch_rst) begin if(WREADY_latch_rst) WREADY_latch <= 0; else if(WREADY_latch_set) WREADY_latch <= 1; end wire WREADY_latch2_rst = mask_pre | ~ARESETN; wire WREADY_latch2_set = WREADY; always@(posedge WREADY_latch2_set or posedge WREADY_latch2_rst) begin if(WREADY_latch2_rst) WREADY_latch2 <= 0; else if(WREADY_latch2_set) WREADY_latch2 <= 1; end always@(posedge CLK) begin if(~ARESETN) WADDR_DONE <= 0; else if(~WADDR_DONE & AWVALID & AWREADY) WADDR_DONE <= 1; else if(BVALID & BREADY) WADDR_DONE <= 0; end always@(posedge CLK) begin if(~ARESETN) FIRST_WDATA_MASK <= 1; else if(WADDR_DONE & (wcounter==4'hf)) FIRST_WDATA_MASK <= 0; else if(wcounter==4'h0) FIRST_WDATA_MASK <= 1; end always@(posedge CLK) begin if(~ARESETN) wcounter <= 4'h0; else if(wcounter!=4'h0) wcounter <= wcounter -1 ; else if(WADDR_DONE & WVALID & WREADY_latch2 & ~(WLAST & masked_WREADY)) //!! wcounter <= 4'hf; end assign mask_pre = (wcounter != 4'h0); assign WREADY_mask = FIRST_WDATA_MASK | mask_pre; assign WVALID_mask = FIRST_WDATA_MASK | mask_pre; assign masked_WVALID = WREADY_latch | (WVALID & ~WVALID_mask); assign masked_WREADY = WREADY & ~WREADY_mask; assign masked_AWREADY = ~WADDR_DONE & AWREADY; endmodule
I am very sorry.Regarding the read, the same consideration as the write should be needed.The following is the revised code for the read.
module AXI_R_DELAY15( CLK, ARESETN, ARVALID, // from a master ARREADY, // from a slave RVALID, // from a slave RREADY, // from a master RLAST, // from a master masked_RVALID, // to a master masked_RREADY, // to a slave masked_ARVALID,// to a slave masked_ARREADY // to a master ); input CLK; input ARESETN; input ARVALID; input ARREADY; input RVALID; input RREADY; input RLAST; output masked_RVALID; output masked_RREADY; output masked_ARVALID; output masked_ARREADY; reg RADDR_DONE; reg FIRST_RDATA_MASK; reg [3:0] rcounter; reg next_rlast; reg next2_rlast; reg done_raddr; wire rmask_pre; wire RREADY_mask; wire RVALID_mask; reg RREADY_latch; reg RREADY_latch2; wire RREADY_latch_rst = RREADY | ~ARESETN; wire RREADY_latch_set = RADDR_DONE & RVALID; always@(posedge RREADY_latch_set or posedge RREADY_latch_rst) begin if(RREADY_latch_rst) RREADY_latch <= 0; else if(RREADY_latch_set) RREADY_latch <= 1; end wire RREADY_latch2_rst = rmask_pre | ~ARESETN; wire RREADY_latch2_set = RREADY; always@(posedge RREADY_latch2_set or posedge RREADY_latch2_rst) begin if(RREADY_latch2_rst) RREADY_latch2 <= 0; else if(RREADY_latch2_set) RREADY_latch2 <= 1; end always@(posedge CLK) begin if(~ARESETN) begin next_rlast <= 0; next2_rlast <= 0; done_raddr <= 0; end else begin next_rlast <= (rcounter == 4'h1); next2_rlast <= next_rlast; done_raddr <= RLAST & masked_RREADY; end end always@(posedge CLK) begin if(~ARESETN) RADDR_DONE <= 0; else if(~RADDR_DONE & ARVALID & masked_ARREADY) RADDR_DONE <= 1; else if(done_raddr & (next2_rlast & ~(RVALID & ARVALID & ARREADY))) //!!! RADDR_DONE <= 0; end always@(posedge CLK) begin if(~ARESETN) FIRST_RDATA_MASK <= 0; else if(ARVALID & masked_ARREADY) FIRST_RDATA_MASK <= 1; else if(rcounter==4'hf) FIRST_RDATA_MASK <= 0; end always@(posedge CLK) begin if(~ARESETN) rcounter <= 4'h0; else if(rcounter!=4'h0) rcounter <= rcounter -1 ; else if(RADDR_DONE & RVALID & RREADY_latch2 & ~next_rlast) //!! rcounter <= 4'hf; end assign rmask_pre = (rcounter != 4'h0); assign RREADY_mask = FIRST_RDATA_MASK | rmask_pre | next2_rlast; assign RVALID_mask = FIRST_RDATA_MASK | rmask_pre | next2_rlast; assign masked_RVALID = RREADY_latch | (RVALID & ~RVALID_mask); // RVALID for master assign masked_RREADY = RREADY & ~RREADY_mask; // RREADY for slave assign masked_ARREADY = ~RADDR_DONE & ARREADY; // this make outstanding 1 assign masked_ARVALID = ~RADDR_DONE & ARVALID; // this make outstanding 1 endmodule
I am sorry very much for many time revising.I have revised 2 parts of my codes.One is for the write and another is for the read.
(1) Write
always@(posedge CLK) begin if(~ARESETN) FIRST_WDATA_MASK <= 1; else if(WADDR_DONE & (wcounter==4'hf)) FIRST_WDATA_MASK <= 0; else if((wcounter==4'h0) & WREADY) FIRST_WDATA_MASK <= 1; end
(2) Read
always@(posedge CLK) begin if(~ARESETN) next_rlast <= 0; else if (rcounter == 4'h1) next_rlast <= 1; else if ((rcounter == 4'h0) & masked_RREADY) next_rlast <= 0; end
I will do it today and let you know. Can we talk on hangout?It will be a lot easier.
Let me explain you the code behaviour I am following:
My memory controller block is using the axi bridges to communicate with the MCB
CPU-AXI bridges(here are my channels)-MCB
Now I am not using any simulator. Rather I am using the xilinx SDK and EDK(EMBEDDED development kit). I change the hardware in EDK and then run the memory writing code in SDK and check if the data I write is being written to memory with delay or not. Note I havenot generated testbench for the my write channel or read channel as there are a lot of signals involved.
Following is my write channel code :
//
// File name: axi_mcb_w_channel.v
// Description:
///////////////////////////////////////////////////////////////////////////////
`timescale 1ps/1ps
`default_nettype none
module axi_mcb_w_channel #
(
// Parameter Definitions
// Width of AXI xDATA and MCB xx_data
// Range: 32, 64, 128.
parameter integer C_DATA_WIDTH = 32,
// Width of beat counter, limits max transaction size.
// Range: 1-6 (-> 2-64 beat transactions)
parameter integer C_CNT_WIDTH = 4,
// Pipelines the wr_full signal from mcb by using
// wr_count. Does not add write latency.
parameter integer C_PL_WR_FULL = 1,
// Pipelines the wvalid and wready handshake used for
// counting. May add one cycle of latency.
parameter integer C_PL_WHANDSHAKE = 1,
// Pipelines the intermodule signal w_complete. May add
// 1 cycle of latency.
parameter integer C_PL_W_COMPLETE = 1
)
// Port Declarations
input wire clk ,
input wire reset ,
input wire [C_DATA_WIDTH-1:0] wdata,
input wire [C_DATA_WIDTH/8-1:0] wstrb,
input wire wlast,
input wire wvalid,
output wire wready,
output wire wr_en,
output wire [C_DATA_WIDTH/8-1:0] wr_mask,
output wire [C_DATA_WIDTH-1:0] wr_data,
input wire wr_full,
input wire wr_empty,
input wire [6:0] wr_count,
input wire wr_underrun,
input wire wr_error,
input wire calib_done,
output wire w_complete,
input wire w_trans_cnt_full
);
////////////////////////////////////////////////////////////////////////////////
// Local parameters
localparam integer P_MCB_FULL_CNT = 64;
// Wire and register declarations
wire whandshake;
reg [C_CNT_WIDTH-1:0] cnt;
reg subburst_last;
wire w_complete_ns;
wire w_complete_i;
wire wready_i;
wire wlast_i;
wire whandshake_i;
// BEGIN RTL
assign wready = wready_i;
assign wr_en = whandshake;
assign wr_mask = ~wstrb;
assign wr_data = wdata;
assign whandshake = wvalid & wready;
generate
if (C_PL_WR_FULL) begin : PL_WR_FULL
reg [6:0] wr_count_d1;
wire wr_afull_ns;
reg wready_r;
// Calculate almost full from wr_count instead of using wr_full for timing
// closure
always @(posedge clk) begin
wr_count_d1 <= wr_count;
end
assign wr_afull_ns = (wr_count_d1 > (P_MCB_FULL_CNT-3));
if (reset) begin
wready_r <= 1'b0;
end else begin
wready_r <= ~wr_afull_ns & calib_done & ~w_trans_cnt_full;
assign wready_i = wready_r;
else
begin : NO_PL_WR_FULL
assign wready_i = ~wr_full & calib_done & ~w_trans_cnt_full;
endgenerate
if (C_PL_WHANDSHAKE) begin : PL_WHANDSHAKE
reg wlast_d1;
reg whandshake_d1;
// Count the number of beats we have
// Use delayed values of the incoming signals for better timing
wlast_d1 <= wlast;
whandshake_d1 <= whandshake;
assign wlast_i = wlast_d1;
assign whandshake_i = whandshake_d1;
else begin : NO_PL_WHANDSHAKE
assign wlast_i = wlast;
assign whandshake_i = whandshake;
if (w_complete_ns | reset) begin
cnt <= {C_CNT_WIDTH{1'b1}};
end else if (whandshake_i) begin
cnt <= cnt - 1'b1;
// Determines have reached a subburst boundary
if (reset | w_complete_ns) begin
subburst_last <= 1'b0;
end else if ((cnt == {{C_CNT_WIDTH-1{1'b0}},1'b1}) & whandshake_i) begin
subburst_last <= 1'b1;
assign w_complete_ns = whandshake_i & (wlast_i | subburst_last);
if (C_PL_W_COMPLETE) begin : PL_W_COMPLETE
reg w_complete_r;
// latch the output of w_complete
w_complete_r <= w_complete_ns;
assign w_complete_i = w_complete_r;
else begin : NO_PL_W_COMPLETE
assign w_complete_i = w_complete_ns;
assign w_complete = w_complete_i;
endmodule
`default_nettype wire
I want not to talk on hangout, because I will not support until you will succeed.I can only give you hints.I did my best by proposing an example which can work well in a certain environmentNow, I would like to finish the conversation.
By the way, if you have the AXI bridge, how about adding the following logics into the bridge?As the wready can be generated independently with wvalid, any latches will not be needed.
assign wtimer_trigger = wvalid & wready_i;assign wready = (wtimer == 5'h1) & wready_i;
always @(posedge clk) beginif(reset) wtimer <= 5'h0;else if(wtime != 5'h1) wtimer <= wrimer - 1;else if(wtimer_trigger & (wtimer == 5'h0)) wtimer <= 5'h10;else if(wready) wtimer <= 5'h0;end
Thank you so much for all the suggestions you have provided me.. You have really brought me this far. I have tried the write (with latches ) it does not seem to work. Some last doubts to end the conversation. Please let me if your write channel is similar to mine and the test bench you have used to test it. I have tried the bridge suggestion as well. But that does not delay my data.
I cannot judge whether your axi_mcb_w_channel logic would be correct or not.It seems to have a lot of strange parts for me.Honestry speaking, I wonder why my proposal for the bridge did not work.
I have tried the bridge suggestion as well. But that does not delay my data.
Is your data modification done between the bridge and the slave?My assumption is that it would be done between CPU and the bridge.
Yes sir I have made the modifications between bridge and the slave as I do not have access to the CPU part of the code. You can have a look at the attachment(axi_mcb_w_channel.v) to see where I have made the changes. Also I have attached axi bridge(axi_mcb.v). Sir, can you please tell me which particular simulator have you used.
I am working on the latch code sent by you.
I am afraid that you would insert the delay logic into the axi_mcb_{aw,w,b}_channel_0. It would be to very complex and difficult.
I recommend to put my logic on between the register slice and the axi_mcb_{aw,w,b}_channel_0.