//------------------------------------------------------------------------------
// task statements for user-defined testbench
// Please use these tasks to implement test cases
//------------------------------------------------------------------------------
// - nclk()
//    Wait for next clock edge
// - mem_write(addr, size, data)
//    Write data to location 'addr' on DRAM, size in byte (1 to 32)
// - mem_read(addr, size, data)
//    Read data from location 'addr' on DRAM, size in byte (1 to 32)
// - slave_write_MEMORYTYPE_NAME_ID(data, addr)
//    Write data to location 'addr' on DRAM. size equals to data width of I/F
// - slave_read_MEMORYTYPE_NAME_ID(data, addr)
//    Read data from location 'addr' on DRAM. size equals to data width of I/F
//------------------------------------------------------------------------------

`timescale 1ns / 1ps
`include "{{ hdlname }}"
`include "{{ common_hdlname }}"

`define DUMP_VCD
`define MEM_READ_LATENCY 8
`define MEM_WRITE_LATENCY 4

module test_top;
`ifdef DUMP_VCD
  initial begin
    $dumpfile("uut.vcd");
    $dumpvars(0, uut);
  end
`endif
  test uut ();
endmodule

module test;
  parameter SIM_CYCLE = 1000 * 1000 * 1000;
  parameter MEMIMG = "{{ memimg }}";
  parameter SIM_ADDR_WIDTH = {{ simaddrwidth }};

  // Clock Period (Half)
  parameter HPERIOD_CLK_ULOGIC = {{ clock_hperiod_userlogic }};
  parameter HPERIOD_CLK_BUS = {{ clock_hperiod_bus }};
  parameter SINGLE_CLOCK = {% if single_clock %}1{% else %}0{% endif %};

  // Memory Access Latency (in User logic Clock)
  parameter READ_LATENCY = `MEM_READ_LATENCY;
  parameter WRITE_LATENCY = `MEM_WRITE_LATENCY;

  // Bus Type
  parameter BUS_TYPE = "avalon";
  parameter IGNORE_PROTOCOL_ERROR = {% if ignore_protocol_error %}1{% else %}0{% endif %};

{% for param in def_top_parameters %}
  {{ param }}
{%- endfor %}

{% for master in masterlist | sort(attribute='name') %}  
  parameter integer C_AVM_{{ master.name }}_DATA_WIDTH = {{ master.datawidth }};
  parameter integer C_AVM_{{ master.name }}_ADDR_WIDTH = {{ ext_addrwidth }};
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
  parameter integer C_AVS_{{ slave.name }}_DATA_WIDTH = {{ slave.datawidth }};
  parameter integer C_AVS_{{ slave.name }}_ADDR_WIDTH = {{ slave.addrwidth }};
{% endfor %}

  parameter C_AVM_TARGET = 'h00000000;
  
  //------------------------------------------------------------------------------
  // User logic Clock and Reset
  //------------------------------------------------------------------------------
  reg csi_sys_user_clk;
  reg csi_sys_user_reset_n;

  //---------------------------------------------------------------------------
  // User-defined I/O ports in Top-level User logic (wire)
  //---------------------------------------------------------------------------
{%- for ioport in def_top_ioports | sort() %}
  {{ ioport }}
{%- endfor %}

  //---------------------------------------------------------------------------
  // Simulation Clock and Reset
  //---------------------------------------------------------------------------
  wire sim_clk;
  wire sim_resetn;
  assign sim_clk = csi_sys_user_clk;
  assign sim_resetn = csi_sys_user_reset_n;

  //------------------------------------------------------------------------------
  // Avalon interface
  //------------------------------------------------------------------------------
{% for master in masterlist | sort(attribute='name') %}
{%- if not single_clock %}
  // Clock and Reset
  reg csi_sys_{{ master.name }}_clk;
  reg csi_sys_{{ master.name }}_reset_n;
{%- endif %}
  // Common
  wire [C_AVM_{{ master.name }}_ADDR_WIDTH-1:0] avm_{{ master.name }}_address;
  wire avm_{{ master.name }}_waitrequest;
  wire [C_AVM_{{ master.name }}_DATA_WIDTH/8-1:0] avm_{{ master.name }}_byteenable;
  wire [8:0] avm_{{ master.name }}_burstcount;
  // Read
  wire avm_{{ master.name }}_read;
  wire [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] avm_{{ master.name }}_readdata;
  wire avm_{{ master.name }}_readdatavalid;
  // Write
  wire avm_{{ master.name }}_write;
  wire [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] avm_{{ master.name }}_writedata;
{% endfor %}

