#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Copyright (c) 2018-2019-2021 by Ando Ki (andoki@gmail.com)
# This is licensed with the 2-clause BSD license to make the program and
# library useful in open and closed source products independent of their
# licensing scheme.
#-------------------------------------------------------------------------------
# gen_axi_top.sh -- Top-level generator for AMBA AXI system
#-------------------------------------------------------------------------------
# VERSION: 2021.06.01.
#-------------------------------------------------------------------------------
SHELL=/bin/bash

#-------------------------------------------------------------------------------
AXI4=1
NUM_MST=2
NUM_SLV=2
NUM_BYTES=0 # size of memory for each slave, i.e., memory
NAME_BUS=
FILE_OUT="top.v"

#-------------------------------------------------------------------------------
function func_help() {
   echo "Usage : $0 [options]"
   echo "      -mst    num        :num of masters, ${NUM_MST}"
   echo "      -slv    num        :num of slaves, i.e., memories, ${NUM_SLV}"
   echo "      -axi3              :force to use AXI3 (to use AXI4, not specify)"
   echo "      -siz    bytes      :size of each slave in bytes, ${NUM_BYTES}; 0 for auto"
   echo "      -bus    module     :name of bus, ${NAME_BUS}"
   echo "      -out    file_name  :output file name, ${FILE_OUT}"
   echo "      -h/-?              :printf help"
   echo ""
   echo    "Example: $ $0 -mst 2 -slv 2 -siz 1024 -out top.v"
   return 0
}

#-------------------------------------------------------------------------------
while [ "`echo $1|cut -c1`" = "-" ]; do
  case $1 in
      -mst) shift
            if [ ! "$1" ]; then
               echo "-mst needs option"
               func_help
               exit -1
            fi
            NUM_MST=$1
            ;;
      -slv) shift
            if [ ! "$1" ]; then
               echo "-slv needs option"
               func_help
               exit -1
            fi
            NUM_SLV=$1
            ;;
      -axi3) AXI4=0
             ;;
      -siz) shift
            if [ ! "$1" ]; then
               echo "-siz needs option"
               func_help
               exit -1
            fi
            NUM_BYTES=$1
            ;;
      -out) shift
            if [ ! "$1" ]; then
               echo "-out needs option"
               func_help
               exit -1
            fi
            FILE_OUT=$1
            ;;
      -h|-\?) func_help
              exit -1
              ;;
      *)      echo "Unknown option: $1"
              func_help
              exit -1
              ;;
  esac
  shift
done
if [ ! -z "$1" ]; then
   echo un-known options: $1
   exit 1
fi

#-------------------------------------------------------------------------------
function func_log2() {
    local x=0
    for (( y=$1-1 ; $y > 0; y >>= 1 )) ; do
        let x=$x+1
    done
    return $x # it is not return value, but error code
}

function func_is_power2() {
   local x=$1
   ((x>0 && ( x & x-1 ) == 0 ))
}

#-------------------------------------------------------------------------------
if [[ "${NUM_BYTES}" == "0" ]]; then
    if [ ${NUM_MST} -gt ${NUM_SLV} ]; then
        if [[ ${NUM_MST}%2 -eq 0 ]]; then
            let NUM_BYTES=1024*${NUM_MST}/${NUM_SLV}
        else
            let NUM_BYTES=(1024*${NUM_MST}+1024)/${NUM_SLV}
        fi
    else
        if [[ ${NUM_SLV}%2 -eq 0 ]]; then
            let NUM_BYTES=1024*${NUM_SLV}/${NUM_SLV}
        else
            let NUM_BYTES=(1024*${NUM_SLV}+1024)/${NUM_SLV}
        fi
    fi
fi

if ! func_is_power2 ${NUM_BYTES}; then
    func_log2 "${NUM_BYTES}"
    let na=$?
    let NUM_BYTES=$((2 ** ${na}))
fi

#-------------------------------------------------------------------------------
NAME_BUS="amba_axi_m${NUM_MST}s${NUM_SLV}"
#-------------------------------------------------------------------------------
set -o errexit
exec 3>&1 1>$FILE_OUT

