This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

can we delay read and write transactions(axi4) by providing delay in register slice?

Basically I want to provide delay of 15 clock cycles  for writing and reading through axi4 bus .Is it possible?

Parents
  • Hello Preet Kaur Walia.

    I doubt your suspicion (or maybe experiment result?) "if(WADDR_DONE&WVALID&WREADY)" might not become true because WVALID and WREADY should independent according to "A3.3.1 Dependencies between channel handshake signals" of AXI specs.

    Actually, there would be some wrong scenarios with your implementation of "else if(WADDR_DONE & WREADY)" and the reset value was '0'.

    If First_WDATA_Mask reset value was '0', it cannot handle the following scenario.

    I think almost all case would be the <2> timing.

    And "else if(WADDR_DONE & WREADY)" would not handle the following scenario.

    This would be the same situation with "else if(WADDR_DONE & WVALID)".

    So, I would like to propose the following description.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      FIRST_WDATA_MASK <= 1;    // new change
    else if(AWVALID & masked_AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE & WREADY & WVALID)  // should not change
      FIRST_WDATA_MASK <= 0;  
    end 
    

    How about this?

    Otherwize.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      FIRST_WDATA_MASK <= 1;    // new change
    else if(AWVALID & masked_AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE & (wcount==4'hf))  // new change
      FIRST_WDATA_MASK <= 0;  
    end 
    

    Best regards,

    Yasuhiko Koumoto.

Reply
  • Hello Preet Kaur Walia.

    I doubt your suspicion (or maybe experiment result?) "if(WADDR_DONE&WVALID&WREADY)" might not become true because WVALID and WREADY should independent according to "A3.3.1 Dependencies between channel handshake signals" of AXI specs.

    Actually, there would be some wrong scenarios with your implementation of "else if(WADDR_DONE & WREADY)" and the reset value was '0'.

    If First_WDATA_Mask reset value was '0', it cannot handle the following scenario.

    I think almost all case would be the <2> timing.

    And "else if(WADDR_DONE & WREADY)" would not handle the following scenario.

    This would be the same situation with "else if(WADDR_DONE & WVALID)".

    So, I would like to propose the following description.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      FIRST_WDATA_MASK <= 1;    // new change
    else if(AWVALID & masked_AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE & WREADY & WVALID)  // should not change
      FIRST_WDATA_MASK <= 0;  
    end 
    

    How about this?

    Otherwize.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      FIRST_WDATA_MASK <= 1;    // new change
    else if(AWVALID & masked_AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE & (wcount==4'hf))  // new change
      FIRST_WDATA_MASK <= 0;  
    end 
    

    Best regards,

    Yasuhiko Koumoto.

Children
  • Sir

    None of the solutions seem to work and I am not able to figure out the reason.

    Regards

    Preet Kaur Walia

  • Hello Preet Kaur Walia,

    it's sad news.
    By the way, you said that if the following logic was used, it went well.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      FIRST_WDATA_MASK <= 0;  
    else if(AWVALID & masked_AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE & WREADY)  //change
      FIRST_WDATA_MASK <= 0;  
    end 
    

    If it is correct, I guess that your master would not assert WVALID until getting WREADY from the slave. But it would violate the AXI specs.
    Can you confirm it?
    If you can confirm it, I should compromise the description above.
    To the contrary, if your slave would not assert WREADY until getting WVALID from the master, "else if(WADDR_DONE & WREADY)" would be replaced for "else if(WADDR_DONE & WVALID)".

    By the way, I have found something was wrong.
    "else if(AWVALID&masked_AWREADY)" would be strange (also in the read case).
    I'm sorry but I think masked_AWREADY should be AWREADY.

    I am afraind WADDR_DONE would not become "1" with the previous description.
    Therefore, the logics would be the following.

    always@(posedge CLK) begin  
    if(~ARESETN)  
      WADDR_DONE <= 0;  
    else if(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(AWVALID&AWREADY)  
      FIRST_WDATA_MASK <= 1;  
    else if(WADDR_DONE&(wcounter==4'hf))  
      FIRST_WDATA_MASK <= 0;  
    end  
    always@(posedge CLK) begin  
    if(~ARESETN)  
      wcounter <= 4'h0;  
    else if(WADDR_DONE&masked_WVALID&masked_WREADY)  
      wcounter <= 4'hf;  
    else if(wcounter!=4'h0)  
      wcoubter <= wcounter -1 ;  
    end  
    assign mask_pre = (wcouner != 4'h0);  
    assign WREADY_mask = FIRST_WDATA_MASK | mask_pre;  // CHANGE!  
    assign WVALID_mask = mask_pre;                    // CHANGE!  
    assign masked_WVALID = WVALID & ~WVALID_mask; // RVALID for master  
    assign masked_WREADY = WREADY & ~WREADY_mask;  // RREADY for slave  
    assign masked_AWREADY = ~WADDR_DONE & AWREADY; // this make outstanding 1 
    

    How about them?
    I'm sorry for you inconvenience.

    Best regards,

    Yasuhiko Koumoto.

  • Sir

    The condition

    always@(posedge CLK) begin   

         if(~ARESETN)   

               FIRST_WDATA_MASK <= 1;    // new change 

         else if(AWVALID & masked_AWREADY)   

                FIRST_WDATA_MASK <= 1;   

         else if(WADDR_DONE & WREADY) 

               FIRST_WDATA_MASK <= 0;   

    end  

    should work fine considering that wvalid and wready need not be high together. Therefore, it might be possible that wvalid has gone high for a clock cycle and aftersometime wready goes high. Data mask should go low after that. Therefore it would not deviate from the AXI specification.

     

  • Hello,

    if the releasing the FIRST_WDATA_MASK only by WREADY made your system working fine, it's a good news.
    I think the characteristic of  "wvalid has gone high for a clock cycle and aftersometime wready goes high" would be strange because the assertions (i.e. go to High) WVALID and WREADY should be independent.
    If the master makes WVALID high before the  slave makes WREADY high, the FIRST_WDATA_MASK logic cannot stop the data cycle.
    The logic will only go well if the WVAID of the master will go high after the slave would make WREADY high.
    Anyway, there would be the timing WVALID and WREADY will be High at the same and I wonder why "WADDR_DONE & WVALID & WREADY" would be wrong for de-asserting FIRST_WDATA_MASK.
    The only possibility would be WADDR_DONE was '0' at the timing when "WVALID & WREADY" was '1'. These are the cases <1> and <2> of my previous post.
    I will propose the new condition for releasing FIRST_WDATA_MASK.
    Could you please try it?

    always@(posedge CLK) begin    
         if(~ARESETN)    
               FIRST_WDATA_MASK <= 1;    // new change  
         else if(AWVALID & AWREADY)    
                FIRST_WDATA_MASK <= ~(WVALID & WREADY);    
         else if(WADDR_DONE & WVALID & WREADY)  
               FIRST_WDATA_MASK <= 0;    
    end   
    

    Best regards,
    Yauhiko Koumoto.

  • Sir

    I am working on it. Also I had a query that in the write case ,

    According to me the following scenario should be followed:

    We should  mask wvalid as we need to stop the wvalid from the CPU from going to the slave otherwise, it will do the write transaction as and when wvalid is high.Slave will then send wready (telling the CPU it is ready to accept more data).

    Whereas we are working on the contrary. As it can be seen from the first data mask situation, wready is being masked and wvalid is being sent to the slave. Therefore, there is a possibilty that slave has already written the data to memory before we are providing the delay. (in the first data mask situation we are only masking the wready)

    1. assign WREADY_mask = FIRST_WDATA_MASK | mask_pre;  // CHANGE!   
    2. assign WVALID_mask = mask_pre;          
  • 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 also
    assign WVALID_mask = FIRST_WDATA_MASK | mask_pre;

    Best regards,

    Yasuhiko Koumoto.

  • Sir

    It does not work .

    Regards

    Preet

  • Hello,

    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
    

    Best regards,

    Yasuhiko Koumoto.

  • Sir

    The write does not seem to work for me. Which environment have you used? I have not tried read yet.

    Regards

    Preet Kaur Walia

  • Hello,

    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.

    Best regards,

    Yasuhiko Koumoto.

  • Hello,


    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.

  • Hello,


    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
    

    Best regards,

    Yasuhiko Koumoto.

  • Hello,


    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
    

    Best regards,
    Yasuhiko Koumoto.

  • Hello,


    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
    

    Best regards,
    Yasuhiko Koumoto.

  • Sir

    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));

      always @(posedge clk) begin

        if (reset) begin

          wready_r <= 1'b0;

        end else begin

          wready_r <= ~wr_afull_ns & calib_done & ~w_trans_cnt_full;

        end

      end

      assign wready_i = wready_r;

    end

    else

    begin : NO_PL_WR_FULL

      assign wready_i = ~wr_full & calib_done & ~w_trans_cnt_full;

    end

    endgenerate

    generate

    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

      always @(posedge clk) begin

        wlast_d1  <= wlast;

        whandshake_d1 <= whandshake;

      end

      assign wlast_i = wlast_d1;

      assign whandshake_i = whandshake_d1;

    end

    else begin : NO_PL_WHANDSHAKE

      assign wlast_i = wlast;

      assign whandshake_i = whandshake;

    end

    endgenerate

    always @(posedge clk) begin

      if (w_complete_ns | reset) begin

        cnt <= {C_CNT_WIDTH{1'b1}};

      end else if (whandshake_i) begin

        cnt <= cnt - 1'b1;

      end

    end

    // Determines have reached a subburst boundary

    always @(posedge clk) begin

      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;

      end

    end

    assign w_complete_ns = whandshake_i & (wlast_i | subburst_last);

    generate

    if (C_PL_W_COMPLETE) begin : PL_W_COMPLETE

      reg w_complete_r;

      // latch the output of w_complete

      always @(posedge clk) begin

        w_complete_r <= w_complete_ns;

      end

      assign w_complete_i = w_complete_r;

    end

    else begin : NO_PL_W_COMPLETE

      assign w_complete_i = w_complete_ns;

    end

    endgenerate

       

    assign w_complete = w_complete_i;

    endmodule

    `default_nettype wire

    Regards

    Preet Kaur Walia