{% for slave in slavelist | sort(attribute='name') %}
{%- if not single_clock %}
  // Clock and Reset
  reg csi_sys_{{ slave.name }}_clk;
  reg csi_sys_{{ slave.name }}_reset_n;
{%- endif %}
  // Common
  wire [C_AVS_{{ slave.name }}_ADDR_WIDTH-1:0] avs_{{ slave.name }}_address;
  wire avs_{{ slave.name }}_waitrequest;
  wire [C_AVS_{{ slave.name }}_DATA_WIDTH/8-1:0] avs_{{ slave.name }}_byteenable;
  wire [8:0] avs_{{ slave.name }}_burstcount;
  // Read
  wire avs_{{ slave.name }}_read;
  wire [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] avs_{{ slave.name }}_readdata;
  wire avs_{{ slave.name }}_readdatavalid;
  // Write
  wire avs_{{ slave.name }}_write;
  wire [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] avs_{{ slave.name }}_writedata;
{% endfor %}

  {{ ipname }}
  inst_uut
  (
{% for master in masterlist | sort(attribute='name') %}
{%- if not single_clock %}
   .csi_sys_{{ master.name }}_clk(csi_sys_{{ master.name }}_clk),
   .csi_sys_{{ master.name }}_reset_n(csi_sys_{{ master.name }}_reset_n),
{%- endif %}
   .avm_{{ master.name }}_address(avm_{{ master.name }}_address),
   .avm_{{ master.name }}_waitrequest(avm_{{ master.name }}_waitrequest),
   .avm_{{ master.name }}_byteenable(avm_{{ master.name }}_byteenable),
{% if not master.lite %}
   .avm_{{ master.name }}_burstcount(avm_{{ master.name }}_burstcount),
{%- endif %}
   .avm_{{ master.name }}_read(avm_{{ master.name }}_read),
   .avm_{{ master.name }}_readdata(avm_{{ master.name }}_readdata),
   .avm_{{ master.name }}_readdatavalid(avm_{{ master.name }}_readdatavalid),
   .avm_{{ master.name }}_write(avm_{{ master.name }}_write),
   .avm_{{ master.name }}_writedata(avm_{{ master.name }}_writedata),
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
{%- if not single_clock %}
   .csi_sys_{{ slave.name }}_clk(csi_sys_{{ slave.name }}_clk),
   .csi_sys_{{ slave.name }}_reset_n(csi_sys_{{ slave.name }}_reset_n),
{%- endif %}
   .avs_{{ slave.name }}_address(avs_{{ slave.name }}_address >> {{ log2(slave.datawidth/8) }}),
   .avs_{{ slave.name }}_waitrequest(avs_{{ slave.name }}_waitrequest),
   .avs_{{ slave.name }}_byteenable(avs_{{ slave.name }}_byteenable),
{% if not slave.lite %}
   .avs_{{ slave.name }}_burstcount(avs_{{ slave.name }}_burstcount),
{%- endif %}
   .avs_{{ slave.name }}_read(avs_{{ slave.name }}_read),
   .avs_{{ slave.name }}_readdata(avs_{{ slave.name }}_readdata),
   .avs_{{ slave.name }}_readdatavalid(avs_{{ slave.name }}_readdatavalid),
   .avs_{{ slave.name }}_write(avs_{{ slave.name }}_write),
   .avs_{{ slave.name }}_writedata(avs_{{ slave.name }}_writedata),
{% endfor %}

{%- for ioport in name_top_ioports %}
   .coe_{{ ioport }}({{ ioport }}),
{%- endfor %}

   .csi_sys_user_clk(csi_sys_user_clk),
   .csi_sys_user_reset_n(csi_sys_user_reset_n)
   ); 

