/***************************************************************************
 *   Copyright (C) 2021 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include "avreeprom.h"
#include "datautils.h"
#include "e_mcu.h"
#include "simulator.h"

#include "avreeprom.h"
#include "datautils.h"
#include "e_mcu.h"
#include "simulator.h"

AvrEeprom::AvrEeprom( eMcu* mcu, QString name )
         : McuEeprom( mcu, name )
{
}
AvrEeprom::~AvrEeprom(){}

void AvrEeprom::setup()
{
    m_EECR  = m_mcu->getReg( "EECR" );
    m_EEPM  = getRegBits( "EEPM0, EEPM1", m_mcu );
    m_EEMPE = getRegBits( "EEMPE", m_mcu );
    m_EEPE  = getRegBits( "EEPE", m_mcu );
    m_EERE  = getRegBits( "EERE", m_mcu );
}

void AvrEeprom::initialize()
{
    m_mode = 0;
    McuEeprom::initialize();
}

void AvrEeprom::runEvent() // Write cycle end reached
{
    bool eempe = getRegBitsBool( *m_EECR, m_EEMPE );
    if( eempe ) clearRegBits( m_EEMPE );            // No read operation took place: clear EEMPE
    else        clearRegBits( m_EEPE );             // Read operation took place: clear EEPE
}

void AvrEeprom::configureA( uint8_t newEECR ) // EECR is being written
{
    bool eempe = getRegBitsBool( newEECR, m_EEMPE );
    bool eepe  = getRegBitsBool( newEECR, m_EEPE );

    if( !eepe )
    {
        m_mode = getRegBitsVal( newEECR, m_EEPM ); // EEPROM Programming Mode Bits

        if( getRegBitsBool( newEECR, m_EERE ) ) // Read triggered
        {
            m_mcu->m_regOverride = newEECR & ~(m_EERE.mask); // Clear EERE: it happens after 4 cycles, but cpu is halted for these cycles
            m_mcu->cyclesDone += 4;
            readEeprom(); // Should we return here?
        }
    }
    if( eempe )
    {
        bool oldEepe = getRegBitsBool( *m_EECR, m_EEPE );

        if( !oldEepe && eepe ) // Write triggered
        {
            m_mcu->m_regOverride = newEECR & ~(m_EEMPE.mask); // Clear EEMPE: it happens after 4 cycles but we need to cancel it now
            Simulator::self()->cancelEvents( this );          // Cancel EEMPE clear event
            m_mcu->cyclesDone += 2;
            writeEeprom();
            return;
        }
        bool oldEempe = getRegBitsBool( *m_EECR, m_EEMPE );
        if( !oldEempe ) // Shedule EEMPE clear: 4 cycles
            Simulator::self()->addEvent( m_mcu->psInst()*4, this );
    }
}

void AvrEeprom::writeEeprom()
{
    uint8_t data = *m_dataReg;
    uint64_t time;

    if( m_EEPM.mask ) // Has EEPM bits: atmega328 and friends
    {
        switch( m_mode )
        {
            case 0:     // 3.4 ms - Erase and Write in one operation (Atomic Operation)
                time = 3400*1e6; // picoseconds
                break;
            case 1:     // 1.8 ms - Erase Only
                data = 0xFF;
                // fallthrough
            case 2:     // 1.8 ms - Write Only
                time = 1800*1e6; // picoseconds
                break;
        }
    }
    else            // No EEPM bits: atmega8 8.5 ms
    {
        time = 8500*1e6; // picoseconds
    }
    m_mcu->setRomValue( m_address, data );
    Simulator::self()->addEvent( time, this ); // Shedule Write cycle end
}

