#include "tsar_cluster_v1.h"

#define DIRECT_TRACE
#define COHERENCE_TRACE

namespace soclib {
  namespace caba {

    template<typename vci_param, size_t cmd_width, size_t rsp_width>
    TsarClusterV1<vci_param, cmd_width, rsp_width>::TsarClusterV1(
      sc_module_name nm,

      // Cluster Index
      int cluster_idx,

      // Dspin Routers parameters
      int infifo_depth,
      int outfifo_depth,
      int x_local,
      int y_local,

      // Bits for global routing
      size_t x_width,
      size_t y_width,

      // Mapping tables
      const MappingTable & md,
      const MappingTable & mc,
      const MappingTable & mx,

      // Processor Number
      size_t nprocs,
      size_t max_nprocs,
     
      // Cache L1 sizes
      size_t iways,
      size_t isets,
      size_t iwords,
      size_t dways,
      size_t dsets,
      size_t dwords,

      // MemCache sizes
      size_t mcways,
      size_t mcsets,
      size_t mcwords,

      int    is_io,

      Loader & loader
    ) : soclib::caba::BaseModule(nm),
        m_nprocs(nprocs)
    {
      std::ostringstream sd;
      sd << "ringd_" << x_local << "_" << y_local;
      ringd = new VciSimpleRingFast<vci_param, cmd_width, rsp_width> (
        sd.str().c_str(),
        md,                               // Direct Mapping Table
        IntTab(),                         // Cluster index
        2,                                // Wrapper fifo depth
        nprocs,                           // Number of initiators
        2 + is_io                         // Number of targets
      );

#ifdef DEBUG_TSAR_CLUSTER_V1
      std::cout << ringd->name() << " instantiated" << std::endl;
#endif

      std::ostringstream sc;
      sc << "ringc_" << x_local << "_" << y_local;
      ringc = new VciSimpleRingFast<vci_param, cmd_width, rsp_width> (
        sc.str().c_str(),
        mc,                               // Direct Mapping Table
        IntTab(),                         // Cluster index
        2,                                // Wrapper fifo depth
        nprocs + 1,                       // Number of initiators
        max_nprocs + 1                    // Number of targets
      );

#ifdef DEBUG_TSAR_CLUSTER_V1
      std::cout << ringc->name() << " instantiated" << std::endl;
#endif

      proc_iss::set_loader(loader);
      procs = new VciCcXCacheWrapperV1<vci_param, proc_iss> * [nprocs];
      for(size_t p=0; p < nprocs; p++) {
        std::ostringstream sp;
        sp << "proc_" << x_local << "_" << y_local << "_" << p;

        procs[p] = new VciCcXCacheWrapperV1<vci_param, proc_iss> (
          sp.str().c_str(),
          p + nprocs*cluster_idx,         // Processor Id
          md, mc,                         // Mapping Tables
          IntTab(p),                      // SRCID_D
          IntTab(p),                      // SRCID_C
          IntTab(p),                      // TGTID_C
          iways, isets, iwords,           // ICache Size
          dways, dsets, dwords,           // DCache Size
          x_width, y_width, max_nprocs    // Coherence Parameters
        );
    
#ifdef DEBUG_TSAR_CLUSTER_V1
        std::cout << procs[p]->name() << " instantiated" << std::endl;
#endif
      }

      std::ostringstream sm;
      sm << "memc_" << x_local << "_" << y_local;
      memc = new VciMemCacheV1<vci_param> (
        sm.str().c_str(),
        md, mc, mx,                       // Mapping Tables
        IntTab(0),                        // SRCID_X
        IntTab(max_nprocs),               // SRCID_C
        IntTab(0),                        // TGTID_D
        IntTab(max_nprocs),               // TGTID_C
        mcways, mcsets, mcwords           // MemCache Size  
      );
      
#ifdef DEBUG_TSAR_CLUSTER_V1
      std::cout << memc->name() << " instantiated" << std::endl;
#endif

      std::ostringstream sx;
      sx << "xicu_" << x_local << "_" << y_local;
      xicu = new VciXicu<vci_param> (
        sx.str().c_str(),
        md,
        IntTab(1),                        // TGTID_D
        nprocs,                           // number of TIMERS
        is_io,                            // number of hard IRQs
        nprocs,                           // number of soft IRQs
        nprocs                            // number of output IRQ lines
      );
      
#ifdef DEBUG_TSAR_CLUSTER_V1
      std::cout << xicu->name() << " instantiated" << std::endl;
#endif

      std::ostringstream stty;
      mtty = NULL;
      if (is_io == 1) {
        stty << "mtty_" << x_local << "_" << y_local;

        mtty = new VciMultiTty<vci_param> (
          stty.str().c_str(),
          IntTab(2),
          md,
          "tty0", NULL
        );

#ifdef DEBUG_TSAR_CLUSTER_V1
        std::cout << mtty->name() << " instantiated" << std::endl;
#endif
      }

      //////////////////////////////////////////////////////////////
      // Netlist

      signal_vci_ini_d = alloc_elems<VciSignals<vci_param> >("s_vci_ini_d", nprocs);
      signal_vci_tgt_d = alloc_elems<VciSignals<vci_param> >("s_vci_tgt_d", 2 + is_io);
      signal_vci_ini_c = alloc_elems<VciSignals<vci_param> >("s_vci_ini_c", nprocs + 1);
      signal_vci_tgt_c = alloc_elems<VciSignals<vci_param> >("s_vci_tgt_c", nprocs + 1);

      signal_proc_irq  = new sc_signal<bool>[nprocs];

      memc->p_clk               (p_clk);
      memc->p_resetn            (p_resetn);
      memc->p_vci_tgt           (signal_vci_tgt_d[0]);
      memc->p_vci_ini           (signal_vci_ini_c[nprocs]);
      memc->p_vci_tgt_cleanup   (signal_vci_tgt_c[max_nprocs]);
      memc->p_vci_ixr           (p_vci_ixr);

      for ( size_t p = 0 ; p < nprocs ; p++ ) {
        procs[p]->p_clk        (p_clk);  
        procs[p]->p_resetn     (p_resetn);  
        procs[p]->p_vci_ini_rw (signal_vci_ini_d[p]);
        procs[p]->p_vci_ini_c  (signal_vci_ini_c[p]);
        procs[p]->p_vci_tgt    (signal_vci_tgt_c[p]);
        procs[p]->p_irq[0]     (signal_proc_irq[p]);

        for ( size_t j = 1 ; j < 6 ; j++ ) {
          procs[p]->p_irq[j]   (signal_false); 
        }
      }

      // XICU
      xicu->p_clk       (p_clk);
      xicu->p_resetn    (p_resetn);
      xicu->p_vci       (signal_vci_tgt_d[1]);

      if(is_io == 1) {
        xicu->p_hwi[0]  (signal_mtty_irq);

        mtty->p_clk     (p_clk);
        mtty->p_resetn  (p_resetn);
        mtty->p_vci     (signal_vci_tgt_d[2]);
        mtty->p_irq[0]  (signal_mtty_irq);
      }

      for ( size_t p = 0 ; p < nprocs ; p++ ) {
        xicu->p_irq[p]  (signal_proc_irq[p]);
      }

      // Direct ring
      ringd->p_clk                    (p_clk);
      ringd->p_resetn                 (p_resetn);

      for ( size_t p = 0 ; p < nprocs ; p++ ) {
        ringd->p_to_initiator[p]      (signal_vci_ini_d[p]);
      }

      for ( int t = 0 ; t < (2 + is_io) ; t++ ) {
        ringd->p_to_target[t]         (signal_vci_tgt_d[t]);
      }

      // Coherence ring
      ringc->p_clk                    (p_clk);
      ringc->p_resetn                 (p_resetn);

      for ( size_t i = 0 ; i < (nprocs + 1) ; i++ ) {
        ringc->p_to_initiator[i]      (signal_vci_ini_c[i]);
      }

      for ( size_t t = 0 ; t < (max_nprocs + 1) ; t++ ) {
        ringc->p_to_target[t]         (signal_vci_tgt_c[t]);
      }
    } // End TsarClusterV1