{% for master in masterlist | sort(attribute='name') %}
{%- if master.lite %}
  assign avm_{{ master.name }}_burstcount = 1;
{%- endif %}
{% endfor %}

  dram_stub #
  (
{% for master in masterlist | sort(attribute='name') %}
   .C_AVM_{{ master.name }}_ADDR_WIDTH(C_AVM_{{ master.name }}_ADDR_WIDTH),
   .C_AVM_{{ master.name }}_DATA_WIDTH(C_AVM_{{ master.name }}_DATA_WIDTH),
{% endfor %}
   .MEMIMG(MEMIMG),
   .SIM_ADDR_WIDTH(SIM_ADDR_WIDTH),
   .READ_LATENCY(READ_LATENCY),
   .WRITE_LATENCY(WRITE_LATENCY),
   .IGNORE_PROTOCOL_ERROR(IGNORE_PROTOCOL_ERROR)
   )
  inst_dram_stub
  (
{% for master in masterlist | sort(attribute='name') %}
{%- if not single_clock %}
   .csi_sys_{{ master.name }}_clk(csi_sys_{{ master.name }}_clk),
   .csi_sys_{{ master.name }}_reset_n(csi_sys_{{ master.name }}_reset_n),
{%- else %}
   .csi_sys_{{ master.name }}_clk(csi_sys_user_clk),
   .csi_sys_{{ master.name }}_reset_n(csi_sys_user_reset_n),
{%- endif %}
   .avm_{{ master.name }}_address(avm_{{ master.name }}_address),
   .avm_{{ master.name }}_waitrequest(avm_{{ master.name }}_waitrequest),
   .avm_{{ master.name }}_byteenable(avm_{{ master.name }}_byteenable),
   .avm_{{ master.name }}_burstcount(avm_{{ master.name }}_burstcount),
   .avm_{{ master.name }}_read(avm_{{ master.name }}_read),
   .avm_{{ master.name }}_readdata(avm_{{ master.name }}_readdata),
   .avm_{{ master.name }}_readdatavalid(avm_{{ master.name }}_readdatavalid),
   .avm_{{ master.name }}_write(avm_{{ master.name }}_write),
   .avm_{{ master.name }}_writedata(avm_{{ master.name }}_writedata),
{% endfor %}

   .csi_sys_user_clk(csi_sys_user_clk),
   .csi_sys_user_reset_n(csi_sys_user_reset_n)
   );

{% for slave in slavelist | sort(attribute='name') %}
  reg {{ slave.name }}_ext_write_enq;
  reg [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] {{ slave.name }}_ext_write_data;
  wire {{ slave.name }}_ext_write_almost_full;
  reg {{ slave.name }}_ext_read_deq;
  wire [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] {{ slave.name }}_ext_read_data;
  wire {{ slave.name }}_ext_read_empty;

  reg [C_AVS_{{ slave.name }}_ADDR_WIDTH-1:0] {{ slave.name }}_ext_addr;
  reg {{ slave.name }}_ext_read_enable;
  reg {{ slave.name }}_ext_write_enable;
  reg [8:0] {{ slave.name }}_ext_word_size;
  wire {{ slave.name }}_ext_done;

  initial begin
    {{ slave.name }}_ext_write_enq = 0;
    {{ slave.name }}_ext_write_data = 0;
    {{ slave.name }}_ext_read_deq = 0;
    {{ slave.name }}_ext_addr = 0;
    {{ slave.name }}_ext_read_enable = 0;
    {{ slave.name }}_ext_write_enable = 0;
    {{ slave.name }}_ext_word_size = 0;
  end
{% endfor %}

