Index: trunk/modules/vci_cc_xcache_wrapper_v4/caba/source/src/vci_cc_xcache_wrapper_v4.cpp
===================================================================
--- trunk/modules/vci_cc_xcache_wrapper_v4/caba/source/src/vci_cc_xcache_wrapper_v4.cpp	(revision 143)
+++ trunk/modules/vci_cc_xcache_wrapper_v4/caba/source/src/vci_cc_xcache_wrapper_v4.cpp	(revision 144)
@@ -490,7 +490,16 @@
                 dreq_num_cpu           = new uint32_t                            [m_nb_dcache];
 
-                m_cpt_icache_access = new uint32_t [m_nb_icache];
-                m_cpt_dcache_access = new uint32_t [m_nb_dcache];
-
+                m_cpt_icache_access         = new uint32_t [m_nb_icache];
+                m_cpt_dcache_access         = new uint32_t [m_nb_dcache];
+                m_cpt_icache_miss_victim_wait = new uint32_t [m_nb_icache];
+                m_cpt_dcache_miss_victim_wait = new uint32_t [m_nb_dcache];
+
+#if CC_XCACHE_WRAPPER_STORE_AFTER_STORE
+                m_cpt_dcache_store_after_store    = new uint32_t [m_nb_dcache];
+#endif
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+                m_cpt_dcache_hit_after_miss_read  = new uint32_t [m_nb_dcache];
+                m_cpt_dcache_hit_after_miss_write = new uint32_t [m_nb_dcache];
+#endif
                
                 m_cpt_fsm_dcache  = new uint32_t * [m_nb_dcache];
@@ -754,5 +763,13 @@
         delete [] m_cpt_icache_access   ;
         delete [] m_cpt_dcache_access   ;
-
+        delete [] m_cpt_icache_miss_victim_wait;
+        delete [] m_cpt_dcache_miss_victim_wait;
+#if CC_XCACHE_WRAPPER_STORE_AFTER_STORE
+        delete [] m_cpt_dcache_store_after_store;
+#endif
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+        delete [] m_cpt_dcache_hit_after_miss_read;
+        delete [] m_cpt_dcache_hit_after_miss_write;
+#endif
         for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
         delete [] m_cpt_fsm_dcache [num_cache];
@@ -801,5 +818,5 @@
     }
     ////////////////////////
