#include "fpgaflashengine.h"
#include "fpgaflashoperation.h"

//***************************
// Simulator



enum step_operation_t
{
    stp_operation_nc,
    stp_operation_in_progress,
    stp_operation_done
};

struct fpga_flash_ip_simulator_t
{
    uint32_t ctrl[DIM_DATA_BUFFER/4]; //256/4];
    uint32_t sts[DIM_DATA_BUFFER/4]; //256/4];
    uint32_t fifo[DIM_DATA_BUFFER/4];
    step_t step;
    step_operation_t step_operation;
};

static fpga_flash_ip_simulator_t fpga_flash_ip_simulator;

bool FpgaFlashEngine::simulateWrite(uint32_t address, const void* data, unsigned int len)
{
    if (address==0)
    {
        //se si tratta di un comando, lo scrivo nella struttura di comando del simulatore
        memcpy(fpga_flash_ip_simulator.ctrl, data, len);
    }
    else
    if (address==adr_fifo)
    {
        //se si tratta di un dato, lo scrivo nella struttura fifo del simulatore
        memcpy(fpga_flash_ip_simulator.fifo, data, len);
    }
    return true;
}

bool FpgaFlashEngine::simulateRead(uint32_t address, void* data, unsigned int len)
{
    //se devo leggere uno stato,
    if ((address / 4)==r_spi_status_base)
    {
        //copio lo stato fornito nel simulatore
        memcpy(fpga_flash_ip_simulator.sts, data, len);

        //estraggo il registro di stato
        //unsigned int spisr =fpga_flash_ip_simulator.sts[0];

        uint32_t res = 0;

        /*switch(fpga_flash_ip_simulator.step)
        {
        case stp_nc:
            fpga_flash_ip_simulator.step = stp_ack;
            //simulazione, spi_core_ack=1 e lo scrivo nello stato
            res = encodeSPISR(spisr, spi_core_ack);
            break;
        case stp_ack:
            fpga_flash_ip_simulator.step = stp_busy;
            res = encodeSPISR(spisr, spi_core_busy);
            break;
        case stp_busy:
            //fpga_flash_ip_simulator.step = stp_error;
            //res = encodeSPISR(spisr, spi_core_error);
            fpga_flash_ip_simulator.step = stp_ack_after_busy;
            spisr = 0;
            res = encodeSPISR(spisr, spi_core_ack);
            break;
        case stp_ack_after_busy:
            fpga_flash_ip_simulator.step = stp_nc;
            res = 0;
            break;
        case stp_error:
            fpga_flash_ip_simulator.step = stp_nc;
            res = 0;
            break;
        }*/

        fpga_flash_ip_simulator.sts[0] = res;

        //restituisco lo stato modificato
        memcpy(data, fpga_flash_ip_simulator.sts, len);

        return true;
    }
    else
    if ((address / 4)==r_spirr)
    {
        //devo leggere un valore di ritorno
        memcpy(fpga_flash_ip_simulator.fifo, data, len);

        uint32_t res = 0x0;

        switch(fpga_flash_ip_simulator.step_operation)
        {
        case stp_operation_nc:
            res = 0x1;
            fpga_flash_ip_simulator.step_operation = stp_operation_in_progress;
            break;
        case stp_operation_in_progress:
            fpga_flash_ip_simulator.step_operation = stp_operation_done;
            res = 0x0;
            break;
        case stp_operation_done:
            fpga_flash_ip_simulator.step_operation = stp_operation_nc;
            res = 0x0;
            break;
        }

        fpga_flash_ip_simulator.fifo[0] = res;

        //restituisco lo stato modificato
        memcpy(data, fpga_flash_ip_simulator.fifo, len);

        return true;
    }
    return false;
}

bool FpgaFlashEngine::simulateErase(uint32_t address, void* data, unsigned int len)
{
    if (address==r_spi_status_base)
    {
        //fare erase su simulatore
        //memcpy(data, fpga_flash_ip_simulator.sts, len);
    }
    return false;
}

bool FpgaFlashEngine::simulateReset()
{
    //fare reset su simulatore
    //memcpy(data, fpga_flash_ip_simulator.sts, len);

    return false;
}

unsigned int FpgaFlashEngine::simulateReadFlashID()
{
    //fare ReadFlashID su simulatore
    //memcpy(data, fpga_flash_ip_simulator.sts, len);

    return 0;
}

bool FpgaFlashEngine::simulateReadStatusSPI()
{
    //fare ReadStatusSPI su simulatore
    //memcpy(data, fpga_flash_ip_simulator.sts, len);

    return false;
}

bool FpgaFlashEngine::simulateTerminate()
{
    //fare ReadStatusSPI su simulatore
    //memcpy(data, fpga_flash_ip_simulator.sts, len);

    return false;
}

bool decodeSPISR(uint32_t _spisr, spisr_bit_t _bit)
{
    unsigned int res = (_spisr & _bit);
    return  (res != 0);
}

uint32_t encodeSPISR(uint32_t _spisr, spisr_bit_t _bit)
{
    uint32_t res = (_spisr | _bit);
    return  res;
}



//*****************************************
// FlashOperation

static FlashOperation fop;

FpgaFlashEngine::FpgaFlashEngine()
{
    fop.init(this, moder_spimode_x4mode, bytes4address, primarySpiPort);

    memset(&fpga_flash_ip_simulator, 0, sizeof fpga_flash_ip_simulator);
}

void FpgaFlashEngine::setProfile(const FpgaFlashProfile& profile)
{
    fop.profile=profile;
}

void FpgaFlashEngine::setInterface(FpgaFlashInterface* flashInterface)
{
    fop.fif=flashInterface;
}

bool FpgaFlashEngine::fpgaProgram(const void* data, unsigned int size)
{
#ifdef NO_OPERATION_ON_FLASH
    //No flash operations are performed
    return true;
#else
    return fop.program(data, size);
#endif
}

bool FpgaFlashEngine::fpgaErase(unsigned int size)
{
    return fop.eraseForSize(size);
}

bool FpgaFlashEngine::fpgaReset()
{
    return fop.reset();
}

bool FpgaFlashEngine::readFlashID()
{
    return fop.readFlashID(primarySpiPort);
}

bool FpgaFlashEngine::readStatusSPI()
{
    return fop.readStatusRegisterSPISR();
}

bool FpgaFlashEngine::getEnableMsgBlk()
{
    return fop.getEnableMsgBlk();
}

//*****************************************
// STOP FlashOperation