{% for slave in slavelist | sort(attribute='name') %}
  avalon_master_fifo #
  (
   .C_AVM_ADDR_WIDTH(C_AVS_{{ slave.name }}_ADDR_WIDTH),
   .C_AVM_DATA_WIDTH(C_AVS_{{ slave.name }}_DATA_WIDTH),
   .C_AVM_TARGET(0)
   )
  inst_avalon_master_fifo_{{ slave.name }}
  (
{%- if not single_clock %}
   .ACLK(csi_sys_{{ slave.name }}_clk), // Avalon clock
   .ARESETN(csi_sys_{{ slave.name }}_reset_n), // Avalon reset
{%- else %}
   .ACLK(csi_sys_user_clk), // Avalon clock
   .ARESETN(csi_sys_user_reset_n), // Avalon reset
{%- endif %}

   .user_write_enq({{ slave.name }}_ext_write_enq),
   .user_write_data({{ slave.name }}_ext_write_data),
   .user_write_almost_full({{ slave.name }}_ext_write_almost_full),
   .user_read_deq({{ slave.name }}_ext_read_deq),
   .user_read_data({{ slave.name }}_ext_read_data),
   .user_read_empty({{ slave.name }}_ext_read_empty),

   .user_addr({{ slave.name }}_ext_addr),
   .user_read_enable({{ slave.name }}_ext_read_enable),
   .user_write_enable({{ slave.name }}_ext_write_enable),
   .user_word_size({{ slave.name }}_ext_word_size),
   .user_done({{ slave.name }}_ext_done),

   .avm_address(avs_{{ slave.name }}_address),
   .avm_waitrequest(avs_{{ slave.name }}_waitrequest),
   .avm_byteenable(avs_{{ slave.name }}_byteenable),
   .avm_burstcount(avs_{{ slave.name }}_burstcount),

   .avm_read(avs_{{ slave.name }}_read),
   .avm_readdata(avs_{{ slave.name }}_readdata),
   .avm_readdatavalid(avs_{{ slave.name }}_readdatavalid),

   .avm_write(avs_{{ slave.name }}_write),
   .avm_writedata(avs_{{ slave.name }}_writedata)
  );
{% endfor %}

  initial begin
    csi_sys_user_clk = 0;
    #HPERIOD_CLK_ULOGIC;
    forever #HPERIOD_CLK_ULOGIC csi_sys_user_clk = ~csi_sys_user_clk;
  end

{%- if not single_clock %}

{% for master in masterlist | sort(attribute='name') %}
  initial begin
    csi_sys_{{ master.name }}_clk = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS csi_sys_{{ master.name }}_clk = ~csi_sys_{{ master.name }}_clk;
  end
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
  initial begin
    csi_sys_{{ slave.name }}_clk = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS csi_sys_{{ slave.name }}_clk = ~csi_sys_{{ slave.name }}_clk;
  end
{% endfor %}

{%- endif %}

  task nclk;
    begin
      wait(~csi_sys_user_clk);
      wait(csi_sys_user_clk);
      #1;
    end
  endtask

  integer cycle_count;
  
  initial begin
    if(SINGLE_CLOCK &&
       (HPERIOD_CLK_ULOGIC != HPERIOD_CLK_BUS)) begin
      $display("ERROR: All clock periods should be same in single clock mode");
      $finish;
    end

    csi_sys_user_reset_n = 1;

{%- if not single_clock %}

{% for master in masterlist | sort(attribute='name') %}
    csi_sys_{{ master.name }}_reset_n = 1;
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
    csi_sys_{{ slave.name }}_reset_n = 1;
{% endfor %}

{%- endif %}
    
    #100;

    csi_sys_user_reset_n = 0;

{%- if not single_clock %}

{% for master in masterlist | sort(attribute='name') %}
    csi_sys_{{ master.name }}_reset_n = 0;
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
    csi_sys_{{ slave.name }}_reset_n = 0;
{% endfor %}