-    tmpl(void)::print_stats()
+  tmpl(void)::print_stats(bool print_wbuf, bool print_fsm)
     ////////////////////////
     {
@@ -860,37 +877,65 @@
         std::cout << "- DCACHE ACCESS                  : " << m_cpt_dcache_access_all << std::endl;
         for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
-            std::cout << "  + [" << num_cache << "] : " << m_cpt_dcache_access [num_cache] << " (" << (float)m_cpt_dcache_access [num_cache]*100.0/(float)m_cpt_dcache_access_all << "%)" << std::endl;
-
-        std::cout << "- DCACHE FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(dcache_fsm_state_str ); ++i)
-        {
-            std::cout << "  + "  << dcache_fsm_state_str[i] << " :\t ";
-            for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
-                std::cout << m_cpt_fsm_dcache [num_cache][i] << ", ";
-            std::cout << std::endl; 
-        }
-        std::cout << "- ICACHE FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(icache_fsm_state_str ); ++i)
-        {
-            std::cout << "  + "  << icache_fsm_state_str[i] << " :\t ";
-            for (uint32_t num_cache=0; num_cache<m_nb_icache; ++num_cache)
-                std::cout << m_cpt_fsm_icache [num_cache][i] << ", ";
-            std::cout << std::endl; 
-        }
-        std::cout << "- CMD FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(cmd_fsm_state_str ); ++i)
-            std::cout << "  + " << cmd_fsm_state_str[i] << " :\t " << m_cpt_fsm_cmd [i] << std::endl;
-        std::cout << "- RSP FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(rsp_fsm_state_str ); ++i)
-            std::cout << "  + " << rsp_fsm_state_str[i] << " :\t " << m_cpt_fsm_rsp [i] << std::endl;
-        std::cout << "- TGT FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(tgt_fsm_state_str ); ++i)
-            std::cout << "  + "  << tgt_fsm_state_str[i] << " :\t " << m_cpt_fsm_tgt [i] << std::endl;
-        std::cout << "- CLEANUP FSM" << std::endl;
-        for (uint32_t i=0; i<soclib::common::size(cleanup_fsm_state_str ); ++i)
-            std::cout << "  + "  << cleanup_fsm_state_str[i] << " :\t " << m_cpt_fsm_cleanup [i] << std::endl;
+          {
+            std::cout << "  + [" << num_cache << "] : " << m_cpt_dcache_access [num_cache] << " (" << (float)m_cpt_dcache_access [num_cache]*100.0/(float)m_cpt_dcache_access_all << "%)";
+
+#if CC_XCACHE_WRAPPER_STORE_AFTER_STORE
+            std::cout << " - store after store : " << m_cpt_dcache_store_after_store [num_cache];
+#endif
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+            std::cout << " - Hit after Miss : Read " << m_cpt_dcache_hit_after_miss_read [num_cache] << ", Write " << m_cpt_dcache_hit_after_miss_write [num_cache];
+#endif
+            std::cout << std::endl;
+          }
+
+        uint32_t m_cpt_icache_miss_victim_wait_all = 0;
+        for (uint32_t num_cache=0; num_cache<m_nb_icache; ++num_cache)
+            m_cpt_icache_miss_victim_wait_all += m_cpt_icache_miss_victim_wait [num_cache];
+        std::cout << "- ICACHE MISS VICTIM WAIT        : " << m_cpt_icache_miss_victim_wait_all << std::endl;
+        for (uint32_t num_cache=0; num_cache<m_nb_icache; ++num_cache)
+            std::cout << "  + [" << num_cache << "] : " << m_cpt_icache_miss_victim_wait [num_cache] << std::endl;
+
+        uint32_t m_cpt_dcache_miss_victim_wait_all = 0;
+        for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
+            m_cpt_dcache_miss_victim_wait_all += m_cpt_dcache_miss_victim_wait [num_cache];
+        std::cout << "- DCACHE MISS VICTIM WAIT        : " << m_cpt_dcache_miss_victim_wait_all << std::endl;
+        for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
+            std::cout << "  + [" << num_cache << "] : " << m_cpt_dcache_miss_victim_wait [num_cache] << std::endl;
+
+        if (print_fsm)
+          {
+            std::cout << "- DCACHE FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(dcache_fsm_state_str ); ++i)
+              {
+                std::cout << "  + "  << dcache_fsm_state_str[i] << " :\t ";
+                for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
+                  std::cout << m_cpt_fsm_dcache [num_cache][i] << ", ";
+                std::cout << std::endl; 
+              }
+            std::cout << "- ICACHE FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(icache_fsm_state_str ); ++i)
+              {
+                std::cout << "  + "  << icache_fsm_state_str[i] << " :\t ";
+                for (uint32_t num_cache=0; num_cache<m_nb_icache; ++num_cache)
+                  std::cout << m_cpt_fsm_icache [num_cache][i] << ", ";
+                std::cout << std::endl; 
+              }
+            std::cout << "- CMD FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(cmd_fsm_state_str ); ++i)
+              std::cout << "  + " << cmd_fsm_state_str[i] << " :\t " << m_cpt_fsm_cmd [i] << std::endl;
+            std::cout << "- RSP FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(rsp_fsm_state_str ); ++i)
+              std::cout << "  + " << rsp_fsm_state_str[i] << " :\t " << m_cpt_fsm_rsp [i] << std::endl;
+            std::cout << "- TGT FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(tgt_fsm_state_str ); ++i)
+              std::cout << "  + "  << tgt_fsm_state_str[i] << " :\t " << m_cpt_fsm_tgt [i] << std::endl;
+            std::cout << "- CLEANUP FSM" << std::endl;
+            for (uint32_t i=0; i<soclib::common::size(cleanup_fsm_state_str ); ++i)
+              std::cout << "  + "  << cleanup_fsm_state_str[i] << " :\t " << m_cpt_fsm_cleanup [i] << std::endl;
+          }
 
         std::cout << "* : accepted or not by the cache" << std::endl ;
 
+        if (print_wbuf)
         for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
             r_wbuf[num_cache]->printStatistics();
@@ -1085,5 +1130,6 @@
             for (uint32_t num_cache=0; num_cache<m_nb_icache; ++num_cache)
             {
-                m_cpt_icache_access [num_cache] = 0;
+                m_cpt_icache_access           [num_cache] = 0;
+                m_cpt_icache_miss_victim_wait [num_cache] = 0;
 
                 for (uint32_t i=0; i<soclib::common::size(icache_fsm_state_str ); ++i)
@@ -1092,6 +1138,14 @@
             for (uint32_t num_cache=0; num_cache<m_nb_dcache; ++num_cache)
             {
-                m_cpt_dcache_access [num_cache] = 0;
-
+                m_cpt_dcache_access               [num_cache] = 0;
+                m_cpt_dcache_miss_victim_wait     [num_cache] = 0;
+
+#if CC_XCACHE_WRAPPER_STORE_AFTER_STORE
+                m_cpt_dcache_store_after_store    [num_cache] = 0;
+#endif
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+                m_cpt_dcache_hit_after_miss_read  [num_cache] = 0;
+                m_cpt_dcache_hit_after_miss_write [num_cache] = 0;
+#endif
                 for (uint32_t i=0; i<soclib::common::size(dcache_fsm_state_str ); ++i)
                     m_cpt_fsm_dcache  [num_cache][i] = 0;
@@ -1676,8 +1730,9 @@
             num_cache = get_num_icache(addr,num_cpu);
 
-            // test if already used
-            if (not ireq[num_cache].valid and
-                (r_icache_lock [num_cache] == m_nb_cpu) or
-                (r_icache_lock [num_cache] == num_cpu))
+            bool icache_req_valid = ((not ireq[num_cache].valid and               // no previous request in this cycle
+                                      (r_icache_lock [num_cache] == m_nb_cpu)) or // no previous request in previous cycle
+                                     (r_icache_lock [num_cache] == num_cpu));     // previous request in previous cycle by this cpu
+
+            if (icache_req_valid)
             {
                 bool valid = _ireq.valid;
@@ -1709,10 +1764,31 @@
             addr      = (addr_40)_dreq.addr;
             num_cache = get_num_dcache(addr);
+            
+
+            bool dcache_no_lock      = (r_dcache_lock [num_cache] == m_nb_cpu);
+            bool dcache_lock_owner   = (r_dcache_lock [num_cache] == num_cpu);
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+            bool dcache_lock_no_owner= not dcache_no_lock and not dcache_lock_owner;
+            bool dcache_wait         = ((r_dcache_fsm[num_cache] == DCACHE_MISS_WAIT)//  or
+                                        // (r_dcache_fsm[num_cache] == DCACHE_UNC_WAIT) or
+                                        // (r_dcache_fsm[num_cache] == DCACHE_SC_WAIT)
+                                        );
+
+            bool dcache_req_valid = ((not dreq[num_cache].valid and               // no previous request in this cycle
+                                      not have_sync and                           // no sync instruction
+                                      (dcache_no_lock or
+                                       (dcache_lock_no_owner and dcache_wait))) or // no previous request in previous cycle
+                                     (dcache_lock_owner and not dcache_wait));     // previous request in previous cycle by this cpu
+#else
+            bool dcache_req_valid = ((not dreq[num_cache].valid and // no previous request in this cycle
+                                      not have_sync and             // no sync instruction
+                                      dcache_no_lock) or            // no previous request in previous cycle
+                                     dcache_lock_owner);            // previous request in previous cycle by this cpu
+#endif
+            // @@@@
+
 
             // test if already used
-            if (not dreq[num_cache].valid and
-                not have_sync and
-                (r_dcache_lock [num_cache] == m_nb_cpu) or
-                (r_dcache_lock [num_cache] == num_cpu))
+            if (dcache_req_valid)
             {
                 bool valid = _dreq.valid;
@@ -1722,4 +1798,8 @@
                     PRINTF("    * <CPU2CACHE> DCACHE :    Transaction between cpu %d and cache %d (lock)\n",num_cpu,num_cache);
                     dreq_num_cache [num_cpu  ] = num_cache;
+
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+                    if (not dcache_lock_no_owner)
+#endif
                     r_dcache_lock [num_cache] = num_cpu;
                 }
@@ -1823,7 +1903,4 @@
                         PRINTF("    * <ICACHE [%d]> hit %d - cached %d - cleanup_hit %d\n",num_cache, icache_hit, icache_cached, icache_cleanup_hit);
 
-                        // ASSERT( not (icache_hit and icache_cleanup_hit),
-                        //         "Icache hit and icache_cleanup_hit");
-
                         if (icache_hit and icache_cleanup_hit)
                         {
@@ -1837,16 +1914,24 @@
                                 m_cpt_ins_miss++;
                                 m_cost_ins_miss_frz++;
+                                
                                 r_icache_addr_save[num_cache] = (addr_40) _ireq.addr;
-                                
-                                CACHE_MISS_BUF_REQ_INIT(i,num_cache);
-                                
+
                                 if ( icache_cached )
                                 {
-                                    r_icache_fsm     [num_cache] = ICACHE_MISS_VICTIM;
-                                    r_icache_miss_req[num_cache] = true;
-                                    
+                                    // to prevent deadlock, miss victim don't be block
+                                    if (not r_icache_cleanup_req[num_cache])
+                                    {
+                                        CACHE_MISS_BUF_REQ_INIT(i,num_cache);
+                                        r_icache_fsm     [num_cache] = ICACHE_MISS_VICTIM;
+                                        r_icache_miss_req[num_cache] = true;
+                                    }
+                                    else
+                                        m_cpt_icache_miss_victim_wait [num_cache] ++;
                                 }
                                 else
                                 {
+                                    CACHE_MISS_BUF_REQ_INIT(i,num_cache);
+                                    r_icache_addr_save[num_cache] = (addr_40) _ireq.addr;
+
                                     r_icache_fsm    [num_cache] = ICACHE_UNC_WAIT;
                                     r_icache_unc_req[num_cache] = true;
@@ -1863,5 +1948,5 @@
                         _irsp.valid          = icache_hit;
                         _irsp.instruction    = icache_ins;
-                    }
+                        }
                     break;
                 }
@@ -1869,5 +1954,5 @@
             case ICACHE_MISS_VICTIM:
                 {
-                    if (not r_icache_cleanup_req[num_cache])
+                    // if (not r_icache_cleanup_req[num_cache])
                     {
                         size_t     way;
@@ -2285,16 +2370,24 @@
                                             if (not dcache_cleanup_hit)
                                             {
-                                                CACHE_MISS_BUF_REQ_INIT(d,num_cache);
                                                 
                                                 // Miss : send signal at the CMD_FSM (via r_dcache_miss_req or r_dcache_unc_req)
                                                 if ( dcache_cached ) {
-                                                    m_cpt_data_read_miss++;
-                                                    m_cost_data_miss_frz++;
-                                                    r_dcache_miss_req [num_cache] = true;
-                                                    r_dcache_fsm [num_cache] = DCACHE_MISS_VICTIM;
-                                                    
+                                                    // to prevent deadlock, miss victim don't be block
+                                                    if (not r_dcache_cleanup_req[num_cache].read())
+                                                    {
+                                                        CACHE_MISS_BUF_REQ_INIT(d,num_cache);
+                                                        
+                                                        m_cpt_data_read_miss++;
+                                                        m_cost_data_miss_frz++;
+                                                        r_dcache_miss_req [num_cache] = true;
+                                                        r_dcache_fsm [num_cache] = DCACHE_MISS_VICTIM;
+                                                    }
+                                                    else
+                                                        m_cpt_icache_miss_victim_wait [num_cache] ++;
                                                 } else {
                                                     if (not r_dcache_previous_unc[num_cache].read()) // strongly order to the uncached access
                                                     {
+                                                        CACHE_MISS_BUF_REQ_INIT(d,num_cache);
+
                                                         r_dcache_previous_unc[num_cache] = true;
                                                         
@@ -2451,10 +2544,79 @@
                 {
                     m_cpt_dcache_data_write++;
-                    data_t mask = vci_param::be2mask(r_dcache_be_save[num_cache]);
-                    data_t wdata = (mask & r_dcache_wdata_save[num_cache]) | (~mask & r_dcache_rdata_save[num_cache]);
-                    vci_addr_t ad = r_dcache_addr_save[num_cache].read();
+                    data_t     mask  = vci_param::be2mask(r_dcache_be_save[num_cache]);
+                    data_t     wdata = (mask & r_dcache_wdata_save[num_cache]) | (~mask & r_dcache_rdata_save[num_cache]);
+                    vci_addr_t ad    = r_dcache_addr_save[num_cache].read();
                     r_dcache[num_cache]->write(ad, wdata);
 
-                    r_dcache_fsm [num_cache] = DCACHE_IDLE;
+                    int dcache_fsm_next = DCACHE_IDLE; // default
+
+#if CC_XCACHE_WRAPPER_STORE_AFTER_STORE
+                    // Test if write after write
+
+                    if (_dreq.valid and (_dreq.type == iss_t::DATA_WRITE))
+                    {
+                        PRINTF("    * <DCACHE [%d]> Have dreq (Write after Write)\n",num_cache);
+
+                        data_t      dcache_rdata       = 0;
+                        // dcache_cached and dcache_hit don't used with _dreq.type == {DATA_SC, XTN_READ, XTN_WRITE}
+                        bool        dcache_cached      = dreq_cached  [num_cache];
+                        uint32_t    dcache_num_cpu     = dreq_num_cpu [num_cache];
+                        bool        dcache_hit         = r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata);
+
+                        m_cpt_dcache_data_read += m_dcache_ways;
+                        m_cpt_dcache_dir_read  += m_dcache_ways;
+
+                        PRINTF("    * <DCACHE [%d]> r_dcache_previous_unc : %d\n",num_cache,r_dcache_previous_unc[num_cache].read());
+                        
+                        if (dcache_cached or not r_dcache_previous_unc[num_cache].read()) // strongly order to the uncached access
+                            {
+                                bool valid;
+                                addr_40 addr = _dreq.addr;
+                                set_num_dcache(addr,num_cache);
+                                
+                                // FIXME : 
+                                //  * dans le wbuf, ne pas mettre l'adresse au complet (economie de surface)
+                                //  * pour cela, virer le set_num_dcache !
+                                valid = r_wbuf[num_cache]->write(addr, _dreq.be, _dreq.wdata, dcache_cached, dcache_num_cpu);
+                                PRINTF("    * <DCACHE [%d]> r_wbuf valid          : %d\n",num_cache,valid);
+                                
+                                if (valid)
+                                    {
+                                        m_cpt_dcache_store_after_store [num_cache] ++;
+                                        
+                                        m_cpt_data_write++;
+                                        
+                                        if (not dcache_cached)
+                                            {
+                                                r_dcache_previous_unc[num_cache] = true;
+                                                m_cpt_data_write_uncached++;
+                                            }
+                                        else if (not dcache_hit)
+                                            m_cpt_data_write_miss++;
+                                        
+                                        if (dcache_hit) {
+                                            // update data cache
+                                            dcache_fsm_next = DCACHE_WRITE_UPDT;
+                                        } else {
+                                            // write accepted
+                                            dcache_fsm_next = DCACHE_IDLE;
+                                        }
+                                    }
+                                
+                                _drsp.valid = valid;
+                                _drsp.rdata = 0;
+                            }
+
+                        r_dcache_addr_save   [num_cache] = (addr_40) _dreq.addr;
+                        // r_dcache_type_save   [num_cache] = _dreq.type;
+                        r_dcache_wdata_save  [num_cache] = _dreq.wdata;
+                        r_dcache_be_save     [num_cache] = _dreq.be;
+                        r_dcache_rdata_save  [num_cache] = dcache_rdata;
+                        // r_dcache_cached_save [num_cache] = dcache_cached;
+                        // r_dcache_num_cpu_save[num_cache] = dcache_num_cpu;
+                    }
+#endif
+
+                    r_dcache_fsm [num_cache] = dcache_fsm_next; // default
 
                     break;
@@ -2463,5 +2625,5 @@
             case DCACHE_MISS_VICTIM:
                 {
-                    if (not r_dcache_cleanup_req[num_cache].read())
+                    // if (not r_dcache_cleanup_req[num_cache].read())
                      {
                          size_t     way;
@@ -2486,4 +2648,63 @@
             case DCACHE_MISS_WAIT:
                 {
+#if CC_XCACHE_WRAPPER_MULTI_CACHE_HIT_AFTER_MISS
+                  data_t   dcache_rdata   = 0;
+                  bool     dcache_hit     = r_dcache[num_cache]->read((vci_addr_t) _dreq.addr, &dcache_rdata);
+                  // bool     dcache_cached  = dreq_cached  [num_cache];
+                  // uint32_t dcache_num_cpu = dreq_num_cpu [num_cache];
+
+                  m_cpt_dcache_data_read += m_dcache_ways;
+                  m_cpt_dcache_dir_read  += m_dcache_ways;
+                  
+                  if (_dreq.valid)
+                    switch (_dreq.type)
+                      {
+                      case iss_t::DATA_READ : // accept only hit dcache load
+                        {
+                          m_cpt_data_read++; // new dcache read
+                          
+                          if (dcache_hit) // no special test for uncached read, because it's always miss
+                            {
+                              m_cpt_dcache_hit_after_miss_read [num_cache] ++;
+                              
+                              // address is in the cache : return the word
+                              _drsp.valid = true;
+                              _drsp.rdata = dcache_rdata; // return read data (cf dcache_hit)
+                            }
+                          break;
+                        }
+                      // case iss_t::DATA_WRITE : // accept only cached write and miss in dcache (else need update dcache)
+                      //   {
+                      //     if (dcache_cached and not dcache_hit)
+                      //       {
+                      //         bool valid;
+                      //         addr_40 addr = _dreq.addr;
+                      //         set_num_dcache(addr,num_cache);
+                              
+                      //         // FIXME : 
+                      //         //  * dans le wbuf, ne pas mettre l'adresse au complet (economie de surface)
+                      //         //  * pour cela, virer le set_num_dcache !
+                      //         valid = r_wbuf[num_cache]->write(addr, _dreq.be, _dreq.wdata, dcache_cached, dcache_num_cpu);
+                      //         PRINTF("    * <DCACHE [%d]> r_wbuf valid          : %d\n",num_cache,valid);
+                              
+                      //         if (valid)
+                      //           {
+                      //             m_cpt_dcache_hit_after_miss_write [num_cache] ++;
+
+                      //             m_cpt_data_write++;
+                      //             m_cpt_data_write_miss++;
+                      //           }
+                              
+                      //         _drsp.valid = valid;
+                      //         _drsp.rdata = 0;
+                      //       }
+                      //     break;
+                      //   }
+                      default :
+                        {
+                          break;
+                        }
+                      }
+#endif
 
                     // if ( _dreq.valid ) m_cost_data_miss_frz++;
