text: /*******************************************************************************
  * Copyright (c) 2012-2014, The Microsystems Design Labratory (MDL)
  * Department of Computer Science and Engineering, The Pennsylvania State University
  * All rights reserved.
  * 
  * This source code is part of NVMain - A cycle accurate timing, bit accurate
  * energy simulator for both volatile (e.g., DRAM) and non-volatile memory
  * (e.g., PCRAM). The source code is free and you can redistribute and/or
  * modify it by providing that the following conditions are met:
  * 
  *  1) Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
  * 
  *  2) Redistributions in binary form must reproduce the above copyright notice,
  *     this list of conditions and the following disclaimer in the documentation
  *     and/or other materials provided with the distribution.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * Author list: 
  *   Matt Poremba    ( Email: mrp5060 at psu dot edu 
  *                     Website: http://www.cse.psu.edu/~poremba/ )
  *******************************************************************************/
  
  #include "Endurance/BitModel/BitModel.h"
  #include <iostream>
  
  using namespace NVM;
  
  BitModel::BitModel( )
  {
      /*
       *  Clear the life map, which will hold all of the endurance
       *  values for each of our rows. Do this to ensure it didn't
       *  happen to be allocated somewhere that thinks it contains 
       *  values.
       */
      life.clear( );
  
      SetGranularity( 1 );
  }
  
  BitModel::~BitModel( )
  {
      /*
       *  Nothing to do here. We do not own the *config pointer, so
       *  don't delete that.
       */
  }
  
  void BitModel::SetConfig( Config *config, bool createChildren )
  {
      Params *params = new Params( );
      params->SetParams( config );
      SetParams( params );
  
      EnduranceModel::SetConfig( config, createChildren );
  }
  
  ncycles_t BitModel::Read( NVMainRequest *request )
  {
      uint64_t row;
      uint64_t col;
      ncycles_t rv = 0;
  
      request->address.GetTranslatedAddress( &row, &col, NULL, NULL, NULL, NULL );
      
      uint64_t wordkey;
      uint64_t rowSize;
      uint64_t wordSize;
      uint64_t partitionCount;
  
      wordSize = p->BusWidth;
      wordSize *= p->tBURST * p->RATE;
      wordSize /= 8;
  
      rowSize = p->COLS * wordSize; 
      
      /* Check each bit to see if it is dead */
      for( uint64_t i = 0; i < wordSize; ++i )
      {
          for( int j = 0; j < 8; j++ )
          {
              /*
               *  Think of each row being partitioned into 1-bit divisions. 
               *  Each row has rowSize * 8 paritions. For the key we will use:
               *
               *  row * number of partitions + partition in this row
               */
              partitionCount = rowSize * 8;
              
              wordkey = row * partitionCount 
                               + (col * wordSize * 8) + i * 8 + j;
  
              if( IsDead( wordkey ) )
              {
                  rv = -(rv + 1);
                  return rv;
              }
          }
      }
  
      return rv;
  }
  
  ncycles_t BitModel::Write( NVMainRequest *request, NVMDataBlock& oldData ) 
  {
      NVMDataBlock& newData = request->data;
      NVMAddress& address = request->address;
  
      /*
       *  The default life map is an stl map< uint64_t, uint64_t >. 
       *  You may map row and col to this map_key however you want.
       *  It is up to you to ensure there are no collisions here.
       */
      uint64_t row;
      uint64_t col;
      ncycles_t rv = 0;
  
      address.GetTranslatedAddress( &row, &col, NULL, NULL, NULL, NULL );
      
      /*
       *  If using the default life map, we can call the DecrementLife
       *  function which will check if the map_key already exists. If so,
       *  the life value is decremented (write count incremented). Otherwise 
       *  the map_key is inserted with a write count of 1.
       */
      uint64_t wordkey;
      uint64_t rowSize;
      uint64_t wordSize;
      uint64_t partitionCount;
  
      wordSize = p->BusWidth;
      wordSize *= p->tBURST * p->RATE;
      wordSize /= 8;
  
      rowSize = p->COLS * wordSize; 
  
      /* Check each byte to see if it was modified */
      for( uint64_t i = 0; i < wordSize; ++i )
      {
          /*
           *  If no bytes have changed we can just continue. Yes, I know this
           *  will check the byte 8 times, but i'd rather not change the iter.
           */
          uint8_t oldByte, newByte;
  
          oldByte = oldData.GetByte( i );
          newByte = newData.GetByte( i );
  
          if( oldByte == newByte ) 
              continue;
  
          /*
           *  If the bytes are different, then at least one bit has changed.
           *  check each bit individually.
           */
          for( int j = 0; j < 8; j++ )
          {
              uint8_t oldBit, newBit;
  
              oldBit = ( oldByte >> j ) & 0x1;
              newBit = ( newByte >> j ) & 0x1;
  
              if( oldBit == newBit )
                  continue;
  
              //std::cout << "Bit " << j << " changed in byte " << i << std::endl;
  
              /*
               *  Think of each row being partitioned into 1-bit divisions. 
               *  Each row has rowSize * 8 paritions. For the key we will use:
               *
               *  row * number of partitions + partition in this row
               */
              partitionCount = rowSize * 8;
              
              wordkey = row * partitionCount 
                               + (col * wordSize * 8) + i * 8 + j;
  
              //std::cout << "Key is " << wordkey << std::endl;
  
              if( !DecrementLife( wordkey ) )
                  rv = -1;
          }
      }
  
      return rv;
  }
  
  