{%- endif %}

    #100;

    csi_sys_user_reset_n = 1;

{%- if not single_clock %}

{% for master in masterlist | sort(attribute='name') %}
    csi_sys_{{ master.name }}_reset_n = 1;
{% endfor %}
{% for slave in slavelist | sort(attribute='name') %}
    csi_sys_{{ slave.name }}_reset_n = 1;
{% endfor %}

{%- endif %}

    #100;

    nclk();

    for(cycle_count=0; cycle_count<SIM_CYCLE; cycle_count=cycle_count+1) begin
      nclk();
    end
    
    $display("[IPgen] time:%d simulation time out. cycle:%d", $stime, cycle_count);
    $finish;
  end

  //----------------------------------------------------------------------------
  // DRAM read/write task
  //----------------------------------------------------------------------------
  task mem_write;
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [5:0] size;
    input [255:0] data;
    integer i;
    begin
      for(i=0; i<size; i=i+1) begin
        inst_dram_stub.memory[addr + i] = (data >> (8 * i)) & 8'hFF;
      end
    end
  endtask

  task mem_read;
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [5:0] size;
    output [255:0] data;
    integer i;
    begin
      data = 256'h0;
      for(i=0; i<size; i=i+1) begin
        data = data | ((inst_dram_stub.memory[addr + i] & 8'hFF) << (i * 8));
      end
    end
  endtask

  //----------------------------------------------------------------------------
  // iochannel/ioregister read/write task
  //----------------------------------------------------------------------------
{% for slave in slavelist | sort(attribute='name') %}
  task slave_write_{{ slave.name }};
    input [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] data;
    input [C_AVS_{{ slave.name }}_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      wait(!{{ slave.name }}_ext_write_almost_full);
      #1;
      {{ slave.name }}_ext_write_enable = 1;
      {{ slave.name }}_ext_addr = addr;
      {{ slave.name }}_ext_word_size = 1;
      {{ slave.name }}_ext_write_enq = 1;
      {{ slave.name }}_ext_write_data = data;
      nclk();
      {{ slave.name }}_ext_write_enq = 0;
      nclk();
      wait({{ slave.name }}_ext_done);
      #1;
      {{ slave.name }}_ext_write_enable = 0;
      nclk();
    end
  endtask

  task slave_read_{{ slave.name }};
    output [C_AVS_{{ slave.name }}_DATA_WIDTH-1:0] data;
    input [C_AVS_{{ slave.name }}_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      {{ slave.name }}_ext_read_enable = 1;
      {{ slave.name }}_ext_addr = addr;
      {{ slave.name }}_ext_word_size = 1;
      nclk();
      nclk();
      wait({{ slave.name }}_ext_done);
      #1;
      {{ slave.name }}_ext_read_enable = 0;
      nclk();
      wait(!{{ slave.name }}_ext_read_empty);
      #1;
      data = {{ slave.name }}_ext_read_data;
      {{ slave.name }}_ext_read_deq = 1;
      nclk();
      {{ slave.name }}_ext_read_deq = 0;
      nclk();
    end
  endtask
{% endfor %}

  //----------------------------------------------------------------------------
  // Setting of User-defined I/O ports
  //----------------------------------------------------------------------------
  // Please add signal or module definitions here for simulation
{% if usertestcode != '' %}
{{ usertestcode }}
{% endif %}
  
endmodule


//------------------------------------------------------------------------------
// DRAM Stub with Avalon Interface
//------------------------------------------------------------------------------
module dram_stub #
  (
{% for master in masterlist | sort(attribute='name') %}   
   parameter integer C_AVM_{{ master.name }}_ADDR_WIDTH            = 32,
   parameter integer C_AVM_{{ master.name }}_DATA_WIDTH            = 32,
{% endfor %}
   parameter MEMIMG = "{{ memimg }}",
   parameter SIM_ADDR_WIDTH = {{ simaddrwidth }},
   parameter READ_LATENCY = 32,
   parameter WRITE_LATENCY = 32,
   parameter IGNORE_PROTOCOL_ERROR = 0
   )
  (
{% for master in masterlist | sort(attribute='name') %}   
   input  wire                               csi_sys_{{ master.name }}_clk,
   input  wire                               csi_sys_{{ master.name }}_reset_n,

   input  wire [C_AVM_{{ master.name }}_ADDR_WIDTH-1:0] avm_{{ master.name }}_address,
   output reg                                avm_{{ master.name }}_waitrequest,
   input  wire [C_AVM_{{ master.name }}_DATA_WIDTH/8-1:0] avm_{{ master.name }}_byteenable,
   input  wire [8:0]                         avm_{{ master.name }}_burstcount,

   input  wire                               avm_{{ master.name }}_read,
   output reg  [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] avm_{{ master.name }}_readdata,
   output reg                                avm_{{ master.name }}_readdatavalid,

   input  wire                               avm_{{ master.name }}_write,
   input  wire [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] avm_{{ master.name }}_writedata,
{% endfor %}

   input csi_sys_user_clk, // User logic (Unused)
   input csi_sys_user_reset_n // User logic (Unused)
   );

  //------------------------------------------------------------------------------
  // Memory Field
  //------------------------------------------------------------------------------
  localparam MEMORY_LEN = (2 ** SIM_ADDR_WIDTH);
  reg [7:0] memory [0:MEMORY_LEN-1];

  integer i;
  integer val;
  integer __fp, __c;

  initial begin
    if(MEMIMG == "None") begin
      val = 0;
      for(i=0; i<MEMORY_LEN; i=i+1) begin
        memory[i] = val >> (8 * (i % 4));
        if((i % 4) == 3) val = val + 1;
      end
    end else begin
{%- if binfile %}
      __fp = $fopen(MEMIMG, "rb");
      __c = $fread(memory, __fp);
{%- else %}
      $readmemh(MEMIMG, memory);
{%- endif %}
      $display("read memory image file %s", MEMIMG);
    end
  end

{% for master in masterlist | sort(attribute='name') %}   
  task mem_write_{{ master.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    input [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] data;
    integer pos;
    begin
      for(pos=0; pos < size; pos=pos+1) begin
        memory[addr+pos] = (data >> (8*pos)) & 'hFF;
      end
    end
  endtask
  
  task mem_read_{{ master.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    output [C_AVM_{{ master.name }}_DATA_WIDTH-1:0] data;
    integer pos;
    begin
      data = 0;
      for(pos=0; pos < size; pos=pos+1) begin
        data = data | memory[addr+pos] << (8*pos);
      end
    end
  endtask
{% endfor %}

  //------------------------------------------------------------------------------
  // Timing Model
  //------------------------------------------------------------------------------
{% for master in masterlist | sort(attribute='name') %}   
  reg {{ master.name }}_write_mode;
  reg {{ master.name }}_read_mode;
  reg [C_AVM_{{ master.name }}_ADDR_WIDTH-1:0] d_avm_{{ master.name }}_address;
  reg [8:0] d_avm_{{ master.name }}_burstcount;
  reg [31:0] {{ master.name }}_stall_count;
  
  reg {{ master.name }}_reset_done;
  initial begin
    {{ master.name }}_reset_done = 0;
    #1;
    wait(!csi_sys_{{ master.name }}_reset_n);
    wait(csi_sys_{{ master.name }}_reset_n);
    #1;
    {{ master.name }}_reset_done = 1;
  end
  
  always @(negedge csi_sys_{{ master.name }}_clk) begin
    if(!csi_sys_{{ master.name }}_reset_n) begin
      {{ master.name }}_write_mode <= 0;
      {{ master.name }}_read_mode <= 0;
      {{ master.name }}_stall_count <= 0;
    end else begin
      avm_{{ master.name }}_waitrequest = 1;
      avm_{{ master.name }}_readdatavalid = 0;
      
      if({{ master.name }}_reset_done) begin
        if( !((avm_{{ master.name }}_write === 1'b0) || (avm_{{ master.name }}_write === 1'b1)) ) begin
          $display("Error: Illegal write operation: avm_{{ master.name }}_write = %b, avm_write should be 1'b1 or 1'b0.", avm_{{ master.name }}_write);
          if(!IGNORE_PROTOCOL_ERROR) $finish;
        end
        if( !((avm_{{ master.name }}_read === 1'b0) || (avm_{{ master.name }}_read === 1'b1)) ) begin
          $display("Error: Illegal read operation: avm_{{ master.name }}_read = %b, avm_read should be 1'b1 or 1'b0.", avm_{{ master.name }}_read);
          if(!IGNORE_PROTOCOL_ERROR) $finish;
        end
      end

      if(!{{ master.name }}_write_mode && avm_{{ master.name }}_write) begin
        {{ master.name }}_stall_count <= {{ master.name }}_stall_count + 1;
        if({{ master.name }}_stall_count == WRITE_LATENCY) begin
          {{ master.name }}_stall_count <= 0;
          avm_{{ master.name }}_waitrequest = 0;
          mem_write_{{ master.name }}(avm_{{ master.name }}_address, C_AVM_{{ master.name }}_DATA_WIDTH/8, avm_{{ master.name }}_writedata);
          d_avm_{{ master.name }}_address = avm_{{ master.name }}_address + (C_AVM_{{ master.name }}_DATA_WIDTH / 8);
          d_avm_{{ master.name }}_burstcount = avm_{{ master.name }}_burstcount - 1;
          if(d_avm_{{ master.name }}_burstcount == 0) begin
            {{ master.name }}_write_mode <= 0;
          end else begin
            {{ master.name }}_write_mode <= 1;
          end
        end
      end

      if(!{{ master.name }}_read_mode && avm_{{ master.name }}_read) begin
        {{ master.name }}_stall_count <= {{ master.name }}_stall_count + 1;
        if({{ master.name }}_stall_count == READ_LATENCY) begin
          {{ master.name }}_read_mode <= 1;
          {{ master.name }}_stall_count <= 0;
          avm_{{ master.name }}_waitrequest = 0;
          d_avm_{{ master.name }}_address = avm_{{ master.name }}_address;
          d_avm_{{ master.name }}_burstcount = avm_{{ master.name }}_burstcount;
        end
      end
      
      if({{ master.name }}_write_mode) begin
        avm_{{ master.name }}_waitrequest = 0;
        if(avm_{{ master.name }}_write) begin
          mem_write_{{ master.name }}(d_avm_{{ master.name }}_address, C_AVM_{{ master.name }}_DATA_WIDTH/8, avm_{{ master.name }}_writedata);
          d_avm_{{ master.name }}_address = d_avm_{{ master.name }}_address + (C_AVM_{{ master.name }}_DATA_WIDTH / 8);
          d_avm_{{ master.name }}_burstcount = d_avm_{{ master.name }}_burstcount - 1;
          if(d_avm_{{ master.name }}_burstcount == 0) begin
            {{ master.name }}_write_mode <= 0;
          end
        end
      end

      if({{ master.name }}_read_mode) begin
        mem_read_{{ master.name }}(d_avm_{{ master.name }}_address, C_AVM_{{ master.name }}_DATA_WIDTH/8, avm_{{ master.name }}_readdata);
        avm_{{ master.name }}_readdatavalid = 1;
        d_avm_{{ master.name }}_address = d_avm_{{ master.name }}_address + (C_AVM_{{ master.name }}_DATA_WIDTH / 8);
        d_avm_{{ master.name }}_burstcount = d_avm_{{ master.name }}_burstcount - 1;
        if(d_avm_{{ master.name }}_burstcount == 0) begin
          {{ master.name }}_read_mode <= 0;
        end
      end

    end
  end
{% endfor %}

endmodule

