
`timescale 1ns / 1ps
`include "{{ 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_CTHREAD = {{ clock_hperiod_controlthread }};
  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 = "axi";

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

{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}  
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH        = {{ ext_addrwidth }};
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH        = {{ memory.ext_datawidth }};
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH   = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH      = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH      = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH       = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH       = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH       = 1;
 
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_SUPPORTS_WRITE    = 1;
  parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_SUPPORTS_READ     = 1;
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}  
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH      = {{ ext_addrwidth }};
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH      = {{ instream.ext_datawidth }};
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH    = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH    = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH     = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH     = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH     = 1;
 
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_SUPPORTS_WRITE  = 1;
  parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_SUPPORTS_READ   = 1;
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}  
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH      = {{ ext_addrwidth }};
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH      = {{ outstream.ext_datawidth }};
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH    = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH    = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH     = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH     = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH     = 1;
 
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_SUPPORTS_WRITE  = 1;
  parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_SUPPORTS_READ   = 1;
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH = {{ iochannel.ext_datawidth }};
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH = {{ ext_addrwidth }}; 
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_WUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_RUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_BUSER_WIDTH = 1;

  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_SUPPORTS_WRITE = 1;
  parameter integer C_{{ thread.name }}_{{ iochannel.name }}_AXI_SUPPORTS_READ = 1;
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH = {{ ioregister.ext_datawidth }};
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH = {{ ext_addrwidth }}; 
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_WUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_RUSER_WIDTH = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_BUSER_WIDTH = 1;

  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_SUPPORTS_WRITE = 1;
  parameter integer C_{{ thread.name }}_{{ ioregister.name }}_AXI_SUPPORTS_READ = 1;
{% endfor %}
{%- endfor %}
  parameter C_M_AXI_TARGET = 'h00000000;
  
  //----------------------------------------------------------------------------
  // Control Thread Clock and Reset
  //----------------------------------------------------------------------------
{%- for thread in threads | sort(attribute='name') %}
  reg {{ thread.name }}_CCLK;
  reg {{ thread.name }}_CRESETN;
{%- endfor %}

  //------------------------------------------------------------------------------
  // User logic Clock and Reset
  //------------------------------------------------------------------------------
  reg UCLK;
  reg URESETN;

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

  //---------------------------------------------------------------------------
  // Finish 
  //---------------------------------------------------------------------------
{%- for thread in threads | sort(attribute='name') %}
  wire {{ thread.name }}_finish;
{%- endfor %}

  //---------------------------------------------------------------------------
  // Simulation Clock and Reset
  //---------------------------------------------------------------------------
  wire sim_clk;
  wire sim_resetn;
  assign sim_clk = UCLK;
  assign sim_resetn = URESETN;

  //------------------------------------------------------------------------------
  // AXI interface
  //------------------------------------------------------------------------------
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
  // Clock and Reset
  reg {{ thread.name }}_{{ memory.name }}_AXI_ACLK;
  reg {{ thread.name }}_{{ memory.name }}_AXI_ARESETN;
  // Master Interface Write Address
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_AWID;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_AWADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWBURST;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_AWLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWQOS;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_AWUSER;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_AWVALID;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_AWREADY;
  
  // Master Interface Write Data
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_WDATA;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_WSTRB;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_WLAST;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_WUSER;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_WVALID;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_WREADY;
  
  // Master Interface Write Response
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_BID;
  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_BRESP;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_BUSER;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_BVALID;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_BREADY;
  
  // Master Interface Read Address
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_ARID;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_ARADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARBURST;
  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARQOS;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_ARUSER;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_ARVALID;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_ARREADY;
  
  // Master Interface Read Data 
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_RID;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_RDATA;
  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_RRESP;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_RLAST;
  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_RUSER;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_RVALID;
  wire                               {{ thread.name }}_{{ memory.name }}_AXI_RREADY;
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for instream in thread.instreams | sort(attribute='name') %}
  // Clock and Reset
  reg {{ thread.name }}_{{ instream.name }}_AXI_ACLK;
  reg {{ thread.name }}_{{ instream.name }}_AXI_ARESETN;
  // Master Interface Write Address
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_AWID;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_AWADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWBURST;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_AWLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWQOS;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_AWUSER;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_AWVALID;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_AWREADY;
  
  // Master Interface Write Data
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_WDATA;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_WSTRB;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_WLAST;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_WUSER;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_WVALID;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_WREADY;
  
  // Master Interface Write Response
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_BID;
  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_BRESP;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_BUSER;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_BVALID;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_BREADY;
  
  // Master Interface Read Address
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_ARID;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_ARADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARBURST;
  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARQOS;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_ARUSER;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_ARVALID;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_ARREADY;
  
  // Master Interface Read Data 
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_RID;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_RDATA;
  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_RRESP;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_RLAST;
  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_RUSER;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_RVALID;
  wire                               {{ thread.name }}_{{ instream.name }}_AXI_RREADY;
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
  // Clock and Reset
  reg {{ thread.name }}_{{ outstream.name }}_AXI_ACLK;
  reg {{ thread.name }}_{{ outstream.name }}_AXI_ARESETN;
  // Master Interface Write Address
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_AWID;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_AWADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWBURST;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWQOS;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_AWUSER;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_AWVALID;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_AWREADY;
  
  // Master Interface Write Data
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_WDATA;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_WSTRB;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_WLAST;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_WUSER;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_WVALID;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_WREADY;
  
  // Master Interface Write Response
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_BID;
  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_BRESP;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_BUSER;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_BVALID;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_BREADY;
  
  // Master Interface Read Address
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_ARID;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_ARADDR;
  wire [8-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARLEN;
  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE;
  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARBURST;
  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK;
  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE;
  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARPROT;
  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARQOS;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_ARUSER;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_ARVALID;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_ARREADY;
  
  // Master Interface Read Data 
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_RID;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_RDATA;
  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_RRESP;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_RLAST;
  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_RUSER;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_RVALID;
  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_RREADY;
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  // Clock and Reset
  reg {{ thread.name }}_{{ iochannel.name }}_AXI_ACLK;
  reg {{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN;

  // Slave Interface Write Address
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWID;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWADDR;
  wire [7:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWLEN;
  wire [2:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWSIZE;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWBURST;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWLOCK;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWCACHE;
  wire [2:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWPROT;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWREGION;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWQOS;
  wire [C_{{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER_WIDTH-1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_AWVALID;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_AWREADY;

  // Slave Interface Write Data
  wire [C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH-1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_WID;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_WDATA;
  wire [((C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH/8) -1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_WSTRB;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_WLAST;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_WUSER_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_WUSER;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_WVALID;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_WREADY;

  // Slave Interface Write Response
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_BID;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_BRESP;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_BUSER_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_BUSER;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_BVALID;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_BREADY;

  // Slave Interface Read Address
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARID;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARADDR;
  wire [7:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARLEN;
  wire [2:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARSIZE;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARBURST;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARLOCK;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARCACHE;
  wire [2:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARPROT;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARREGION;
  wire [3:0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARQOS;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_ARVALID;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_ARREADY;

  // Slave Interface Read Data
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_RID;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_RDATA;
  wire [1:0] {{ thread.name }}_{{ iochannel.name }}_AXI_RRESP;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_RLAST;
  wire [(C_{{ thread.name }}_{{ iochannel.name }}_AXI_RUSER_WIDTH-1):0] {{ thread.name }}_{{ iochannel.name }}_AXI_RUSER;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_RVALID;
  wire {{ thread.name }}_{{ iochannel.name }}_AXI_RREADY;
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  // Clock and Reset
  reg {{ thread.name }}_{{ ioregister.name }}_AXI_ACLK;
  reg {{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN;

  // Slave Interface Write Address
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWID;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWADDR;
  wire [7:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWLEN;
  wire [2:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWSIZE;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWBURST;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWLOCK;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWCACHE;
  wire [2:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWPROT;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWREGION;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWQOS;
  wire [C_{{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER_WIDTH-1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_AWVALID;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_AWREADY;

  // Slave Interface Write Data
  wire [C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH-1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_WID;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_WDATA;
  wire [((C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH/8) -1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_WSTRB;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_WLAST;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_WUSER_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_WUSER;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_WVALID;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_WREADY;

  // Slave Interface Write Response
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_BID;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_BRESP;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_BUSER_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_BUSER;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_BVALID;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_BREADY;

  // Slave Interface Read Address
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARID;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARADDR;
  wire [7:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARLEN;
  wire [2:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARSIZE;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARBURST;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARLOCK;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARCACHE;
  wire [2:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARPROT;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARREGION;
  wire [3:0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARQOS;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_ARVALID;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_ARREADY;

  // Slave Interface Read Data
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_RID;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_RDATA;
  wire [1:0] {{ thread.name }}_{{ ioregister.name }}_AXI_RRESP;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_RLAST;
  wire [(C_{{ thread.name }}_{{ ioregister.name }}_AXI_RUSER_WIDTH-1):0] {{ thread.name }}_{{ ioregister.name }}_AXI_RUSER;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_RVALID;
  wire {{ thread.name }}_{{ ioregister.name }}_AXI_RREADY;
{% endfor %}
{%- endfor %}


  pycoram_{{ userlogic_name.lower() }}
  inst_uut
  (
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
   .{{ thread.name }}_{{ memory.name }}_AXI_ACLK({{ thread.name }}_{{ memory.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARESETN({{ thread.name }}_{{ memory.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ memory.name }}_AXI_AWID({{ thread.name }}_{{ memory.name }}_AXI_AWID),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWADDR({{ thread.name }}_{{ memory.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWLEN({{ thread.name }}_{{ memory.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWSIZE({{ thread.name }}_{{ memory.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWBURST({{ thread.name }}_{{ memory.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWLOCK({{ thread.name }}_{{ memory.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWCACHE({{ thread.name }}_{{ memory.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWPROT({{ thread.name }}_{{ memory.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWQOS({{ thread.name }}_{{ memory.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWUSER({{ thread.name }}_{{ memory.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWVALID({{ thread.name }}_{{ memory.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWREADY({{ thread.name }}_{{ memory.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_WDATA({{ thread.name }}_{{ memory.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ memory.name }}_AXI_WSTRB({{ thread.name }}_{{ memory.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ memory.name }}_AXI_WLAST({{ thread.name }}_{{ memory.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ memory.name }}_AXI_WUSER({{ thread.name }}_{{ memory.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_WVALID({{ thread.name }}_{{ memory.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_WREADY({{ thread.name }}_{{ memory.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_BID({{ thread.name }}_{{ memory.name }}_AXI_BID),
   .{{ thread.name }}_{{ memory.name }}_AXI_BRESP({{ thread.name }}_{{ memory.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ memory.name }}_AXI_BUSER({{ thread.name }}_{{ memory.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_BVALID({{ thread.name }}_{{ memory.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_BREADY({{ thread.name }}_{{ memory.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_ARID({{ thread.name }}_{{ memory.name }}_AXI_ARID),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARADDR({{ thread.name }}_{{ memory.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARLEN({{ thread.name }}_{{ memory.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARSIZE({{ thread.name }}_{{ memory.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARBURST({{ thread.name }}_{{ memory.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARLOCK({{ thread.name }}_{{ memory.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARCACHE({{ thread.name }}_{{ memory.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARPROT({{ thread.name }}_{{ memory.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARQOS({{ thread.name }}_{{ memory.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARUSER({{ thread.name }}_{{ memory.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARVALID({{ thread.name }}_{{ memory.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARREADY({{ thread.name }}_{{ memory.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_RID({{ thread.name }}_{{ memory.name }}_AXI_RID),
   .{{ thread.name }}_{{ memory.name }}_AXI_RDATA({{ thread.name }}_{{ memory.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ memory.name }}_AXI_RRESP({{ thread.name }}_{{ memory.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ memory.name }}_AXI_RLAST({{ thread.name }}_{{ memory.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ memory.name }}_AXI_RUSER({{ thread.name }}_{{ memory.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_RVALID({{ thread.name }}_{{ memory.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_RREADY({{ thread.name }}_{{ memory.name }}_AXI_RREADY),
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
   .{{ thread.name }}_{{ instream.name }}_AXI_ACLK({{ thread.name }}_{{ instream.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARESETN({{ thread.name }}_{{ instream.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ instream.name }}_AXI_AWID({{ thread.name }}_{{ instream.name }}_AXI_AWID),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWADDR({{ thread.name }}_{{ instream.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWLEN({{ thread.name }}_{{ instream.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWSIZE({{ thread.name }}_{{ instream.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWBURST({{ thread.name }}_{{ instream.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWLOCK({{ thread.name }}_{{ instream.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWCACHE({{ thread.name }}_{{ instream.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWPROT({{ thread.name }}_{{ instream.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWQOS({{ thread.name }}_{{ instream.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWUSER({{ thread.name }}_{{ instream.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWVALID({{ thread.name }}_{{ instream.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWREADY({{ thread.name }}_{{ instream.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_WDATA({{ thread.name }}_{{ instream.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ instream.name }}_AXI_WSTRB({{ thread.name }}_{{ instream.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ instream.name }}_AXI_WLAST({{ thread.name }}_{{ instream.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ instream.name }}_AXI_WUSER({{ thread.name }}_{{ instream.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_WVALID({{ thread.name }}_{{ instream.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_WREADY({{ thread.name }}_{{ instream.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_BID({{ thread.name }}_{{ instream.name }}_AXI_BID),
   .{{ thread.name }}_{{ instream.name }}_AXI_BRESP({{ thread.name }}_{{ instream.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ instream.name }}_AXI_BUSER({{ thread.name }}_{{ instream.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_BVALID({{ thread.name }}_{{ instream.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_BREADY({{ thread.name }}_{{ instream.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_ARID({{ thread.name }}_{{ instream.name }}_AXI_ARID),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARADDR({{ thread.name }}_{{ instream.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARLEN({{ thread.name }}_{{ instream.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARSIZE({{ thread.name }}_{{ instream.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARBURST({{ thread.name }}_{{ instream.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARLOCK({{ thread.name }}_{{ instream.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARCACHE({{ thread.name }}_{{ instream.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARPROT({{ thread.name }}_{{ instream.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARQOS({{ thread.name }}_{{ instream.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARUSER({{ thread.name }}_{{ instream.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARVALID({{ thread.name }}_{{ instream.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARREADY({{ thread.name }}_{{ instream.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_RID({{ thread.name }}_{{ instream.name }}_AXI_RID),
   .{{ thread.name }}_{{ instream.name }}_AXI_RDATA({{ thread.name }}_{{ instream.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ instream.name }}_AXI_RRESP({{ thread.name }}_{{ instream.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ instream.name }}_AXI_RLAST({{ thread.name }}_{{ instream.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ instream.name }}_AXI_RUSER({{ thread.name }}_{{ instream.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_RVALID({{ thread.name }}_{{ instream.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_RREADY({{ thread.name }}_{{ instream.name }}_AXI_RREADY),
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
   .{{ thread.name }}_{{ outstream.name }}_AXI_ACLK({{ thread.name }}_{{ outstream.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARESETN({{ thread.name }}_{{ outstream.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ outstream.name }}_AXI_AWID({{ thread.name }}_{{ outstream.name }}_AXI_AWID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR({{ thread.name }}_{{ outstream.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN({{ thread.name }}_{{ outstream.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE({{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWBURST({{ thread.name }}_{{ outstream.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK({{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE({{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWPROT({{ thread.name }}_{{ outstream.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWQOS({{ thread.name }}_{{ outstream.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER({{ thread.name }}_{{ outstream.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWVALID({{ thread.name }}_{{ outstream.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWREADY({{ thread.name }}_{{ outstream.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_WDATA({{ thread.name }}_{{ outstream.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WSTRB({{ thread.name }}_{{ outstream.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WLAST({{ thread.name }}_{{ outstream.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WUSER({{ thread.name }}_{{ outstream.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WVALID({{ thread.name }}_{{ outstream.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WREADY({{ thread.name }}_{{ outstream.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_BID({{ thread.name }}_{{ outstream.name }}_AXI_BID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BRESP({{ thread.name }}_{{ outstream.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BUSER({{ thread.name }}_{{ outstream.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BVALID({{ thread.name }}_{{ outstream.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BREADY({{ thread.name }}_{{ outstream.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARID({{ thread.name }}_{{ outstream.name }}_AXI_ARID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR({{ thread.name }}_{{ outstream.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN({{ thread.name }}_{{ outstream.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE({{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARBURST({{ thread.name }}_{{ outstream.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK({{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE({{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARPROT({{ thread.name }}_{{ outstream.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARQOS({{ thread.name }}_{{ outstream.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER({{ thread.name }}_{{ outstream.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARVALID({{ thread.name }}_{{ outstream.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARREADY({{ thread.name }}_{{ outstream.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_RID({{ thread.name }}_{{ outstream.name }}_AXI_RID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RDATA({{ thread.name }}_{{ outstream.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RRESP({{ thread.name }}_{{ outstream.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RLAST({{ thread.name }}_{{ outstream.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RUSER({{ thread.name }}_{{ outstream.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RVALID({{ thread.name }}_{{ outstream.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RREADY({{ thread.name }}_{{ outstream.name }}_AXI_RREADY),
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ACLK({{ thread.name }}_{{ iochannel.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN({{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN),

{% if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWID({{ thread.name }}_{{ iochannel.name }}_AXI_AWID),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWADDR({{ thread.name }}_{{ iochannel.name }}_AXI_AWADDR),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWLEN({{ thread.name }}_{{ iochannel.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWSIZE({{ thread.name }}_{{ iochannel.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWBURST({{ thread.name }}_{{ iochannel.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWLOCK({{ thread.name }}_{{ iochannel.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWCACHE({{ thread.name }}_{{ iochannel.name }}_AXI_AWCACHE),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWPROT({{ thread.name }}_{{ iochannel.name }}_AXI_AWPROT),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWREGION({{ thread.name }}_{{ iochannel.name }}_AXI_AWREGION),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWQOS({{ thread.name }}_{{ iochannel.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER({{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWVALID({{ thread.name }}_{{ iochannel.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_AWREADY({{ thread.name }}_{{ iochannel.name }}_AXI_AWREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WID({{ thread.name }}_{{ iochannel.name }}_AXI_WID),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WDATA({{ thread.name }}_{{ iochannel.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WSTRB({{ thread.name }}_{{ iochannel.name }}_AXI_WSTRB),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WLAST({{ thread.name }}_{{ iochannel.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WUSER({{ thread.name }}_{{ iochannel.name }}_AXI_WUSER),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WVALID({{ thread.name }}_{{ iochannel.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_WREADY({{ thread.name }}_{{ iochannel.name }}_AXI_WREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_BID({{ thread.name }}_{{ iochannel.name }}_AXI_BID),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_BRESP({{ thread.name }}_{{ iochannel.name }}_AXI_BRESP),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_BUSER({{ thread.name }}_{{ iochannel.name }}_AXI_BUSER),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_BVALID({{ thread.name }}_{{ iochannel.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_BREADY({{ thread.name }}_{{ iochannel.name }}_AXI_BREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARID({{ thread.name }}_{{ iochannel.name }}_AXI_ARID),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARADDR({{ thread.name }}_{{ iochannel.name }}_AXI_ARADDR),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARLEN({{ thread.name }}_{{ iochannel.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARSIZE({{ thread.name }}_{{ iochannel.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARBURST({{ thread.name }}_{{ iochannel.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARLOCK({{ thread.name }}_{{ iochannel.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARCACHE({{ thread.name }}_{{ iochannel.name }}_AXI_ARCACHE),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARPROT({{ thread.name }}_{{ iochannel.name }}_AXI_ARPROT),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARREGION({{ thread.name }}_{{ iochannel.name }}_AXI_ARREGION),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARQOS({{ thread.name }}_{{ iochannel.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER({{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARVALID({{ thread.name }}_{{ iochannel.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_ARREADY({{ thread.name }}_{{ iochannel.name }}_AXI_ARREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RID({{ thread.name }}_{{ iochannel.name }}_AXI_RID),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RDATA({{ thread.name }}_{{ iochannel.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RRESP({{ thread.name }}_{{ iochannel.name }}_AXI_RRESP),
{%- if not lite %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RLAST({{ thread.name }}_{{ iochannel.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RUSER({{ thread.name }}_{{ iochannel.name }}_AXI_RUSER),
{%- endif %}
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RVALID({{ thread.name }}_{{ iochannel.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ iochannel.name }}_AXI_RREADY({{ thread.name }}_{{ iochannel.name }}_AXI_RREADY),
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ACLK({{ thread.name }}_{{ ioregister.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN({{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN),

{% if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWID({{ thread.name }}_{{ ioregister.name }}_AXI_AWID),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWADDR({{ thread.name }}_{{ ioregister.name }}_AXI_AWADDR),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWLEN({{ thread.name }}_{{ ioregister.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWSIZE({{ thread.name }}_{{ ioregister.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWBURST({{ thread.name }}_{{ ioregister.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWLOCK({{ thread.name }}_{{ ioregister.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWCACHE({{ thread.name }}_{{ ioregister.name }}_AXI_AWCACHE),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWPROT({{ thread.name }}_{{ ioregister.name }}_AXI_AWPROT),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWREGION({{ thread.name }}_{{ ioregister.name }}_AXI_AWREGION),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWQOS({{ thread.name }}_{{ ioregister.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER({{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWVALID({{ thread.name }}_{{ ioregister.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_AWREADY({{ thread.name }}_{{ ioregister.name }}_AXI_AWREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WID({{ thread.name }}_{{ ioregister.name }}_AXI_WID),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WDATA({{ thread.name }}_{{ ioregister.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WSTRB({{ thread.name }}_{{ ioregister.name }}_AXI_WSTRB),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WLAST({{ thread.name }}_{{ ioregister.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WUSER({{ thread.name }}_{{ ioregister.name }}_AXI_WUSER),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WVALID({{ thread.name }}_{{ ioregister.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_WREADY({{ thread.name }}_{{ ioregister.name }}_AXI_WREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_BID({{ thread.name }}_{{ ioregister.name }}_AXI_BID),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_BRESP({{ thread.name }}_{{ ioregister.name }}_AXI_BRESP),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_BUSER({{ thread.name }}_{{ ioregister.name }}_AXI_BUSER),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_BVALID({{ thread.name }}_{{ ioregister.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_BREADY({{ thread.name }}_{{ ioregister.name }}_AXI_BREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARID({{ thread.name }}_{{ ioregister.name }}_AXI_ARID),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARADDR({{ thread.name }}_{{ ioregister.name }}_AXI_ARADDR),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARLEN({{ thread.name }}_{{ ioregister.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARSIZE({{ thread.name }}_{{ ioregister.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARBURST({{ thread.name }}_{{ ioregister.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARLOCK({{ thread.name }}_{{ ioregister.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARCACHE({{ thread.name }}_{{ ioregister.name }}_AXI_ARCACHE),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARPROT({{ thread.name }}_{{ ioregister.name }}_AXI_ARPROT),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARREGION({{ thread.name }}_{{ ioregister.name }}_AXI_ARREGION),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARQOS({{ thread.name }}_{{ ioregister.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER({{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARVALID({{ thread.name }}_{{ ioregister.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_ARREADY({{ thread.name }}_{{ ioregister.name }}_AXI_ARREADY),
   
{% if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RID({{ thread.name }}_{{ ioregister.name }}_AXI_RID),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RDATA({{ thread.name }}_{{ ioregister.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RRESP({{ thread.name }}_{{ ioregister.name }}_AXI_RRESP),
{%- if not lite %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RLAST({{ thread.name }}_{{ ioregister.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RUSER({{ thread.name }}_{{ ioregister.name }}_AXI_RUSER),
{%- endif %}
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RVALID({{ thread.name }}_{{ ioregister.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ ioregister.name }}_AXI_RREADY({{ thread.name }}_{{ ioregister.name }}_AXI_RREADY),
{% endfor %}
{%- endfor %}

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

{%- for thread in threads | sort(attribute='name') %}
   .{{ thread.name }}_finish({{ thread.name }}_finish),
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
   .{{ thread.name }}_CCLK({{ thread.name }}_CCLK),
   .{{ thread.name }}_CRESETN({{ thread.name }}_CRESETN),
{%- endfor %}

   .UCLK(UCLK),
   .URESETN(URESETN)
   ); 

  dram_stub #
  (
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
   .C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH),
   .C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH(C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH),
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
   .C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH),
   .C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH(C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH),
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH),
   .C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH(C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH),
{% endfor %}
{%- endfor %}
   .MEMIMG(MEMIMG),
   .SIM_ADDR_WIDTH(SIM_ADDR_WIDTH),
   .READ_LATENCY(READ_LATENCY),
   .WRITE_LATENCY(WRITE_LATENCY)
   )
  inst_dram_stub
  (
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
   .{{ thread.name }}_{{ memory.name }}_AXI_ACLK({{ thread.name }}_{{ memory.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARESETN({{ thread.name }}_{{ memory.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ memory.name }}_AXI_AWID({{ thread.name }}_{{ memory.name }}_AXI_AWID),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWADDR({{ thread.name }}_{{ memory.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWLEN({{ thread.name }}_{{ memory.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWSIZE({{ thread.name }}_{{ memory.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWBURST({{ thread.name }}_{{ memory.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWLOCK({{ thread.name }}_{{ memory.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWCACHE({{ thread.name }}_{{ memory.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWPROT({{ thread.name }}_{{ memory.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWQOS({{ thread.name }}_{{ memory.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWUSER({{ thread.name }}_{{ memory.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWVALID({{ thread.name }}_{{ memory.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_AWREADY({{ thread.name }}_{{ memory.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_WDATA({{ thread.name }}_{{ memory.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ memory.name }}_AXI_WSTRB({{ thread.name }}_{{ memory.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ memory.name }}_AXI_WLAST({{ thread.name }}_{{ memory.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ memory.name }}_AXI_WUSER({{ thread.name }}_{{ memory.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_WVALID({{ thread.name }}_{{ memory.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_WREADY({{ thread.name }}_{{ memory.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_BID({{ thread.name }}_{{ memory.name }}_AXI_BID),
   .{{ thread.name }}_{{ memory.name }}_AXI_BRESP({{ thread.name }}_{{ memory.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ memory.name }}_AXI_BUSER({{ thread.name }}_{{ memory.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_BVALID({{ thread.name }}_{{ memory.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_BREADY({{ thread.name }}_{{ memory.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_ARID({{ thread.name }}_{{ memory.name }}_AXI_ARID),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARADDR({{ thread.name }}_{{ memory.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARLEN({{ thread.name }}_{{ memory.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARSIZE({{ thread.name }}_{{ memory.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARBURST({{ thread.name }}_{{ memory.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARLOCK({{ thread.name }}_{{ memory.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARCACHE({{ thread.name }}_{{ memory.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARPROT({{ thread.name }}_{{ memory.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARQOS({{ thread.name }}_{{ memory.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARUSER({{ thread.name }}_{{ memory.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARVALID({{ thread.name }}_{{ memory.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_ARREADY({{ thread.name }}_{{ memory.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ memory.name }}_AXI_RID({{ thread.name }}_{{ memory.name }}_AXI_RID),
   .{{ thread.name }}_{{ memory.name }}_AXI_RDATA({{ thread.name }}_{{ memory.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ memory.name }}_AXI_RRESP({{ thread.name }}_{{ memory.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ memory.name }}_AXI_RLAST({{ thread.name }}_{{ memory.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ memory.name }}_AXI_RUSER({{ thread.name }}_{{ memory.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ memory.name }}_AXI_RVALID({{ thread.name }}_{{ memory.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ memory.name }}_AXI_RREADY({{ thread.name }}_{{ memory.name }}_AXI_RREADY),
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
   .{{ thread.name }}_{{ instream.name }}_AXI_ACLK({{ thread.name }}_{{ instream.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARESETN({{ thread.name }}_{{ instream.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ instream.name }}_AXI_AWID({{ thread.name }}_{{ instream.name }}_AXI_AWID),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWADDR({{ thread.name }}_{{ instream.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWLEN({{ thread.name }}_{{ instream.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWSIZE({{ thread.name }}_{{ instream.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWBURST({{ thread.name }}_{{ instream.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWLOCK({{ thread.name }}_{{ instream.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWCACHE({{ thread.name }}_{{ instream.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWPROT({{ thread.name }}_{{ instream.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWQOS({{ thread.name }}_{{ instream.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWUSER({{ thread.name }}_{{ instream.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWVALID({{ thread.name }}_{{ instream.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_AWREADY({{ thread.name }}_{{ instream.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_WDATA({{ thread.name }}_{{ instream.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ instream.name }}_AXI_WSTRB({{ thread.name }}_{{ instream.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ instream.name }}_AXI_WLAST({{ thread.name }}_{{ instream.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ instream.name }}_AXI_WUSER({{ thread.name }}_{{ instream.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_WVALID({{ thread.name }}_{{ instream.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_WREADY({{ thread.name }}_{{ instream.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_BID({{ thread.name }}_{{ instream.name }}_AXI_BID),
   .{{ thread.name }}_{{ instream.name }}_AXI_BRESP({{ thread.name }}_{{ instream.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ instream.name }}_AXI_BUSER({{ thread.name }}_{{ instream.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_BVALID({{ thread.name }}_{{ instream.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_BREADY({{ thread.name }}_{{ instream.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_ARID({{ thread.name }}_{{ instream.name }}_AXI_ARID),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARADDR({{ thread.name }}_{{ instream.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARLEN({{ thread.name }}_{{ instream.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARSIZE({{ thread.name }}_{{ instream.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARBURST({{ thread.name }}_{{ instream.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARLOCK({{ thread.name }}_{{ instream.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARCACHE({{ thread.name }}_{{ instream.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARPROT({{ thread.name }}_{{ instream.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARQOS({{ thread.name }}_{{ instream.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARUSER({{ thread.name }}_{{ instream.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARVALID({{ thread.name }}_{{ instream.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_ARREADY({{ thread.name }}_{{ instream.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ instream.name }}_AXI_RID({{ thread.name }}_{{ instream.name }}_AXI_RID),
   .{{ thread.name }}_{{ instream.name }}_AXI_RDATA({{ thread.name }}_{{ instream.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ instream.name }}_AXI_RRESP({{ thread.name }}_{{ instream.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ instream.name }}_AXI_RLAST({{ thread.name }}_{{ instream.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ instream.name }}_AXI_RUSER({{ thread.name }}_{{ instream.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ instream.name }}_AXI_RVALID({{ thread.name }}_{{ instream.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ instream.name }}_AXI_RREADY({{ thread.name }}_{{ instream.name }}_AXI_RREADY),
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
   .{{ thread.name }}_{{ outstream.name }}_AXI_ACLK({{ thread.name }}_{{ outstream.name }}_AXI_ACLK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARESETN({{ thread.name }}_{{ outstream.name }}_AXI_ARESETN),

   .{{ thread.name }}_{{ outstream.name }}_AXI_AWID({{ thread.name }}_{{ outstream.name }}_AXI_AWID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR({{ thread.name }}_{{ outstream.name }}_AXI_AWADDR),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN({{ thread.name }}_{{ outstream.name }}_AXI_AWLEN),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE({{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWBURST({{ thread.name }}_{{ outstream.name }}_AXI_AWBURST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK({{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE({{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWPROT({{ thread.name }}_{{ outstream.name }}_AXI_AWPROT),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWQOS({{ thread.name }}_{{ outstream.name }}_AXI_AWQOS),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER({{ thread.name }}_{{ outstream.name }}_AXI_AWUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWVALID({{ thread.name }}_{{ outstream.name }}_AXI_AWVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_AWREADY({{ thread.name }}_{{ outstream.name }}_AXI_AWREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_WDATA({{ thread.name }}_{{ outstream.name }}_AXI_WDATA),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WSTRB({{ thread.name }}_{{ outstream.name }}_AXI_WSTRB),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WLAST({{ thread.name }}_{{ outstream.name }}_AXI_WLAST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WUSER({{ thread.name }}_{{ outstream.name }}_AXI_WUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WVALID({{ thread.name }}_{{ outstream.name }}_AXI_WVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_WREADY({{ thread.name }}_{{ outstream.name }}_AXI_WREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_BID({{ thread.name }}_{{ outstream.name }}_AXI_BID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BRESP({{ thread.name }}_{{ outstream.name }}_AXI_BRESP),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BUSER({{ thread.name }}_{{ outstream.name }}_AXI_BUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BVALID({{ thread.name }}_{{ outstream.name }}_AXI_BVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_BREADY({{ thread.name }}_{{ outstream.name }}_AXI_BREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARID({{ thread.name }}_{{ outstream.name }}_AXI_ARID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR({{ thread.name }}_{{ outstream.name }}_AXI_ARADDR),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN({{ thread.name }}_{{ outstream.name }}_AXI_ARLEN),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE({{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARBURST({{ thread.name }}_{{ outstream.name }}_AXI_ARBURST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK({{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE({{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARPROT({{ thread.name }}_{{ outstream.name }}_AXI_ARPROT),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARQOS({{ thread.name }}_{{ outstream.name }}_AXI_ARQOS),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER({{ thread.name }}_{{ outstream.name }}_AXI_ARUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARVALID({{ thread.name }}_{{ outstream.name }}_AXI_ARVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_ARREADY({{ thread.name }}_{{ outstream.name }}_AXI_ARREADY),
   
   .{{ thread.name }}_{{ outstream.name }}_AXI_RID({{ thread.name }}_{{ outstream.name }}_AXI_RID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RDATA({{ thread.name }}_{{ outstream.name }}_AXI_RDATA),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RRESP({{ thread.name }}_{{ outstream.name }}_AXI_RRESP),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RLAST({{ thread.name }}_{{ outstream.name }}_AXI_RLAST),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RUSER({{ thread.name }}_{{ outstream.name }}_AXI_RUSER),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RVALID({{ thread.name }}_{{ outstream.name }}_AXI_RVALID),
   .{{ thread.name }}_{{ outstream.name }}_AXI_RREADY({{ thread.name }}_{{ outstream.name }}_AXI_RREADY),
{% endfor %}
{%- endfor %}

   .UCLK(UCLK),
   .URESETN(URESETN)
   );

{%- for thread in threads | sort(attribute='name') %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  reg {{ thread.name }}_{{ iochannel.name }}_ext_write_enq;
  reg [C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1:0] {{ thread.name }}_{{ iochannel.name }}_ext_write_data;
  wire {{ thread.name }}_{{ iochannel.name }}_ext_write_almost_full;
  reg {{ thread.name }}_{{ iochannel.name }}_ext_read_deq;
  wire [C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1:0] {{ thread.name }}_{{ iochannel.name }}_ext_read_data;
  wire {{ thread.name }}_{{ iochannel.name }}_ext_read_empty;

  reg [C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH-1:0] {{ thread.name }}_{{ iochannel.name }}_ext_addr;
  reg {{ thread.name }}_{{ iochannel.name }}_ext_read_enable;
  reg {{ thread.name }}_{{ iochannel.name }}_ext_write_enable;
  reg [8:0] {{ thread.name }}_{{ iochannel.name }}_ext_word_size;
  wire {{ thread.name }}_{{ iochannel.name }}_ext_done;

  initial begin
    {{ thread.name }}_{{ iochannel.name }}_ext_write_enq = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_write_data = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_read_deq = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_addr = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_read_enable = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_write_enable = 0;
    {{ thread.name }}_{{ iochannel.name }}_ext_word_size = 0;
  end
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  reg {{ thread.name }}_{{ ioregister.name }}_ext_write_enq;
  reg [C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1:0] {{ thread.name }}_{{ ioregister.name }}_ext_write_data;
  wire {{ thread.name }}_{{ ioregister.name }}_ext_write_almost_full;
  reg {{ thread.name }}_{{ ioregister.name }}_ext_read_deq;
  wire [C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1:0] {{ thread.name }}_{{ ioregister.name }}_ext_read_data;
  wire {{ thread.name }}_{{ ioregister.name }}_ext_read_empty;

  reg [C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH-1:0] {{ thread.name }}_{{ ioregister.name }}_ext_addr;
  reg {{ thread.name }}_{{ ioregister.name }}_ext_read_enable;
  reg {{ thread.name }}_{{ ioregister.name }}_ext_write_enable;
  reg [8:0] {{ thread.name }}_{{ ioregister.name }}_ext_word_size;
  wire {{ thread.name }}_{{ ioregister.name }}_ext_done;

  initial begin
    {{ thread.name }}_{{ ioregister.name }}_ext_write_enq = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_write_data = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_read_deq = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_addr = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_read_enable = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_write_enable = 0;
    {{ thread.name }}_{{ ioregister.name }}_ext_word_size = 0;
  end
{% endfor %}
{%- endfor %}


{%- for thread in threads | sort(attribute='name') %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  axi_master_fifo #
  (
{%- if not lite %}
   .C_M_AXI_THREAD_ID_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ID_WIDTH),
{%- endif %}
   .C_M_AXI_ADDR_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH),
   .C_M_AXI_DATA_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH),
{%- if not lite %}
   .C_M_AXI_AWUSER_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER_WIDTH),
   .C_M_AXI_ARUSER_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER_WIDTH),
   .C_M_AXI_WUSER_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_WUSER_WIDTH),
   .C_M_AXI_RUSER_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_RUSER_WIDTH),
   .C_M_AXI_BUSER_WIDTH(C_{{ thread.name }}_{{ iochannel.name }}_AXI_BUSER_WIDTH),
   .C_M_AXI_SUPPORTS_WRITE(C_{{ thread.name }}_{{ iochannel.name }}_AXI_SUPPORTS_WRITE),
   .C_M_AXI_SUPPORTS_READ(C_{{ thread.name }}_{{ iochannel.name }}_AXI_SUPPORTS_READ),
{%- endif %}
   .C_M_AXI_TARGET(0)
   )
  inst_axi_master_fifo_{{ thread.name }}_{{ iochannel.name }}
  (
   .ACLK({{ thread.name }}_{{ iochannel.name }}_AXI_ACLK), // AXI clock
   .ARESETN({{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN), // AXI reset

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

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

   .M_AXI_AWID({{ thread.name }}_{{ iochannel.name }}_AXI_AWID),
   .M_AXI_AWADDR({{ thread.name }}_{{ iochannel.name }}_AXI_AWADDR),
   .M_AXI_AWLEN({{ thread.name }}_{{ iochannel.name }}_AXI_AWLEN),
   .M_AXI_AWSIZE({{ thread.name }}_{{ iochannel.name }}_AXI_AWSIZE),
   .M_AXI_AWBURST({{ thread.name }}_{{ iochannel.name }}_AXI_AWBURST),
   .M_AXI_AWLOCK({{ thread.name }}_{{ iochannel.name }}_AXI_AWLOCK[0]),
   .M_AXI_AWCACHE({{ thread.name }}_{{ iochannel.name }}_AXI_AWCACHE),
   .M_AXI_AWPROT({{ thread.name }}_{{ iochannel.name }}_AXI_AWPROT),
   .M_AXI_AWQOS({{ thread.name }}_{{ iochannel.name }}_AXI_AWQOS),
   .M_AXI_AWUSER({{ thread.name }}_{{ iochannel.name }}_AXI_AWUSER),
   .M_AXI_AWVALID({{ thread.name }}_{{ iochannel.name }}_AXI_AWVALID),
   .M_AXI_AWREADY({{ thread.name }}_{{ iochannel.name }}_AXI_AWREADY),

   .M_AXI_WDATA({{ thread.name }}_{{ iochannel.name }}_AXI_WDATA),
   .M_AXI_WSTRB({{ thread.name }}_{{ iochannel.name }}_AXI_WSTRB),
   .M_AXI_WLAST({{ thread.name }}_{{ iochannel.name }}_AXI_WLAST),
   .M_AXI_WUSER({{ thread.name }}_{{ iochannel.name }}_AXI_WUSER),
   .M_AXI_WVALID({{ thread.name }}_{{ iochannel.name }}_AXI_WVALID),
   .M_AXI_WREADY({{ thread.name }}_{{ iochannel.name }}_AXI_WREADY),

   .M_AXI_BID({{ thread.name }}_{{ iochannel.name }}_AXI_BID),
   .M_AXI_BRESP({{ thread.name }}_{{ iochannel.name }}_AXI_BRESP),
   .M_AXI_BUSER({{ thread.name }}_{{ iochannel.name }}_AXI_BUSER),
   .M_AXI_BVALID({{ thread.name }}_{{ iochannel.name }}_AXI_BVALID),
   .M_AXI_BREADY({{ thread.name }}_{{ iochannel.name }}_AXI_BREADY),

   .M_AXI_ARID({{ thread.name }}_{{ iochannel.name }}_AXI_ARID),
   .M_AXI_ARADDR({{ thread.name }}_{{ iochannel.name }}_AXI_ARADDR),
   .M_AXI_ARLEN({{ thread.name }}_{{ iochannel.name }}_AXI_ARLEN),
   .M_AXI_ARSIZE({{ thread.name }}_{{ iochannel.name }}_AXI_ARSIZE),
   .M_AXI_ARBURST({{ thread.name }}_{{ iochannel.name }}_AXI_ARBURST),
   .M_AXI_ARLOCK({{ thread.name }}_{{ iochannel.name }}_AXI_ARLOCK),
   .M_AXI_ARCACHE({{ thread.name }}_{{ iochannel.name }}_AXI_ARCACHE),
   .M_AXI_ARPROT({{ thread.name }}_{{ iochannel.name }}_AXI_ARPROT),
   .M_AXI_ARQOS({{ thread.name }}_{{ iochannel.name }}_AXI_ARQOS),
   .M_AXI_ARUSER({{ thread.name }}_{{ iochannel.name }}_AXI_ARUSER),
   .M_AXI_ARVALID({{ thread.name }}_{{ iochannel.name }}_AXI_ARVALID),
   .M_AXI_ARREADY({{ thread.name }}_{{ iochannel.name }}_AXI_ARREADY),

   .M_AXI_RID({{ thread.name }}_{{ iochannel.name }}_AXI_RID),
   .M_AXI_RDATA({{ thread.name }}_{{ iochannel.name }}_AXI_RDATA),
   .M_AXI_RRESP({{ thread.name }}_{{ iochannel.name }}_AXI_RRESP),
   .M_AXI_RLAST({{ thread.name }}_{{ iochannel.name }}_AXI_RLAST),
   .M_AXI_RUSER({{ thread.name }}_{{ iochannel.name }}_AXI_RUSER),
   .M_AXI_RVALID({{ thread.name }}_{{ iochannel.name }}_AXI_RVALID),
   .M_AXI_RREADY({{ thread.name }}_{{ iochannel.name }}_AXI_RREADY)
  );
  assign {{ thread.name }}_{{ iochannel.name }}_AXI_AWREGION = 0;
  assign {{ thread.name }}_{{ iochannel.name }}_AXI_AWLOCK[1] = 1'b0;
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  axi_master_fifo #
  (
{%- if not lite %}
   .C_M_AXI_THREAD_ID_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ID_WIDTH),
{%- endif %}
   .C_M_AXI_ADDR_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH),
   .C_M_AXI_DATA_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH),
{%- if not lite %}
   .C_M_AXI_AWUSER_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER_WIDTH),
   .C_M_AXI_ARUSER_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER_WIDTH),
   .C_M_AXI_WUSER_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_WUSER_WIDTH),
   .C_M_AXI_RUSER_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_RUSER_WIDTH),
   .C_M_AXI_BUSER_WIDTH(C_{{ thread.name }}_{{ ioregister.name }}_AXI_BUSER_WIDTH),
   .C_M_AXI_SUPPORTS_WRITE(C_{{ thread.name }}_{{ ioregister.name }}_AXI_SUPPORTS_WRITE),
   .C_M_AXI_SUPPORTS_READ(C_{{ thread.name }}_{{ ioregister.name }}_AXI_SUPPORTS_READ),
{%- endif %}
   .C_M_AXI_TARGET(0)
   )
  inst_axi_master_fifo_{{ thread.name }}_{{ ioregister.name }}
  (
   .ACLK({{ thread.name }}_{{ ioregister.name }}_AXI_ACLK), // AXI clock
   .ARESETN({{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN), // AXI reset

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

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

   .M_AXI_AWID({{ thread.name }}_{{ ioregister.name }}_AXI_AWID),
   .M_AXI_AWADDR({{ thread.name }}_{{ ioregister.name }}_AXI_AWADDR),
   .M_AXI_AWLEN({{ thread.name }}_{{ ioregister.name }}_AXI_AWLEN),
   .M_AXI_AWSIZE({{ thread.name }}_{{ ioregister.name }}_AXI_AWSIZE),
   .M_AXI_AWBURST({{ thread.name }}_{{ ioregister.name }}_AXI_AWBURST),
   .M_AXI_AWLOCK({{ thread.name }}_{{ ioregister.name }}_AXI_AWLOCK[0]),
   .M_AXI_AWCACHE({{ thread.name }}_{{ ioregister.name }}_AXI_AWCACHE),
   .M_AXI_AWPROT({{ thread.name }}_{{ ioregister.name }}_AXI_AWPROT),
   .M_AXI_AWQOS({{ thread.name }}_{{ ioregister.name }}_AXI_AWQOS),
   .M_AXI_AWUSER({{ thread.name }}_{{ ioregister.name }}_AXI_AWUSER),
   .M_AXI_AWVALID({{ thread.name }}_{{ ioregister.name }}_AXI_AWVALID),
   .M_AXI_AWREADY({{ thread.name }}_{{ ioregister.name }}_AXI_AWREADY),

   .M_AXI_WDATA({{ thread.name }}_{{ ioregister.name }}_AXI_WDATA),
   .M_AXI_WSTRB({{ thread.name }}_{{ ioregister.name }}_AXI_WSTRB),
   .M_AXI_WLAST({{ thread.name }}_{{ ioregister.name }}_AXI_WLAST),
   .M_AXI_WUSER({{ thread.name }}_{{ ioregister.name }}_AXI_WUSER),
   .M_AXI_WVALID({{ thread.name }}_{{ ioregister.name }}_AXI_WVALID),
   .M_AXI_WREADY({{ thread.name }}_{{ ioregister.name }}_AXI_WREADY),

   .M_AXI_BID({{ thread.name }}_{{ ioregister.name }}_AXI_BID),
   .M_AXI_BRESP({{ thread.name }}_{{ ioregister.name }}_AXI_BRESP),
   .M_AXI_BUSER({{ thread.name }}_{{ ioregister.name }}_AXI_BUSER),
   .M_AXI_BVALID({{ thread.name }}_{{ ioregister.name }}_AXI_BVALID),
   .M_AXI_BREADY({{ thread.name }}_{{ ioregister.name }}_AXI_BREADY),

   .M_AXI_ARID({{ thread.name }}_{{ ioregister.name }}_AXI_ARID),
   .M_AXI_ARADDR({{ thread.name }}_{{ ioregister.name }}_AXI_ARADDR),
   .M_AXI_ARLEN({{ thread.name }}_{{ ioregister.name }}_AXI_ARLEN),
   .M_AXI_ARSIZE({{ thread.name }}_{{ ioregister.name }}_AXI_ARSIZE),
   .M_AXI_ARBURST({{ thread.name }}_{{ ioregister.name }}_AXI_ARBURST),
   .M_AXI_ARLOCK({{ thread.name }}_{{ ioregister.name }}_AXI_ARLOCK),
   .M_AXI_ARCACHE({{ thread.name }}_{{ ioregister.name }}_AXI_ARCACHE),
   .M_AXI_ARPROT({{ thread.name }}_{{ ioregister.name }}_AXI_ARPROT),
   .M_AXI_ARQOS({{ thread.name }}_{{ ioregister.name }}_AXI_ARQOS),
   .M_AXI_ARUSER({{ thread.name }}_{{ ioregister.name }}_AXI_ARUSER),
   .M_AXI_ARVALID({{ thread.name }}_{{ ioregister.name }}_AXI_ARVALID),
   .M_AXI_ARREADY({{ thread.name }}_{{ ioregister.name }}_AXI_ARREADY),

   .M_AXI_RID({{ thread.name }}_{{ ioregister.name }}_AXI_RID),
   .M_AXI_RDATA({{ thread.name }}_{{ ioregister.name }}_AXI_RDATA),
   .M_AXI_RRESP({{ thread.name }}_{{ ioregister.name }}_AXI_RRESP),
   .M_AXI_RLAST({{ thread.name }}_{{ ioregister.name }}_AXI_RLAST),
   .M_AXI_RUSER({{ thread.name }}_{{ ioregister.name }}_AXI_RUSER),
   .M_AXI_RVALID({{ thread.name }}_{{ ioregister.name }}_AXI_RVALID),
   .M_AXI_RREADY({{ thread.name }}_{{ ioregister.name }}_AXI_RREADY)
  );
  assign {{ thread.name }}_{{ ioregister.name }}_AXI_AWREGION = 0;
  assign {{ thread.name }}_{{ ioregister.name }}_AXI_AWLOCK[1] = 1'b0;
{% endfor %}
{%- endfor %}


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

{%- for thread in threads | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_CCLK = 0;
    #HPERIOD_CLK_CTHREAD;
    forever #HPERIOD_CLK_CTHREAD {{ thread.name }}_CCLK = ~{{ thread.name }}_CCLK;
  end
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_{{ memory.name }}_AXI_ACLK = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS {{ thread.name }}_{{ memory.name }}_AXI_ACLK = ~{{ thread.name }}_{{ memory.name }}_AXI_ACLK;
  end
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_{{ instream.name }}_AXI_ACLK = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS {{ thread.name }}_{{ instream.name }}_AXI_ACLK = ~{{ thread.name }}_{{ instream.name }}_AXI_ACLK;
  end
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_{{ outstream.name }}_AXI_ACLK = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS {{ thread.name }}_{{ outstream.name }}_AXI_ACLK = ~{{ thread.name }}_{{ outstream.name }}_AXI_ACLK;
  end
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_{{ iochannel.name }}_AXI_ACLK = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS {{ thread.name }}_{{ iochannel.name }}_AXI_ACLK = ~{{ thread.name }}_{{ iochannel.name }}_AXI_ACLK;
  end
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  initial begin
    {{ thread.name }}_{{ ioregister.name }}_AXI_ACLK = 0;
    #HPERIOD_CLK_BUS;
    forever #HPERIOD_CLK_BUS {{ thread.name }}_{{ ioregister.name }}_AXI_ACLK = ~{{ thread.name }}_{{ ioregister.name }}_AXI_ACLK;
  end
{% endfor %}
{%- endfor %}

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

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

    URESETN = 1;

{%- for thread in threads | sort(attribute='name') %}
    {{ thread.name }}_CRESETN = 1;
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
    {{ thread.name }}_{{ memory.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
    {{ thread.name }}_{{ instream.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
    {{ thread.name }}_{{ outstream.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
    {{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
    {{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN = 1;
{% endfor %}
{%- endfor %}
    
    #100;

    URESETN = 0;

{%- for thread in threads | sort(attribute='name') %}
    {{ thread.name }}_CRESETN = 0;
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
    {{ thread.name }}_{{ memory.name }}_AXI_ARESETN = 0;
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
    {{ thread.name }}_{{ instream.name }}_AXI_ARESETN = 0;
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
    {{ thread.name }}_{{ outstream.name }}_AXI_ARESETN = 0;
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
    {{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN = 0;
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
    {{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN = 0;
{% endfor %}
{%- endfor %}

    #100;

    URESETN = 1;

{%- for thread in threads | sort(attribute='name') %}
    {{ thread.name }}_CRESETN = 1;
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}
    {{ thread.name }}_{{ memory.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}
    {{ thread.name }}_{{ instream.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}
    {{ thread.name }}_{{ outstream.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
    {{ thread.name }}_{{ iochannel.name }}_AXI_ARESETN = 1;
{% endfor %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
    {{ thread.name }}_{{ ioregister.name }}_AXI_ARESETN = 1;
{% endfor %}
{%- endfor %}

    #100;

    nclk();

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

  initial begin
    #301;
    wait(
{%- for thread in threads | sort(attribute='name') %}
         {{ thread.name }}_finish &&
{%- endfor %}    
         1'b1);
    $display("[CoRAM] time:%d all threads finished", $stime);
    $finish;
  end

{%- for thread in threads | sort(attribute='name') %}
{% for iochannel in thread.iochannels | sort(attribute='name') %}
  task iochannel_write_{{ thread.name }}_{{ iochannel.name }};
    input [C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1:0] data;
    input [C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      wait(!{{ thread.name }}_{{ iochannel.name }}_ext_write_almost_full);
      #1;
      {{ thread.name }}_{{ iochannel.name }}_ext_write_enable = 1;
      {{ thread.name }}_{{ iochannel.name }}_ext_addr = addr;
      {{ thread.name }}_{{ iochannel.name }}_ext_word_size = 1;
      {{ thread.name }}_{{ iochannel.name }}_ext_write_enq = 1;
      {{ thread.name }}_{{ iochannel.name }}_ext_write_data = data;
      nclk();
      {{ thread.name }}_{{ iochannel.name }}_ext_write_enq = 0;
      nclk();
      wait({{ thread.name }}_{{ iochannel.name }}_ext_done);
      #1;
      {{ thread.name }}_{{ iochannel.name }}_ext_write_enable = 0;
      nclk();
    end
  endtask

  task iochannel_read_{{ thread.name }}_{{ iochannel.name }};
    output [C_{{ thread.name }}_{{ iochannel.name }}_AXI_DATA_WIDTH-1:0] data;
    input [C_{{ thread.name }}_{{ iochannel.name }}_AXI_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      {{ thread.name }}_{{ iochannel.name }}_ext_read_enable = 1;
      {{ thread.name }}_{{ iochannel.name }}_ext_addr = addr;
      {{ thread.name }}_{{ iochannel.name }}_ext_word_size = 1;
      nclk();
      nclk();
      wait({{ thread.name }}_{{ iochannel.name }}_ext_done);
      #1;
      {{ thread.name }}_{{ iochannel.name }}_ext_read_enable = 0;
      nclk();
      wait(!{{ thread.name }}_{{ iochannel.name }}_ext_read_empty);
      #1;
      data = {{ thread.name }}_{{ iochannel.name }}_ext_read_data;
      {{ thread.name }}_{{ iochannel.name }}_ext_read_deq = 1;
      nclk();
      {{ thread.name }}_{{ iochannel.name }}_ext_read_deq = 0;
      nclk();
    end
  endtask
{% endfor %}
{%- endfor %}

{%- for thread in threads | sort(attribute='name') %}
{% for ioregister in thread.ioregisters | sort(attribute='name') %}
  task ioregister_write_{{ thread.name }}_{{ ioregister.name }};
    input [C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1:0] data;
    input [C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      wait(!{{ thread.name }}_{{ ioregister.name }}_ext_write_almost_full);
      #1;
      {{ thread.name }}_{{ ioregister.name }}_ext_write_enable = 1;
      {{ thread.name }}_{{ ioregister.name }}_ext_addr = addr;
      {{ thread.name }}_{{ ioregister.name }}_ext_word_size = 1;
      {{ thread.name }}_{{ ioregister.name }}_ext_write_enq = 1;
      {{ thread.name }}_{{ ioregister.name }}_ext_write_data = data;
      nclk();
      {{ thread.name }}_{{ ioregister.name }}_ext_write_enq = 0;
      nclk();
      wait({{ thread.name }}_{{ ioregister.name }}_ext_done);
      #1;
      {{ thread.name }}_{{ ioregister.name }}_ext_write_enable = 0;
      nclk();
    end
  endtask

  task ioregister_read_{{ thread.name }}_{{ ioregister.name }};
    output [C_{{ thread.name }}_{{ ioregister.name }}_AXI_DATA_WIDTH-1:0] data;
    input [C_{{ thread.name }}_{{ ioregister.name }}_AXI_ADDR_WIDTH-1:0] addr;
    begin
      nclk();
      {{ thread.name }}_{{ ioregister.name }}_ext_read_enable = 1;
      {{ thread.name }}_{{ ioregister.name }}_ext_addr = addr;
      {{ thread.name }}_{{ ioregister.name }}_ext_word_size = 1;
      nclk();
      nclk();
      wait({{ thread.name }}_{{ ioregister.name }}_ext_done);
      #1;
      {{ thread.name }}_{{ ioregister.name }}_ext_read_enable = 0;
      nclk();
      wait(!{{ thread.name }}_{{ ioregister.name }}_ext_read_empty);
      #1;
      data = {{ thread.name }}_{{ ioregister.name }}_ext_read_data;
      {{ thread.name }}_{{ ioregister.name }}_ext_read_deq = 1;
      nclk();
      {{ thread.name }}_{{ ioregister.name }}_ext_read_deq = 0;
      nclk();
    end
  endtask
{% endfor %}
{%- 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 AXI Interface
//------------------------------------------------------------------------------
module dram_stub #
  (
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}   
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH       = 1,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH           = 1,
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}   
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH       = 1,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH           = 1,
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}   
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH       = 1,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH            = 32,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH          = 1,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH           = 1,
   parameter integer C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH           = 1,
{% endfor %}
{%- endfor %}
   parameter MEMIMG = "{{ memimg }}",
   parameter SIM_ADDR_WIDTH = {{ simaddrwidth }},
   parameter READ_LATENCY = 32,
   parameter WRITE_LATENCY = 32
   )
  (
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}   
   // Clock and Reset
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_ACLK,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_ARESETN,

   // Master Interface Write Address
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_AWID,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_AWADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWBURST,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_AWLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_AWQOS,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_AWUSER,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_AWVALID,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_AWREADY,
   
   // Master Interface Write Data
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_WDATA,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_WSTRB,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_WLAST,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_WUSER,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_WVALID,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_WREADY,
   
   // Master Interface Write Response
   output wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_BID,
   output wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_BRESP,
   output wire [C_{{ thread.name }}_{{ memory.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_BUSER,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_BVALID,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_BREADY,
   
   // Master Interface Read Address
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_ARID,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_ARADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARBURST,
   input  wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_ARQOS,
   input  wire [C_{{ thread.name }}_{{ memory.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ memory.name }}_AXI_ARUSER,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_ARVALID,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_ARREADY,
   
   // Master Interface Read Data 
   output wire [C_{{ thread.name }}_{{ memory.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ memory.name }}_AXI_RID,
   output reg  [C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ memory.name }}_AXI_RDATA,
   output wire [2-1:0]                       {{ thread.name }}_{{ memory.name }}_AXI_RRESP,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_RLAST,
   output wire [C_{{ thread.name }}_{{ memory.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ memory.name }}_AXI_RUSER,
   output reg                                {{ thread.name }}_{{ memory.name }}_AXI_RVALID,
   input  wire                               {{ thread.name }}_{{ memory.name }}_AXI_RREADY,
{% endfor %}
{% for instream in thread.instreams | sort(attribute='name') %}   
   // Clock and Reset
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_ACLK,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_ARESETN,

   // Master Interface Write Address
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_AWID,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_AWADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWBURST,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_AWLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_AWQOS,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_AWUSER,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_AWVALID,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_AWREADY,
   
   // Master Interface Write Data
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_WDATA,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_WSTRB,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_WLAST,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_WUSER,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_WVALID,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_WREADY,
   
   // Master Interface Write Response
   output wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_BID,
   output wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_BRESP,
   output wire [C_{{ thread.name }}_{{ instream.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_BUSER,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_BVALID,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_BREADY,
   
   // Master Interface Read Address
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_ARID,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_ARADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARBURST,
   input  wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_ARQOS,
   input  wire [C_{{ thread.name }}_{{ instream.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ instream.name }}_AXI_ARUSER,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_ARVALID,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_ARREADY,
   
   // Master Interface Read Data 
   output wire [C_{{ thread.name }}_{{ instream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ instream.name }}_AXI_RID,
   output reg  [C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ instream.name }}_AXI_RDATA,
   output wire [2-1:0]                       {{ thread.name }}_{{ instream.name }}_AXI_RRESP,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_RLAST,
   output wire [C_{{ thread.name }}_{{ instream.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ instream.name }}_AXI_RUSER,
   output reg                                {{ thread.name }}_{{ instream.name }}_AXI_RVALID,
   input  wire                               {{ thread.name }}_{{ instream.name }}_AXI_RREADY,
{% endfor %}
{% for outstream in thread.outstreams | sort(attribute='name') %}   
   // Clock and Reset
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_ACLK,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_ARESETN,

   // Master Interface Write Address
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_AWID,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_AWADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWBURST,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_AWLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_AWQOS,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_AWUSER_WIDTH-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_AWUSER,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_AWVALID,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_AWREADY,
   
   // Master Interface Write Data
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_WDATA,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH/8-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_WSTRB,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_WLAST,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_WUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_WUSER,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_WVALID,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_WREADY,
   
   // Master Interface Write Response
   output wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_BID,
   output wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_BRESP,
   output wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_BUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_BUSER,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_BVALID,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_BREADY,
   
   // Master Interface Read Address
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_ARID,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_ARADDR,
   input  wire [8-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARLEN,
   input  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARSIZE,
   input  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARBURST,
   input  wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARLOCK,
   input  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARCACHE,
   input  wire [3-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARPROT,
   input  wire [4-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_ARQOS,
   input  wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_ARUSER_WIDTH-1:0]    {{ thread.name }}_{{ outstream.name }}_AXI_ARUSER,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_ARVALID,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_ARREADY,
   
   // Master Interface Read Data 
   output wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_THREAD_ID_WIDTH-1:0] {{ thread.name }}_{{ outstream.name }}_AXI_RID,
   output reg  [C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH-1:0]      {{ thread.name }}_{{ outstream.name }}_AXI_RDATA,
   output wire [2-1:0]                       {{ thread.name }}_{{ outstream.name }}_AXI_RRESP,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_RLAST,
   output wire [C_{{ thread.name }}_{{ outstream.name }}_AXI_RUSER_WIDTH-1:0]     {{ thread.name }}_{{ outstream.name }}_AXI_RUSER,
   output reg                                {{ thread.name }}_{{ outstream.name }}_AXI_RVALID,
   input  wire                               {{ thread.name }}_{{ outstream.name }}_AXI_RREADY,
{% endfor %}
{%- endfor %}

   input UCLK, // User logic (Unused)
   input URESETN // 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 thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}   
  task mem_write_{{ thread.name }}_{{ memory.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    input [C_{{ thread.name }}_{{ memory.name }}_AXI_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_{{ thread.name }}_{{ memory.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    output [C_{{ thread.name }}_{{ memory.name }}_AXI_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 %}

{% for instream in thread.instreams | sort(attribute='name') %}   
  task mem_write_{{ thread.name }}_{{ instream.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    input [C_{{ thread.name }}_{{ instream.name }}_AXI_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_{{ thread.name }}_{{ instream.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    output [C_{{ thread.name }}_{{ instream.name }}_AXI_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 %}

{% for outstream in thread.outstreams | sort(attribute='name') %}   
  task mem_write_{{ thread.name }}_{{ outstream.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    input [C_{{ thread.name }}_{{ outstream.name }}_AXI_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_{{ thread.name }}_{{ outstream.name }};
    input [SIM_ADDR_WIDTH-1:0] addr;
    input [SIM_ADDR_WIDTH-1:0] size;
    output [C_{{ thread.name }}_{{ outstream.name }}_AXI_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 %}
{%- endfor %}

  //------------------------------------------------------------------------------
  // Timing Model
  //------------------------------------------------------------------------------
{%- for thread in threads | sort(attribute='name') %}
{% for memory in thread.memories | sort(attribute='name') %}   
  reg {{ thread.name }}_{{ memory.name }}_AXI_write_mode;
  reg [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ memory.name }}_AXI_AWADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ memory.name }}_AXI_AWLEN;

  reg {{ thread.name }}_{{ memory.name }}_AXI_read_mode;
  reg [C_{{ thread.name }}_{{ memory.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ memory.name }}_AXI_ARADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ memory.name }}_AXI_ARLEN;

  reg [31:0] {{ thread.name }}_{{ memory.name }}_stall_count;
  
  always @(negedge {{ thread.name }}_{{ memory.name }}_AXI_ACLK) begin
    if(!{{ thread.name }}_{{ memory.name }}_AXI_ARESETN) begin
      {{ thread.name }}_{{ memory.name }}_AXI_write_mode <= 0;
      {{ thread.name }}_{{ memory.name }}_AXI_read_mode <= 0;
      {{ thread.name }}_{{ memory.name }}_stall_count <= 0;
    end else begin
      {{ thread.name }}_{{ memory.name }}_AXI_AWREADY = 0;
      {{ thread.name }}_{{ memory.name }}_AXI_WREADY = 0;
      {{ thread.name }}_{{ memory.name }}_AXI_BVALID = 0;
      
      {{ thread.name }}_{{ memory.name }}_AXI_ARREADY = 0;
      {{ thread.name }}_{{ memory.name }}_AXI_RVALID = 0;
      {{ thread.name }}_{{ memory.name }}_AXI_RLAST = 0;
      
      if(!{{ thread.name }}_{{ memory.name }}_AXI_write_mode && {{ thread.name }}_{{ memory.name }}_AXI_AWVALID) begin
        {{ thread.name }}_{{ memory.name }}_stall_count <= {{ thread.name }}_{{ memory.name }}_stall_count + 1;
        if({{ thread.name }}_{{ memory.name }}_stall_count == WRITE_LATENCY) begin
          {{ thread.name }}_{{ memory.name }}_stall_count <= 0;
          {{ thread.name }}_{{ memory.name }}_AXI_write_mode <= 1;
          {{ thread.name }}_{{ memory.name }}_AXI_AWREADY = 1;
          d_{{ thread.name }}_{{ memory.name }}_AXI_AWADDR = {{ thread.name }}_{{ memory.name }}_AXI_AWADDR;
          d_{{ thread.name }}_{{ memory.name }}_AXI_AWLEN = {{ thread.name }}_{{ memory.name }}_AXI_AWLEN;
        end
      end

      if(!{{ thread.name }}_{{ memory.name }}_AXI_read_mode && {{ thread.name }}_{{ memory.name }}_AXI_ARVALID) begin
        {{ thread.name }}_{{ memory.name }}_stall_count <= {{ thread.name }}_{{ memory.name }}_stall_count + 1;
        if({{ thread.name }}_{{ memory.name }}_stall_count == READ_LATENCY) begin
          {{ thread.name }}_{{ memory.name }}_stall_count <= 0;
          {{ thread.name }}_{{ memory.name }}_AXI_read_mode <= 1;
          {{ thread.name }}_{{ memory.name }}_AXI_ARREADY = 1;
          d_{{ thread.name }}_{{ memory.name }}_AXI_ARADDR = {{ thread.name }}_{{ memory.name }}_AXI_ARADDR;
          d_{{ thread.name }}_{{ memory.name }}_AXI_ARLEN = {{ thread.name }}_{{ memory.name }}_AXI_ARLEN;
        end
      end
      
      if({{ thread.name }}_{{ memory.name }}_AXI_write_mode) begin
        {{ thread.name }}_{{ memory.name }}_AXI_WREADY = 1;
        if({{ thread.name }}_{{ memory.name }}_AXI_WVALID) begin
          mem_write_{{ thread.name }}_{{ memory.name }}(d_{{ thread.name }}_{{ memory.name }}_AXI_AWADDR, C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ memory.name }}_AXI_WDATA);
          if(d_{{ thread.name }}_{{ memory.name }}_AXI_AWLEN == 0 || {{ thread.name }}_{{ memory.name }}_AXI_WLAST) begin // actual burst length -1
            {{ thread.name }}_{{ memory.name }}_AXI_write_mode <= 0;
            {{ thread.name }}_{{ memory.name }}_AXI_BVALID = 1;
          end
          d_{{ thread.name }}_{{ memory.name }}_AXI_AWADDR = d_{{ thread.name }}_{{ memory.name }}_AXI_AWADDR + (C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ memory.name }}_AXI_AWLEN = d_{{ thread.name }}_{{ memory.name }}_AXI_AWLEN - 1;
        end
      end

      if({{ thread.name }}_{{ memory.name }}_AXI_read_mode) begin
        mem_read_{{ thread.name }}_{{ memory.name }}(d_{{ thread.name }}_{{ memory.name }}_AXI_ARADDR, C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ memory.name }}_AXI_RDATA);
        {{ thread.name }}_{{ memory.name }}_AXI_RVALID = 1;
        if(d_{{ thread.name }}_{{ memory.name }}_AXI_ARLEN == 0) begin // actual burst length -1
          {{ thread.name }}_{{ memory.name }}_AXI_RLAST = 1;
          if({{ thread.name }}_{{ memory.name }}_AXI_RREADY) begin
            {{ thread.name }}_{{ memory.name }}_AXI_read_mode <= 0;
          end
        end
        if({{ thread.name }}_{{ memory.name }}_AXI_RREADY) begin
          d_{{ thread.name }}_{{ memory.name }}_AXI_ARADDR = d_{{ thread.name }}_{{ memory.name }}_AXI_ARADDR + (C_{{ thread.name }}_{{ memory.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ memory.name }}_AXI_ARLEN = d_{{ thread.name }}_{{ memory.name }}_AXI_ARLEN - 1;
        end
      end

    end
  end
{% endfor %}

{% for instream in thread.instreams | sort(attribute='name') %}   
  reg {{ thread.name }}_{{ instream.name }}_AXI_write_mode;
  reg [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ instream.name }}_AXI_AWADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ instream.name }}_AXI_AWLEN;

  reg {{ thread.name }}_{{ instream.name }}_AXI_read_mode;
  reg [C_{{ thread.name }}_{{ instream.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ instream.name }}_AXI_ARADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ instream.name }}_AXI_ARLEN;

  reg [31:0] {{ thread.name }}_{{ instream.name }}_stall_count;
  
  always @(negedge {{ thread.name }}_{{ instream.name }}_AXI_ACLK) begin
    if(!{{ thread.name }}_{{ instream.name }}_AXI_ARESETN) begin
      {{ thread.name }}_{{ instream.name }}_AXI_write_mode <= 0;
      {{ thread.name }}_{{ instream.name }}_AXI_read_mode <= 0;
      {{ thread.name }}_{{ instream.name }}_stall_count <= 0;
    end else begin
      {{ thread.name }}_{{ instream.name }}_AXI_AWREADY = 0;
      {{ thread.name }}_{{ instream.name }}_AXI_WREADY = 0;
      {{ thread.name }}_{{ instream.name }}_AXI_BVALID = 0;
      
      {{ thread.name }}_{{ instream.name }}_AXI_ARREADY = 0;
      {{ thread.name }}_{{ instream.name }}_AXI_RVALID = 0;
      {{ thread.name }}_{{ instream.name }}_AXI_RLAST = 0;
      
      if(!{{ thread.name }}_{{ instream.name }}_AXI_write_mode && {{ thread.name }}_{{ instream.name }}_AXI_AWVALID) begin
        {{ thread.name }}_{{ instream.name }}_stall_count <= {{ thread.name }}_{{ instream.name }}_stall_count + 1;
        if({{ thread.name }}_{{ instream.name }}_stall_count == WRITE_LATENCY) begin
          {{ thread.name }}_{{ instream.name }}_stall_count <= 0;
          {{ thread.name }}_{{ instream.name }}_AXI_write_mode <= 1;
          {{ thread.name }}_{{ instream.name }}_AXI_AWREADY = 1;
          d_{{ thread.name }}_{{ instream.name }}_AXI_AWADDR = {{ thread.name }}_{{ instream.name }}_AXI_AWADDR;
          d_{{ thread.name }}_{{ instream.name }}_AXI_AWLEN = {{ thread.name }}_{{ instream.name }}_AXI_AWLEN;
        end
      end

      if(!{{ thread.name }}_{{ instream.name }}_AXI_read_mode && {{ thread.name }}_{{ instream.name }}_AXI_ARVALID) begin
        {{ thread.name }}_{{ instream.name }}_stall_count <= {{ thread.name }}_{{ instream.name }}_stall_count + 1;
        if({{ thread.name }}_{{ instream.name }}_stall_count == READ_LATENCY) begin
          {{ thread.name }}_{{ instream.name }}_stall_count <= 0;
          {{ thread.name }}_{{ instream.name }}_AXI_read_mode <= 1;
          {{ thread.name }}_{{ instream.name }}_AXI_ARREADY = 1;
          d_{{ thread.name }}_{{ instream.name }}_AXI_ARADDR = {{ thread.name }}_{{ instream.name }}_AXI_ARADDR;
          d_{{ thread.name }}_{{ instream.name }}_AXI_ARLEN = {{ thread.name }}_{{ instream.name }}_AXI_ARLEN;
        end
      end
      
      if({{ thread.name }}_{{ instream.name }}_AXI_write_mode) begin
        {{ thread.name }}_{{ instream.name }}_AXI_WREADY = 1;
        if({{ thread.name }}_{{ instream.name }}_AXI_WVALID) begin
          mem_write_{{ thread.name }}_{{ instream.name }}(d_{{ thread.name }}_{{ instream.name }}_AXI_AWADDR, C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ instream.name }}_AXI_WDATA);
          if(d_{{ thread.name }}_{{ instream.name }}_AXI_AWLEN == 0 || {{ thread.name }}_{{ instream.name }}_AXI_WLAST) begin // actual burst length -1
            {{ thread.name }}_{{ instream.name }}_AXI_write_mode <= 0;
            {{ thread.name }}_{{ instream.name }}_AXI_BVALID = 1;
          end
          d_{{ thread.name }}_{{ instream.name }}_AXI_AWADDR = d_{{ thread.name }}_{{ instream.name }}_AXI_AWADDR + (C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ instream.name }}_AXI_AWLEN = d_{{ thread.name }}_{{ instream.name }}_AXI_AWLEN - 1;
        end
      end

      if({{ thread.name }}_{{ instream.name }}_AXI_read_mode) begin
        mem_read_{{ thread.name }}_{{ instream.name }}(d_{{ thread.name }}_{{ instream.name }}_AXI_ARADDR, C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ instream.name }}_AXI_RDATA);
        {{ thread.name }}_{{ instream.name }}_AXI_RVALID = 1;
        if(d_{{ thread.name }}_{{ instream.name }}_AXI_ARLEN == 0) begin // actual burst length -1
          {{ thread.name }}_{{ instream.name }}_AXI_RLAST = 1;
          if({{ thread.name }}_{{ instream.name }}_AXI_RREADY) begin
            {{ thread.name }}_{{ instream.name }}_AXI_read_mode <= 0;
          end
        end
        if({{ thread.name }}_{{ instream.name }}_AXI_RREADY) begin
          d_{{ thread.name }}_{{ instream.name }}_AXI_ARADDR = d_{{ thread.name }}_{{ instream.name }}_AXI_ARADDR + (C_{{ thread.name }}_{{ instream.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ instream.name }}_AXI_ARLEN = d_{{ thread.name }}_{{ instream.name }}_AXI_ARLEN - 1;
        end
      end

    end
  end
{% endfor %}

{% for outstream in thread.outstreams | sort(attribute='name') %}   
  reg {{ thread.name }}_{{ outstream.name }}_AXI_write_mode;
  reg [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN;

  reg {{ thread.name }}_{{ outstream.name }}_AXI_read_mode;
  reg [C_{{ thread.name }}_{{ outstream.name }}_AXI_ADDR_WIDTH-1:0] d_{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR;
  reg [8-1:0] d_{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN;

  reg [31:0] {{ thread.name }}_{{ outstream.name }}_stall_count;
  
  always @(negedge {{ thread.name }}_{{ outstream.name }}_AXI_ACLK) begin
    if(!{{ thread.name }}_{{ outstream.name }}_AXI_ARESETN) begin
      {{ thread.name }}_{{ outstream.name }}_AXI_write_mode <= 0;
      {{ thread.name }}_{{ outstream.name }}_AXI_read_mode <= 0;
      {{ thread.name }}_{{ outstream.name }}_stall_count <= 0;
    end else begin
      {{ thread.name }}_{{ outstream.name }}_AXI_AWREADY = 0;
      {{ thread.name }}_{{ outstream.name }}_AXI_WREADY = 0;
      {{ thread.name }}_{{ outstream.name }}_AXI_BVALID = 0;
      
      {{ thread.name }}_{{ outstream.name }}_AXI_ARREADY = 0;
      {{ thread.name }}_{{ outstream.name }}_AXI_RVALID = 0;
      {{ thread.name }}_{{ outstream.name }}_AXI_RLAST = 0;
      
      if(!{{ thread.name }}_{{ outstream.name }}_AXI_write_mode && {{ thread.name }}_{{ outstream.name }}_AXI_AWVALID) begin
        {{ thread.name }}_{{ outstream.name }}_stall_count <= {{ thread.name }}_{{ outstream.name }}_stall_count + 1;
        if({{ thread.name }}_{{ outstream.name }}_stall_count == WRITE_LATENCY) begin
          {{ thread.name }}_{{ outstream.name }}_stall_count <= 0;
          {{ thread.name }}_{{ outstream.name }}_AXI_write_mode <= 1;
          {{ thread.name }}_{{ outstream.name }}_AXI_AWREADY = 1;
          d_{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR = {{ thread.name }}_{{ outstream.name }}_AXI_AWADDR;
          d_{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN = {{ thread.name }}_{{ outstream.name }}_AXI_AWLEN;
        end
      end

      if(!{{ thread.name }}_{{ outstream.name }}_AXI_read_mode && {{ thread.name }}_{{ outstream.name }}_AXI_ARVALID) begin
        {{ thread.name }}_{{ outstream.name }}_stall_count <= {{ thread.name }}_{{ outstream.name }}_stall_count + 1;
        if({{ thread.name }}_{{ outstream.name }}_stall_count == READ_LATENCY) begin
          {{ thread.name }}_{{ outstream.name }}_stall_count <= 0;
          {{ thread.name }}_{{ outstream.name }}_AXI_read_mode <= 1;
          {{ thread.name }}_{{ outstream.name }}_AXI_ARREADY = 1;
          d_{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR = {{ thread.name }}_{{ outstream.name }}_AXI_ARADDR;
          d_{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN = {{ thread.name }}_{{ outstream.name }}_AXI_ARLEN;
        end
      end
      
      if({{ thread.name }}_{{ outstream.name }}_AXI_write_mode) begin
        {{ thread.name }}_{{ outstream.name }}_AXI_WREADY = 1;
        if({{ thread.name }}_{{ outstream.name }}_AXI_WVALID) begin
          mem_write_{{ thread.name }}_{{ outstream.name }}(d_{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR, C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ outstream.name }}_AXI_WDATA);
          if(d_{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN == 0 || {{ thread.name }}_{{ outstream.name }}_AXI_WLAST) begin // actual burst length -1
            {{ thread.name }}_{{ outstream.name }}_AXI_write_mode <= 0;
            {{ thread.name }}_{{ outstream.name }}_AXI_BVALID = 1;
          end
          d_{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR = d_{{ thread.name }}_{{ outstream.name }}_AXI_AWADDR + (C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN = d_{{ thread.name }}_{{ outstream.name }}_AXI_AWLEN - 1;
        end
      end

      if({{ thread.name }}_{{ outstream.name }}_AXI_read_mode) begin
        mem_read_{{ thread.name }}_{{ outstream.name }}(d_{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR, C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH/8, {{ thread.name }}_{{ outstream.name }}_AXI_RDATA);
        {{ thread.name }}_{{ outstream.name }}_AXI_RVALID = 1;
        if(d_{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN == 0) begin // actual burst length -1
          {{ thread.name }}_{{ outstream.name }}_AXI_RLAST = 1;
          if({{ thread.name }}_{{ outstream.name }}_AXI_RREADY) begin
            {{ thread.name }}_{{ outstream.name }}_AXI_read_mode <= 0;
          end
        end
        if({{ thread.name }}_{{ outstream.name }}_AXI_RREADY) begin
          d_{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR = d_{{ thread.name }}_{{ outstream.name }}_AXI_ARADDR + (C_{{ thread.name }}_{{ outstream.name }}_AXI_DATA_WIDTH / 8);
          d_{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN = d_{{ thread.name }}_{{ outstream.name }}_AXI_ARLEN - 1;
        end
      end

    end
  end
{% endfor %}
{%- endfor %}

endmodule

