#!/bin/bash
#-------------------------------------------------------------------------------
# Copyright (c) 2018 by Ando Ki (andoki@gmail.com)
#-------------------------------------------------------------------------------
# gen_ahb_top.sh -- Top-level generator for AMBA AHB system
#-------------------------------------------------------------------------------
# VERSION: 2018.07.19.
#-------------------------------------------------------------------------------
SHELL=/bin/bash

#-------------------------------------------------------------------------------
NUM_MST=2
NUM_SLV=2
NUM_BYTES=1024
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 "      -siz    bytes      :size of each slave in bytes, ${NUM_BYTES}"
   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
            ;;
      -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
#-------------------------------------------------------------------------------
NAME_BUS="amba_ahb_m${NUM_MST}s${NUM_SLV}"
#-------------------------------------------------------------------------------
set -o errexit
exec 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
\`define SIZE_IN_BYTES $NUM_BYTES
\`endif

module top;
   //---------------------------------------------------------------------------
   localparam NUM_MST=${NUM_MST}
            , NUM_SLV=${NUM_SLV};
   //---------------------------------------------------------------------------
EOT
   cnt_slv=0;
   startX=0;
   sizeX=`echo "ibase=10;obase=16;${NUM_BYTES}"|bc`
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
       startX=`echo "ibase=10;obase=16;$[${cnt_slv}*${NUM_BYTES}]"|bc`
echo "   localparam  P_HSEL${cnt_slv}_START=32'h${startX},P_HSEL${cnt_slv}_SIZE=32'h${sizeX};"
       cnt_slv=$[${cnt_slv}+1]
   done
cat << EOT
   //---------------------------------------------------------------------------
   localparam CLK_PERIOD_HALF=1_000_000_000/(\`CLK_FREQ*2);
   reg         HCLK   = 1'b0; always #(CLK_PERIOD_HALF) HCLK=~HCLK;
   reg         HRESETn= 1'b0; initial #155 HRESETn=1'b1;
   //---------------------------------------------------------------------------
   wire [NUM_MST-1:0] \`BUS_DELAY M_HBUSREQ ;
   wire [NUM_MST-1:0] \`BUS_DELAY M_HGRANT  ;
   wire [31:0]        \`BUS_DELAY M_HADDR  [0:NUM_MST-1];
   wire [ 3:0]        \`BUS_DELAY M_HPROT  [0:NUM_MST-1];
   wire               \`BUS_DELAY M_HLOCK  [0:NUM_MST-1];
   wire [ 1:0]        \`BUS_DELAY M_HTRANS [0:NUM_MST-1];
   wire               \`BUS_DELAY M_HWRITE [0:NUM_MST-1];
   wire [ 2:0]        \`BUS_DELAY M_HSIZE  [0:NUM_MST-1];
   wire [ 2:0]        \`BUS_DELAY M_HBURST [0:NUM_MST-1];
   wire [31:0]        \`BUS_DELAY M_HWDATA [0:NUM_MST-1];
   wire [31:0]        \`BUS_DELAY M_HRDATA  ;
   wire [ 1:0]        \`BUS_DELAY M_HRESP   ;
   wire               \`BUS_DELAY M_HREADY  ;
   //---------------------------------------------------------------------------
   wire [31:0]        \`BUS_DELAY S_HADDR    ;
   wire [ 3:0]        \`BUS_DELAY S_HPROT    ;
   wire [ 1:0]        \`BUS_DELAY S_HTRANS   ;
   wire               \`BUS_DELAY S_HWRITE   ;
   wire [ 2:0]        \`BUS_DELAY S_HSIZE    ;
   wire [ 2:0]        \`BUS_DELAY S_HBURST   ;
   wire [31:0]        \`BUS_DELAY S_HWDATA   ;
   wire [31:0]        \`BUS_DELAY S_HRDATA [0:NUM_SLV-1];
   wire [ 1:0]        \`BUS_DELAY S_HRESP  [0:NUM_SLV-1];
   wire               \`BUS_DELAY S_HREADY   ;
   wire               \`BUS_DELAY S_HREADYout[0:NUM_SLV-1];
   wire [15:0]        \`BUS_DELAY S_HSPLIT   [0:NUM_SLV-1];
   wire [NUM_SLV-1:0] \`BUS_DELAY S_HSEL     ;
   wire [ 3:0]        \`BUS_DELAY S_HMASTER  ;
   wire               \`BUS_DELAY S_HMASTLOCK;
   //---------------------------------------------------------------------------
   ${NAME_BUS} #(.P_NUMM(NUM_MST) // num of masters
                  ,.P_NUMS(NUM_SLV) // num of slaves
EOT
   cnt_slv=0;
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
echo "                  ,.P_HSEL${cnt_slv}_START(P_HSEL${cnt_slv}_START),.P_HSEL${cnt_slv}_SIZE(P_HSEL${cnt_slv}_SIZE)"
       cnt_slv=$[${cnt_slv}+1]
   done
echo "           )"
echo "   u_amba_ahb  ("
echo "        .HRESETn      (HRESETn     )"
echo "      , .HCLK         (HCLK        )"
   cnt_mst=0;
   while [ ${cnt_mst} -lt ${NUM_MST} ]; do
echo "      , .M${cnt_mst}_HBUSREQ  (M_HBUSREQ [${cnt_mst}])"
echo "      , .M${cnt_mst}_HGRANT   (M_HGRANT  [${cnt_mst}])"
echo "      , .M${cnt_mst}_HADDR    (M_HADDR   [${cnt_mst}])"
echo "      , .M${cnt_mst}_HTRANS   (M_HTRANS  [${cnt_mst}])"
echo "      , .M${cnt_mst}_HSIZE    (M_HSIZE   [${cnt_mst}])"
echo "      , .M${cnt_mst}_HBURST   (M_HBURST  [${cnt_mst}])"
echo "      , .M${cnt_mst}_HPROT    (M_HPROT   [${cnt_mst}])"
echo "      , .M${cnt_mst}_HLOCK    (M_HLOCK   [${cnt_mst}])"
echo "      , .M${cnt_mst}_HWRITE   (M_HWRITE  [${cnt_mst}])"
echo "      , .M${cnt_mst}_HWDATA   (M_HWDATA  [${cnt_mst}])"
       cnt_mst=$[${cnt_mst}+1]
   done
echo "      , .M_HRDATA    (M_HRDATA     )"
echo "      , .M_HRESP     (M_HRESP      )"
echo "      , .M_HREADY    (M_HREADY     )"
echo "      , .S_HADDR     (S_HADDR      )"
echo "      , .S_HWRITE    (S_HWRITE     )"
echo "      , .S_HTRANS    (S_HTRANS     )"
echo "      , .S_HSIZE     (S_HSIZE      )"
echo "      , .S_HBURST    (S_HBURST     )"
echo "      , .S_HWDATA    (S_HWDATA     )"
echo "      , .S_HPROT     (S_HPROT      )"
echo "      , .S_HREADY    (S_HREADY     )"
echo "      , .S_HMASTER   (S_HMASTER    )"
echo "      , .S_HMASTLOCK (S_HMASTLOCK  )"
   cnt_slv=0;
   while [ ${cnt_slv} -lt ${NUM_SLV} ]; do
echo "      , .S${cnt_slv}_HSEL     (S_HSEL     [${cnt_slv}])"
echo "      , .S${cnt_slv}_HREADY   (S_HREADYout[${cnt_slv}])"
echo "      , .S${cnt_slv}_HRESP    (S_HRESP    [${cnt_slv}])"
echo "      , .S${cnt_slv}_HRDATA   (S_HRDATA   [${cnt_slv}])"
echo "      , .S${cnt_slv}_HSPLIT   (S_HSPLIT   [${cnt_slv}])"
       cnt_slv=$[${cnt_slv}+1]
   done
echo "      , .REMAP       (1'b0          )"
echo "   );"
cat << EOT
   //---------------------------------------------------------------------------
   wire [NUM_MST-1:0] done;
   //---------------------------------------------------------------------------
   generate
   genvar idx;
   for (idx=0; idx<NUM_MST; idx=idx+1) begin : BLK_MST
        ahb_tester #(.P_MST_ID(idx)
                    ,.P_NUM_MST(NUM_MST)
                    ,.P_NUM_SLV(NUM_SLV)
                    ,.P_SIZE_IN_BYTES(\`SIZE_IN_BYTES))
        u_tester (
              .HRESETn (HRESETn       )
            , .HCLK    (HCLK          )
            , .HBUSREQ (M_HBUSREQ[idx])
            , .HGRANT  (M_HGRANT [idx])
            , .HADDR   (M_HADDR  [idx])
            , .HPROT   (M_HPROT  [idx])
            , .HLOCK   (M_HLOCK  [idx])
            , .HTRANS  (M_HTRANS [idx])
            , .HWRITE  (M_HWRITE [idx])
            , .HSIZE   (M_HSIZE  [idx])
            , .HBURST  (M_HBURST [idx])
            , .HWDATA  (M_HWDATA [idx])
            , .HRDATA  (M_HRDATA      )
            , .HRESP   (M_HRESP       )
            , .HREADY  (M_HREADY      )
        );
        assign done[idx] = BLK_MST[idx].u_tester.done;
   end // for
   endgenerate
   //---------------------------------------------------------------------------
   generate
   genvar idy;
   for (idy=0; idy<NUM_SLV; idy=idy+1) begin : BLK_SLV
        mem_ahb #(.P_SLV_ID(idy)
                 ,.P_SIZE_IN_BYTES(\`SIZE_IN_BYTES)
                 ,.P_DELAY(\`MEM_DELAY))
        u_mem_ahb (
              .HRESETn   (HRESETn  )
            , .HCLK      (HCLK     )
            , .HADDR     (S_HADDR  )
            , .HTRANS    (S_HTRANS )
            , .HWRITE    (S_HWRITE )
            , .HSIZE     (S_HSIZE  )
            , .HBURST    (S_HBURST )
            , .HWDATA    (S_HWDATA )
            , .HSEL      (S_HSEL      [idy])
            , .HRDATA    (S_HRDATA    [idy])
            , .HRESP     (S_HRESP     [idy])
            , .HREADYin  (S_HREADY         )
            , .HREADYout (S_HREADYout [idy])
        );
        assign  S_HSPLIT[idy] = 0;
   end // for
   endgenerate
   //---------------------------------------------------------------------------
   integer idz;
   initial begin
       wait(HRESETn==1'b0);
       wait(HRESETn==1'b1);
       for (idz=0; idz<NUM_MST; idz=idz+1) begin
            wait(done[idz]==1'b1);
       end
       repeat (5) @ (posedge HCLK);
       \$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

#-------------------------------------------------------------------------------
# Revision history:
#
# 2018.07.19: Started by Ando Ki (adki@future-ds.com)
#-------------------------------------------------------------------------------