cat << EOT
//------------------------------------------------------------------------------
// top.v generated by "gen_ahb_top.sh"
//------------------------------------------------------------------------------
\`timescale 1ns/1ns
\`ifndef CLK_FREQ
\`define CLK_FREQ       50000000
\`endif
\`ifdef __ICARUS__
\`define BUS_DELAY
\`else
\`ifndef BUS_DELAY
\`define BUS_DELAY #(1)
\`endif
\`endif
\`ifndef MEM_DELAY
\`define MEM_DELAY 0
\`endif
\`ifndef SIZE_IN_BYTES_PER_SLAVE
\`define SIZE_IN_BYTES_PER_SLAVE $NUM_BYTES
\`endif
\`ifndef SIZE_IN_BYTES_PER_MASTER
\`define SIZE_IN_BYTES_PER_MASTER (($NUM_BYTES*$NUM_SLV)/$NUM_MST)
\`endif
\`ifndef WIDTH_AD
\`define WIDTH_AD  32
\`endif
\`ifndef WIDTH_DA
\`define WIDTH_DA  32
\`endif
EOT

if [ ${AXI4} == 1 ]; then
    echo \`define AMBA_AXI4
fi

cat << EOT
module top;
   //---------------------------------------------------------------------------
   localparam NUM_MST=${NUM_MST}
            , NUM_SLV=${NUM_SLV};
   localparam WIDTH_CID   = \$clog2(NUM_MST) // Channel ID width in bits
            , WIDTH_ID    = 4    // ID width in bits
            , WIDTH_AD    =\`WIDTH_AD    // address width
            , WIDTH_DA    =\`WIDTH_DA    // data width
            , WIDTH_DS    =(WIDTH_DA/8)  // data strobe width
            , WIDTH_SID   =WIDTH_CID+WIDTH_ID // ID for slave
            \`ifdef AMBA_AXI_AWUSER
            , WIDTH_AWUSER=0  // Write-address user path
            \`endif
            \`ifdef AMBA_AXI_WUSER
            , WIDTH_WUSER =0  // Write-data user path
            \`endif
            \`ifdef AMBA_AXI_BUSER
            , WIDTH_BUSER =0  // Write-response user path
            \`endif
            \`ifdef AMBA_AXI_ARUSER
            , WIDTH_ARUSER=0  // read-address user path
            \`endif
            \`ifdef AMBA_AXI_RUSER
            , WIDTH_RUSER =0  // read-data user path
            \`endif
            ;
   //---------------------------------------------------------------------------
EOT
   eval cnt_slv=0
   eval startX=0
   eval sizeX=`echo "ibase=10;obase=16;${NUM_BYTES}"|bc`
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
       eval startX=`echo "ibase=10;obase=16;$[${cnt_slv}*${NUM_BYTES}]"|bc`
echo "   localparam [WIDTH_AD-1:0] ADDR_BASE${cnt_slv}='h${startX}; // address base for memory"
       eval cnt_slv=$[${cnt_slv}+1]
   done
echo "   localparam ADDR_LENGTH=\$clog2('h${sizeX}); // address length for each memory"
cat << EOT
   //---------------------------------------------------------------------------
   localparam CLK_PERIOD_HALF=1_000_000_000/(\`CLK_FREQ*2);
   reg         ACLK   = 1'b0; always #(CLK_PERIOD_HALF) ACLK=~ACLK;
   reg         ARESETn= 1'b0; initial #155 ARESETn=1'b1;
   //---------------------------------------------------------------------------
   wire  [WIDTH_ID-1:0]     \`BUS_DELAY M_AWID       [0:NUM_MST-1];
   wire  [WIDTH_AD-1:0]     \`BUS_DELAY M_AWADDR     [0:NUM_MST-1];
   \`ifdef AMBA_AXI4
   wire  [ 7:0]             \`BUS_DELAY M_AWLEN      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_AWLOCK     [0:NUM_MST-1];
   \`else
   wire  [ 3:0]             \`BUS_DELAY M_AWLEN      [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_AWLOCK     [0:NUM_MST-1];
   \`endif
   wire  [ 2:0]             \`BUS_DELAY M_AWSIZE     [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_AWBURST    [0:NUM_MST-1];
   \`ifdef AMBA_AXI_CACHE
   wire  [ 3:0]             \`BUS_DELAY M_AWCACHE    [0:NUM_MST-1];
   \`endif
   \`ifdef AMBA_AXI_PROT
   wire  [ 2:0]             \`BUS_DELAY M_AWPROT     [0:NUM_MST-1];
   \`endif
   wire                     \`BUS_DELAY M_AWVALID    [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_AWREADY    [0:NUM_MST-1];
   \`ifdef AMBA_QOS
   wire  [ 3:0]             \`BUS_DELAY M_AWQOS      [0:NUM_MST-1];
   wire  [ 3:0]             \`BUS_DELAY M_AWREGION   [0:NUM_MST-1];
   \`endif
   \`ifdef AMBA_AXI_AWUSER
   wire  [WIDTH_AWUSER-1:0] \`BUS_DELAY M_AWUSER     [0:NUM_MST-1];
   \`endif
EOT
if [ ${AXI4} == 0 ]; then
echo "   wire  [WIDTH_ID-1:0]     \`BUS_DELAY M_WID        [0:NUM_MST-1];"
fi
cat << EOT
   wire  [WIDTH_DA-1:0]     \`BUS_DELAY M_WDATA      [0:NUM_MST-1];
   wire  [WIDTH_DS-1:0]     \`BUS_DELAY M_WSTRB      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_WLAST      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_WVALID     [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_WREADY     [0:NUM_MST-1];
   \`ifdef AMBA_AXI_WUSER
   wire  [WIDTH_WUSER-1:0]  \`BUS_DELAY M_WUSER      [0:NUM_MST-1];
   \`endif
   wire  [WIDTH_ID-1:0]     \`BUS_DELAY M_BID        [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_BRESP      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_BVALID     [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_BREADY     [0:NUM_MST-1];
   \`ifdef AMBA_AXI_BUSER
   wire  [WIDTH_BUSER-1:0]  \`BUS_DELAY M_BUSER      [0:NUM_MST-1];
   \`endif
   wire  [WIDTH_ID-1:0]     \`BUS_DELAY M_ARID       [0:NUM_MST-1];
   wire  [WIDTH_AD-1:0]     \`BUS_DELAY M_ARADDR     [0:NUM_MST-1];
   \`ifdef AMBA_AXI4
   wire  [ 7:0]             \`BUS_DELAY M_ARLEN      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_ARLOCK     [0:NUM_MST-1];
   \`else
   wire  [ 3:0]             \`BUS_DELAY M_ARLEN      [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_ARLOCK     [0:NUM_MST-1];
   \`endif
   wire  [ 2:0]             \`BUS_DELAY M_ARSIZE     [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_ARBURST    [0:NUM_MST-1];
   \`ifdef AMBA_AXI_CACHE
   wire  [ 3:0]             \`BUS_DELAY M_ARCACHE    [0:NUM_MST-1];
   \`endif
   \`ifdef AMBA_AXI_PROT
   wire  [ 2:0]             \`BUS_DELAY M_ARPROT     [0:NUM_MST-1];
   \`endif
   wire                     \`BUS_DELAY M_ARVALID    [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_ARREADY    [0:NUM_MST-1];
   \`ifdef AMBA_QOS
   wire  [ 3:0]             \`BUS_DELAY M_ARQOS      [0:NUM_MST-1];
   wire  [ 3:0]             \`BUS_DELAY M_ARREGION   [0:NUM_MST-1];
   \`endif
   \`ifdef AMBA_AXI_ARUSER
   wire  [WIDTH_ARUSER-1:0] \`BUS_DELAY M_ARUSER     [0:NUM_MST-1];
   \`endif
   wire  [WIDTH_ID-1:0]     \`BUS_DELAY M_RID        [0:NUM_MST-1];
   wire  [WIDTH_DA-1:0]     \`BUS_DELAY M_RDATA      [0:NUM_MST-1];
   wire  [ 1:0]             \`BUS_DELAY M_RRESP      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_RLAST      [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_RVALID     [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_RREADY     [0:NUM_MST-1];
   \`ifdef AMBA_AXI_RUSER
   wire  [WIDTH_RUSER-1:0]  \`BUS_DELAY M_RUSER      [0:NUM_MST-1];
   \`endif
   wire                     \`BUS_DELAY M_CSYSREQ    [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_CSYSACK    [0:NUM_MST-1];
   wire                     \`BUS_DELAY M_CACTIVE    [0:NUM_MST-1];
   //------------------------------------------------------------------------
   wire  [WIDTH_SID-1:0]    \`BUS_DELAY S_AWID       [0:NUM_SLV-1];
   wire  [WIDTH_AD-1:0]     \`BUS_DELAY S_AWADDR     [0:NUM_SLV-1];
   \`ifdef AMBA_AXI4
   wire  [ 7:0]             \`BUS_DELAY S_AWLEN      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_AWLOCK     [0:NUM_SLV-1];
   \`else
   wire  [ 3:0]             \`BUS_DELAY S_AWLEN      [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_AWLOCK     [0:NUM_SLV-1];
   \`endif
   wire  [ 2:0]             \`BUS_DELAY S_AWSIZE     [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_AWBURST    [0:NUM_SLV-1];
   \`ifdef AMBA_AXI_CACHE
   wire  [ 3:0]             \`BUS_DELAY S_AWCACHE    [0:NUM_SLV-1];
   \`endif
   \`ifdef AMBA_AXI_PROT
   wire  [ 2:0]             \`BUS_DELAY S_AWPROT     [0:NUM_SLV-1];
   \`endif
   wire                     \`BUS_DELAY S_AWVALID    [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_AWREADY    [0:NUM_SLV-1];
   \`ifdef AMBA_QOS
   wire  [ 3:0]             \`BUS_DELAY S_AWQOS      [0:NUM_SLV-1];
   wire  [ 3:0]             \`BUS_DELAY S_AWREGION   [0:NUM_SLV-1];
   \`endif
   \`ifdef AMBA_AXI_AWUSER
   wire  [WIDTH_AWUSER-1:0] \`BUS_DELAY S_AWUSER     [0:NUM_SLV-1];
   \`endif
EOT
if [ ${AXI4} == 0 ]; then
echo "   wire  [WIDTH_SID-1:0]    \`BUS_DELAY S_WID        [0:NUM_SLV-1];"
fi
cat << EOT
   wire  [WIDTH_DA-1:0]     \`BUS_DELAY S_WDATA      [0:NUM_SLV-1];
   wire  [WIDTH_DS-1:0]     \`BUS_DELAY S_WSTRB      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_WLAST      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_WVALID     [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_WREADY     [0:NUM_SLV-1];
   \`ifdef AMBA_AXI_WUSER
   wire  [WIDTH_WUSER-1:0]  \`BUS_DELAY S_WUSER      [0:NUM_SLV-1];
   \`endif
   wire  [WIDTH_SID-1:0]    \`BUS_DELAY S_BID        [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_BRESP      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_BVALID     [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_BREADY     [0:NUM_SLV-1];
   \`ifdef AMBA_AXI_BUSER
   wire  [WIDTH_BUSER-1:0]  \`BUS_DELAY S_BUSER      [0:NUM_SLV-1];
   \`endif
   wire  [WIDTH_SID-1:0]    \`BUS_DELAY S_ARID       [0:NUM_SLV-1];
   wire  [WIDTH_AD-1:0]     \`BUS_DELAY S_ARADDR     [0:NUM_SLV-1];
   \`ifdef AMBA_AXI4
   wire  [ 7:0]             \`BUS_DELAY S_ARLEN      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_ARLOCK     [0:NUM_SLV-1];
   \`else
   wire  [ 3:0]             \`BUS_DELAY S_ARLEN      [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_ARLOCK     [0:NUM_SLV-1];
   \`endif
   wire  [ 2:0]             \`BUS_DELAY S_ARSIZE     [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_ARBURST    [0:NUM_SLV-1];
   \`ifdef AMBA_AXI_CACHE
   wire  [ 3:0]             \`BUS_DELAY S_ARCACHE    [0:NUM_SLV-1];
   \`endif
   \`ifdef AMBA_AXI_PROT
   wire  [ 2:0]             \`BUS_DELAY S_ARPROT     [0:NUM_SLV-1];
   \`endif
   wire                     \`BUS_DELAY S_ARVALID    [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_ARREADY    [0:NUM_SLV-1];
   \`ifdef AMBA_QOS
   wire  [ 3:0]             \`BUS_DELAY S_ARQOS      [0:NUM_SLV-1];
   wire  [ 3:0]             \`BUS_DELAY S_ARREGION   [0:NUM_SLV-1];
   \`endif
   \`ifdef AMBA_AXI_ARUSER
   wire  [WIDTH_ARUSER-1:0] \`BUS_DELAY S_ARUSER     [0:NUM_SLV-1];
   \`endif
   wire  [WIDTH_SID-1:0]    \`BUS_DELAY S_RID        [0:NUM_SLV-1];
   wire  [WIDTH_DA-1:0]     \`BUS_DELAY S_RDATA      [0:NUM_SLV-1];
   wire  [ 1:0]             \`BUS_DELAY S_RRESP      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_RLAST      [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_RVALID     [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_RREADY     [0:NUM_SLV-1];
   \`ifdef AMBA_AXI_RUSER
   wire  [WIDTH_RUSER-1:0]  \`BUS_DELAY S_RUSER      [0:NUM_SLV-1];
   \`endif
   wire                     \`BUS_DELAY S_CSYSREQ    [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_CSYSACK    [0:NUM_SLV-1];
   wire                     \`BUS_DELAY S_CACTIVE    [0:NUM_SLV-1];
   //---------------------------------------------------------------------------
   ${NAME_BUS} #(.NUM_MASTER  (${NUM_MST})
                ,.NUM_SLAVE   (${NUM_SLV})
                ,.WIDTH_ID    (WIDTH_ID    )
                ,.WIDTH_AD    (WIDTH_AD    )
                ,.WIDTH_DA    (WIDTH_DA    )
                ,.WIDTH_DS    (WIDTH_DS    )
                \`ifdef AMBA_AWUSER
                ,.WIDTH_AWUSER(WIDTH_AWUSER)
                \`endif
                \`ifdef AMBA_WUSER
                ,.WIDTH_WUSER (WIDTH_WUSER )
                \`endif
                \`ifdef AMBA_BUSER
                ,.WIDTH_BUSER (WIDTH_BUSER )
                \`endif
                \`ifdef AMBA_ARUSER
                ,.WIDTH_ARUSER(WIDTH_ARUSER)
                \`endif
                \`ifdef AMBA_RUSER
                ,.WIDTH_RUSER (WIDTH_RUSER )
                \`endif
EOT
   cnt_slv=0;
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
echo "                ,.ADDR_BASE${cnt_slv}  (ADDR_BASE${cnt_slv}), .ADDR_LENGTH${cnt_slv}(ADDR_LENGTH)"
       cnt_slv=$[${cnt_slv}+1]
   done
echo "                )"
echo "   u_amba_axi  ("
echo "          .ARESETn      (ARESETn     )"
echo "        , .ACLK         (ACLK        )"
   cnt_mst=0;
   while [ ${cnt_mst} -lt ${NUM_MST} ]; do
echo "        , .M${cnt_mst}_AWID              (M_AWID    [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWADDR            (M_AWADDR  [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWLEN             (M_AWLEN   [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWLOCK            (M_AWLOCK  [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWSIZE            (M_AWSIZE  [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWBURST           (M_AWBURST [${cnt_mst}])"
echo "        \`ifdef AMBA_AXI_CACHE"
echo "        , .M${cnt_mst}_AWCACHE           (M_AWCACHE [${cnt_mst}])"
echo "        \`endif"
echo "        \`ifdef AMBA_AXI_PROT"
echo "        , .M${cnt_mst}_AWPROT            (M_AWPROT  [${cnt_mst}])"
echo "        \`endif"
echo "        , .M${cnt_mst}_AWVALID           (M_AWVALID [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWREADY           (M_AWREADY [${cnt_mst}])"
echo "        \`ifdef AMBA_QOS"
echo "        , .M${cnt_mst}_AWQOS             (M_AWQOS   [${cnt_mst}])"
echo "        , .M${cnt_mst}_AWREGION          (M_AWREGION[${cnt_mst}])"
echo "        \`endif"
echo "        \`ifdef AMBA_AXI_AWUSER"
echo "        , .M${cnt_mst}_AWUSER            (M_AWUSER  [${cnt_mst}])"
echo "        \`endif"
if [ ${AXI4} == 0 ]; then
echo "        , .M${cnt_mst}_WID               (M_WID     [${cnt_mst}])"
fi
echo "        , .M${cnt_mst}_WDATA             (M_WDATA   [${cnt_mst}])"
echo "        , .M${cnt_mst}_WSTRB             (M_WSTRB   [${cnt_mst}])"
echo "        , .M${cnt_mst}_WLAST             (M_WLAST   [${cnt_mst}])"
echo "        , .M${cnt_mst}_WVALID            (M_WVALID  [${cnt_mst}])"
echo "        , .M${cnt_mst}_WREADY            (M_WREADY  [${cnt_mst}])"
echo "        \`ifdef AMBA_AXI_WUSER"
echo "        , .M${cnt_mst}_WUSER             (M_WUSER   [${cnt_mst}])"
echo "        \`endif"
echo "        , .M${cnt_mst}_BID               (M_BID     [${cnt_mst}])"
echo "        , .M${cnt_mst}_BRESP             (M_BRESP   [${cnt_mst}])"
echo "        , .M${cnt_mst}_BVALID            (M_BVALID  [${cnt_mst}])"
echo "        , .M${cnt_mst}_BREADY            (M_BREADY  [${cnt_mst}])"
echo "        \`ifdef AMBA_AXI_BUSER"
echo "        , .M${cnt_mst}_BUSER             (M_BUSER   [${cnt_mst}])"
echo "        \`endif"
echo "        , .M${cnt_mst}_ARID              (M_ARID    [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARADDR            (M_ARADDR  [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARLEN             (M_ARLEN   [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARLOCK            (M_ARLOCK  [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARSIZE            (M_ARSIZE  [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARBURST           (M_ARBURST [${cnt_mst}])"
echo "        \`ifdef AMBA_AXI_CACHE"
echo "        , .M${cnt_mst}_ARCACHE           (M_ARCACHE [${cnt_mst}])"
echo "        \`endif"
echo "        \`ifdef AMBA_AXI_PROT"
echo "        , .M${cnt_mst}_ARPROT            (M_ARPROT  [${cnt_mst}])"
echo "        \`endif"
echo "        , .M${cnt_mst}_ARVALID           (M_ARVALID [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARREADY           (M_ARREADY [${cnt_mst}])"
echo "        \`ifdef AMBA_QOS"
echo "        , .M${cnt_mst}_ARQOS             (M_ARQOS   [${cnt_mst}])"
echo "        , .M${cnt_mst}_ARREGION          (M_ARREGION[${cnt_mst}])"
echo "        \`endif"
echo "        \`ifdef AMBA_AXI_ARUSER"
echo "        , .M${cnt_mst}_ARUSER            (M_ARUSER  [${cnt_mst}])"
echo "        \`endif"
echo "        , .M${cnt_mst}_RID               (M_RID     [${cnt_mst}])"
echo "        , .M${cnt_mst}_RDATA             (M_RDATA   [${cnt_mst}])"
echo "        , .M${cnt_mst}_RRESP             (M_RRESP   [${cnt_mst}])"
echo "        , .M${cnt_mst}_RLAST             (M_RLAST   [${cnt_mst}])"
echo "        , .M${cnt_mst}_RVALID            (M_RVALID  [${cnt_mst}])"
echo "        , .M${cnt_mst}_RREADY            (M_RREADY  [${cnt_mst}])"
echo "        \`ifdef AMBA_AXI_RUSER"
echo "        , .M${cnt_mst}_RUSER             (M_RUSER   [${cnt_mst}])"
echo "        \`endif"
       cnt_mst=$[${cnt_mst}+1]
   done
   cnt_slv=0;
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
echo "         , .S${cnt_slv}_AWID              (S_AWID    [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWADDR            (S_AWADDR  [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWLEN             (S_AWLEN   [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWLOCK            (S_AWLOCK  [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWSIZE            (S_AWSIZE  [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWBURST           (S_AWBURST [${cnt_slv}])"
echo "         \`ifdef AMBA_AXI_CACHE"
echo "         , .S${cnt_slv}_AWCACHE           (S_AWCACHE [${cnt_slv}])"
echo "         \`endif"
echo "         \`ifdef AMBA_AXI_PROT"
echo "         , .S${cnt_slv}_AWPROT            (S_AWPROT  [${cnt_slv}])"
echo "         \`endif"
echo "         , .S${cnt_slv}_AWVALID           (S_AWVALID [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWREADY           (S_AWREADY [${cnt_slv}])"
echo "         \`ifdef AMBA_QOS"
echo "         , .S${cnt_slv}_AWQOS             (S_AWQOS   [${cnt_slv}])"
echo "         , .S${cnt_slv}_AWREGION          (S_AWREGION[${cnt_slv}])"
echo "         \`endif"
echo "         \`ifdef AMBA_AXI_AWUSER"
echo "         , .S${cnt_slv}_AWUSER            (S_AWUSER  [${cnt_slv}])"
echo "         \`endif"
if [ ${AXI4} == 0 ]; then
echo "         , .S${cnt_slv}_WID               (S_WID     [${cnt_slv}])"
fi
echo "         , .S${cnt_slv}_WDATA             (S_WDATA   [${cnt_slv}])"
echo "         , .S${cnt_slv}_WSTRB             (S_WSTRB   [${cnt_slv}])"
echo "         , .S${cnt_slv}_WLAST             (S_WLAST   [${cnt_slv}])"
echo "         , .S${cnt_slv}_WVALID            (S_WVALID  [${cnt_slv}])"
echo "         , .S${cnt_slv}_WREADY            (S_WREADY  [${cnt_slv}])"
echo "         \`ifdef AMBA_AXI_WUSER"
echo "         , .S${cnt_slv}_WUSER             (S_WUSER   [${cnt_slv}])"
echo "         \`endif"
echo "         , .S${cnt_slv}_BID               (S_BID     [${cnt_slv}])"
echo "         , .S${cnt_slv}_BRESP             (S_BRESP   [${cnt_slv}])"
echo "         , .S${cnt_slv}_BVALID            (S_BVALID  [${cnt_slv}])"
echo "         , .S${cnt_slv}_BREADY            (S_BREADY  [${cnt_slv}])"
echo "         \`ifdef AMBA_AXI_BUSER"
echo "         , .S${cnt_slv}_BUSER             (S_BUSER   [${cnt_slv}])"
echo "         \`endif"
echo "         , .S${cnt_slv}_ARID              (S_ARID    [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARADDR            (S_ARADDR  [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARLEN             (S_ARLEN   [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARLOCK            (S_ARLOCK  [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARSIZE            (S_ARSIZE  [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARBURST           (S_ARBURST [${cnt_slv}])"
echo "         \`ifdef AMBA_AXI_CACHE"
echo "         , .S${cnt_slv}_ARCACHE           (S_ARCACHE [${cnt_slv}])"
echo "         \`endif"
echo "         \`ifdef AMBA_AXI_PROT"
echo "         , .S${cnt_slv}_ARPROT            (S_ARPROT  [${cnt_slv}])"
echo "         \`endif"
echo "         , .S${cnt_slv}_ARVALID           (S_ARVALID [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARREADY           (S_ARREADY [${cnt_slv}])"
echo "         \`ifdef AMBA_QOS"
echo "         , .S${cnt_slv}_ARQOS             (S_ARQOS   [${cnt_slv}])"
echo "         , .S${cnt_slv}_ARREGION          (S_ARREGION[${cnt_slv}])"
echo "         \`endif"
echo "         \`ifdef AMBA_AXI_ARUSER"
echo "         , .S${cnt_slv}_ARUSER            (S_ARUSER  [${cnt_slv}])"
echo "         \`endif"
echo "         , .S${cnt_slv}_RID               (S_RID     [${cnt_slv}])"
echo "         , .S${cnt_slv}_RDATA             (S_RDATA   [${cnt_slv}])"
echo "         , .S${cnt_slv}_RRESP             (S_RRESP   [${cnt_slv}])"
echo "         , .S${cnt_slv}_RLAST             (S_RLAST   [${cnt_slv}])"
echo "         , .S${cnt_slv}_RVALID            (S_RVALID  [${cnt_slv}])"
echo "         , .S${cnt_slv}_RREADY            (S_RREADY  [${cnt_slv}])"
echo "         \`ifdef AMBA_AXI_RUSER"
echo "         , .S${cnt_slv}_RUSER             (S_RUSER   [${cnt_slv}])"
echo "         \`endif"
       cnt_slv=$[${cnt_slv}+1]
   done
echo "   );"
cat << EOT
   //---------------------------------------------------------------------------
   wire [NUM_MST-1:0]      done;
   wire [NUM_MST-1:0]      busy_out;
   wire               #(1) busy_in=|busy_out;
   //---------------------------------------------------------------------------
   generate
   genvar idx;
   for (idx=0; idx<NUM_MST; idx=idx+1) begin : BLK_MST
        axi_tester #(.P_MST_ID(idx)
                    ,.P_NUM_MST(NUM_MST)
                    ,.P_NUM_SLV(NUM_SLV)
                    ,.P_SIZE_IN_BYTES(\`SIZE_IN_BYTES_PER_MASTER)
                    ,.WIDTH_CID(WIDTH_CID)
                    ,.WIDTH_ID (WIDTH_ID ) // ID width in bits
                    ,.WIDTH_AD (WIDTH_AD ) // address width
                    ,.WIDTH_DA (WIDTH_DA ))// data width
        u_tester (
              .ARESETn   (ARESETn      )
            , .ACLK      (ACLK         )
            , .AWID      (M_AWID    [idx])
            , .AWADDR    (M_AWADDR  [idx])
            , .AWLEN     (M_AWLEN   [idx])
            , .AWLOCK    (M_AWLOCK  [idx])
            , .AWSIZE    (M_AWSIZE  [idx])
            , .AWBURST   (M_AWBURST [idx])
            \`ifdef AMBA_AXI_CACHE
            , .AWCACHE   (M_AWCACHE [idx])
            \`endif
            \`ifdef AMBA_AXI_PROT
            , .AWPROT    (M_AWPROT  [idx])
            \`endif
            , .AWVALID   (M_AWVALID [idx])
            , .AWREADY   (M_AWREADY [idx])
            \`ifdef AMBA_QOS
            , .AWQOS     (M_AWQOS   [idx])
            , .AWREGION  (M_AWREGION[idx])
            \`endif
EOT
if [ ${AXI4} == 0 ]; then
echo "   , .WID       (M_WID     [idx])"
fi
cat << EOT
            , .WDATA     (M_WDATA   [idx])
            , .WSTRB     (M_WSTRB   [idx])
            , .WLAST     (M_WLAST   [idx])
            , .WVALID    (M_WVALID  [idx])
            , .WREADY    (M_WREADY  [idx])
            , .BID       (M_BID     [idx])
            , .BRESP     (M_BRESP   [idx])
            , .BVALID    (M_BVALID  [idx])
            , .BREADY    (M_BREADY  [idx])
            , .ARID      (M_ARID    [idx])
            , .ARADDR    (M_ARADDR  [idx])
            , .ARLEN     (M_ARLEN   [idx])
            , .ARLOCK    (M_ARLOCK  [idx])
            , .ARSIZE    (M_ARSIZE  [idx])
            , .ARBURST   (M_ARBURST [idx])
            \`ifdef AMBA_AXI_CACHE
            , .ARCACHE   (M_ARCACHE [idx])
            \`endif
            \`ifdef AMBA_AXI_PROT
            , .ARPROT    (M_ARPROT  [idx])
            \`endif
            , .ARVALID   (M_ARVALID [idx])
            , .ARREADY   (M_ARREADY [idx])
            \`ifdef AMBA_QOS
            , .ARQOS     (M_ARQOS   [idx])
            , .ARREGION  (M_ARREGION[idx])
            \`endif
            , .RID       (M_RID     [idx])
            , .RDATA     (M_RDATA   [idx])
            , .RRESP     (M_RRESP   [idx])
            , .RLAST     (M_RLAST   [idx])
            , .RVALID    (M_RVALID  [idx])
            , .RREADY    (M_RREADY  [idx])
            , .CSYSREQ   (M_CSYSREQ [idx])
            , .CSYSACK   (M_CSYSACK [idx])
            , .CACTIVE   (M_CACTIVE [idx])
            , .busy_out(busy_out[idx])
            , .busy_in (busy_in      )
        );
        assign done[idx] = BLK_MST[idx].u_tester.done;
        assign M_CSYSREQ[idx] = 1'b0;
   end // for
   endgenerate
EOT

echo "   //---------------------------------------------------------------------------\n"
echo "   initial begin"
   eval cnt_slv=0
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
echo "        \$display(\"mem_axi ${cnt_slv} A=0x%08X ~ %08X\", ADDR_BASE${cnt_slv}, ADDR_BASE${cnt_slv}+(1<<ADDR_LENGTH)-1);"
       eval cnt_slv=$[${cnt_slv}+1]
   done
echo "    end"

cat << EOT
   //---------------------------------------------------------------------------
   generate
   genvar idy;
   for (idy=0; idy<NUM_SLV; idy=idy+1) begin : BLK_SLV
      //mem_axi #(.P_SLV_ID(idy)
      //         ,.P_SIZE_IN_BYTES(\`SIZE_IN_BYTES_PER_SLAVE)
      //         ,.P_DELAY(\`MEM_DELAY)
      //         ,.WIDTH_CID  (WIDTH_CID)// Channel ID width in bits
      //         ,.WIDTH_ID   (WIDTH_ID )// ID width in bits
      //         ,.WIDTH_AD   (WIDTH_AD )// address width
      //         ,.WIDTH_DA   (WIDTH_DA )// data width
      //         ,.WIDTH_DS   (WIDTH_DS )// data strobe width
      //         ,.ADDR_LENGTH(ADDR_LENGTH)) // effective addre bits"
        mem_axi #(.AXI_WIDTH_CID  (WIDTH_CID)// Channel ID width in bits
                 ,.AXI_WIDTH_ID   (WIDTH_ID )// ID width in bits
                 ,.AXI_WIDTH_AD   (WIDTH_AD )// address width
                 ,.AXI_WIDTH_DA   (WIDTH_DA )// data width
                 ,.AXI_WIDTH_DS   (WIDTH_DS )// data strobe width
                 ,.SIZE_IN_BYTES  (\`SIZE_IN_BYTES_PER_SLAVE)
                 ,.ID             (idy))
        u_mem_axi (
               .ARESETn  (ARESETn         )
             , .ACLK     (ACLK            )
             , .AWID     (S_AWID     [idy])
             , .AWADDR   (S_AWADDR   [idy])
             , .AWLEN    (S_AWLEN    [idy])
             , .AWLOCK   (S_AWLOCK   [idy])
             , .AWSIZE   (S_AWSIZE   [idy])
             , .AWBURST  (S_AWBURST  [idy])
             \`ifdef AMBA_AXI_CACHE
             , .AWCACHE  (S_AWCACHE  [idy])
             \`endif
             \`ifdef AMBA_AXI_PROT
             , .AWPROT   (S_AWPROT   [idy])
             \`endif
             , .AWVALID  (S_AWVALID  [idy])
             , .AWREADY  (S_AWREADY  [idy])
             \`ifdef AMBA_QOS
             , .AWQOS    (S_AWQOS    [idy])
             , .AWREGION (S_AWREGION [idy])
             \`endif
EOT
if [ ${AXI4} == 0 ]; then
echo "   , .WID      (S_WID      [idy])"
fi
cat << EOT
             , .WDATA    (S_WDATA    [idy])
             , .WSTRB    (S_WSTRB    [idy])
             , .WLAST    (S_WLAST    [idy])
             , .WVALID   (S_WVALID   [idy])
             , .WREADY   (S_WREADY   [idy])
             , .BID      (S_BID      [idy])
             , .BRESP    (S_BRESP    [idy])
             , .BVALID   (S_BVALID   [idy])
             , .BREADY   (S_BREADY   [idy])
             , .ARID     (S_ARID     [idy])
             , .ARADDR   (S_ARADDR   [idy])
             , .ARLEN    (S_ARLEN    [idy])
             , .ARLOCK   (S_ARLOCK   [idy])
             , .ARSIZE   (S_ARSIZE   [idy])
             , .ARBURST  (S_ARBURST  [idy])
             \`ifdef AMBA_AXI_CACHE
             , .ARCACHE  (S_ARCACHE  [idy])
             \`endif
             \`ifdef AMBA_AXI_PROT
             , .ARPROT   (S_ARPROT   [idy])
             \`endif
             , .ARVALID  (S_ARVALID  [idy])
             , .ARREADY  (S_ARREADY  [idy])
             \`ifdef AMBA_QOS 
             , .ARQOS    (S_ARQOS    [idy])
             , .ARREGION (S_ARREGION [idy])
             \`endif
             , .RID      (S_RID      [idy])
             , .RDATA    (S_RDATA    [idy])
             , .RRESP    (S_RRESP    [idy])
             , .RLAST    (S_RLAST    [idy])
             , .RVALID   (S_RVALID   [idy])
             , .RREADY   (S_RREADY   [idy])
           //, .CSYSREQ  (S_CSYSREQ  [idy])
             , .CSYSREQ  (&done)
             , .CSYSACK  (S_CSYSACK  [idy])
             , .CACTIVE  (S_CACTIVE  [idy])
        );
        assign  S_CSYSREQ[idy] = 1'b0;
   end // for
   endgenerate
   //---------------------------------------------------------------------------
   integer idz;
   initial begin
       wait(ARESETn==1'b0);
       wait(ARESETn==1'b1);
       for (idz=0; idz<NUM_MST; idz=idz+1) begin
            wait(done[idz]==1'b1);
       end
       //for (idz=0; idz<NUM_SLV; idz=idz+1) begin
       //     BLK_SLV[idz].u_mem_axi.axi_statistics(idz);
       //end
       repeat (5) @ (posedge ACLK);
       \$finish(2);
   end
   //---------------------------------------------------------------------------
   initial begin
      \`ifdef VCD
          // use +define+VCD in 'vlog'
          \$dumpfile("wave.vcd");
          \$dumpvars(0);
      \`else
           // use +VCD in 'vsim'
           if (\$test\$plusargs("VCD")) begin
               \$dumpfile("wave.vcd");
               \$dumpvars(5);
           end
      \`endif
   end
   //---------------------------------------------------------------------------
endmodule
EOT
exec 1>&3 3>&-

#-------------------------------------------------------------------------------
# Revision history:
#
# 2021.09.05: 'clogb2()' replace with '$clog2()'
# 2021.06.01: 'axi3' option added
# 2019.06.20: AMBA_AXI_AW/W/B/AR/RUSER
# 2018.07.19: Started by Ando Ki (adki@future-ds.com)
#-------------------------------------------------------------------------------