    template<typename vci_param, size_t cmd_width, size_t rsp_width>
    void TsarClusterV1<vci_param, cmd_width, rsp_width>::print_trace() {
      #ifdef DIRECT_TRACE
      ringd->print_trace();
      #endif
      #ifdef COHERENCE_TRACE
      ringc->print_trace();
      #endif
    }

    template<typename vci_param, size_t cmd_width, size_t rsp_width>
    TsarClusterV1<vci_param, cmd_width, rsp_width>::~TsarClusterV1() {
      for(size_t p=0; p < m_nprocs; p++) {
        delete procs[p];
      }
      delete [] procs;
      delete ringd;
      delete ringc;
      delete memc;
      delete xicu;

      if(mtty) {
        delete mtty;
        dealloc_elems<VciSignals<vci_param> >(signal_vci_tgt_d, 3);
      } else {
        dealloc_elems<VciSignals<vci_param> >(signal_vci_tgt_d, 2);
      }

      dealloc_elems<VciSignals<vci_param> >(signal_vci_ini_d, m_nprocs);
      dealloc_elems<VciSignals<vci_param> >(signal_vci_ini_c, m_nprocs + 1);
      dealloc_elems<VciSignals<vci_param> >(signal_vci_tgt_c, m_nprocs + 1);
      delete [] signal_proc_irq;
    }
  }
}

// vim: tabstop=2 : shiftwidth=2 : expandtab
