/********************************************/
/*70V05 Dual Port RAM Driver Code           */
/*Auto Semaphore version                    */
/********************************************/
/*PIC32MX795F512L-80I                       */
/*PIC32MX765F512L-80I                       */
/********************************************/

    /*     Flag Table        */
    //Flag 000 = address 0000 - 03ff
    //Flag 001 = address 0400 - 07ff
    //Flag 010 = address 0800 - 0bff
    //Flag 011 = address 0c00 - 0fff
    //Flag 100 = address 1000 - 13ff
    //Flag 101 = address 1400 - 17ff
    //Flag 110 = address 1800 - 1bff
    //Flag 110 = address 1c00 - 1fff
    

#include <xc.h>
#include "MainBrain.h"

#define SRAM_FAIL         0
#define SRAM_PASS         1

int sram_test;
int sram_test_data[8192];
uint16_t SRAM_Block;
uint8_t mdata_70V05;
unsigned address_70V05;

void REN70V05_Init(void)
{    
   //RD3 = /CS1
    TRISDbits.TRISD3 = 0;
    PORTDbits.RD3 = 1;
    
    //RG15 = /SEM
    TRISGbits.TRISG15 = 0;
    PORTGbits.RG15 = 1;
    
    //INT1 - INTR
    TRISEbits.TRISE8 = 1;
    
    //RA7 = M/S
    TRISAbits.TRISA7 = 0;    
    //Slave mode to disable the BUSY logic
    PORTAbits.RA7 = 0;
    
    //BUSY - BUSYR
    //Since we are in slave mode we must pull BUSY
    //high to allow writes to the port
    TRISEbits.TRISE9 = 0;
    PORTEbits.RE9 = 1;
    
    //SRAM Semaphore Initialization
    /************************************************************************
    Since any semaphore request flag which contains a zero must be reset to a 
    one, all semaphores on both sides should have a one written into them at
    initialization from both sides to assure that they will be free when
    needed.
    *************************************************************************/
    uint8_t i;
    for(i=0;i<8;i++)
    {
        //pull SEMR low to access the flags
        PORTGbits.RG15 = 0;

        //write a one to Flag    
        PMADDR = i;
        PMDIN = 0x1;
        while(PMMODEbits.BUSY == 1);

        //Set SEMR
        PORTGbits.RG15 = 1;
    }
}

bool REN70V05_WR(uint32_t address_70V05, uint8_t mdata_70V05)
{        
    uint8_t Flag = 0;
    uint8_t temp = 0;
    //save previous address
    //this fixes a hang issue
    int d = PMADDR;

    //0 - 3ff
    if(address_70V05 < 0x400)
    {
        Flag = 0;
    }
    
    //400 - 7ff
    if(address_70V05 > 0x3ff && address_70V05 < 0x800)
    {
        Flag = 1;
    }
    
    //800 - bff
    if(address_70V05 > 0x7ff && address_70V05 < 0xc00)
    {
        Flag = 2;
    }
    
    //c00 - fff
    if(address_70V05 > 0xbff && address_70V05 < 0x1000)
    {
        Flag = 3;
    }
    
    //1000 - 13ff
    if(address_70V05 > 0xfff && address_70V05 < 0x1400)
    {
        Flag = 4;
    }
    
    //1400 - 17ff
    if(address_70V05 > 0x13ff && address_70V05 < 0x1800)
    {
        Flag = 5;
    }
    
    //1800 - 1bff
    if(address_70V05 > 0x17ff && address_70V05 < 0x1c00)
    {
        Flag = 6;
    }
    
    //1c00 - 1fff
    if(address_70V05 > 0x1bff)
    {
        Flag = 7;
    }
    
    //First we must use the semaphore to check and get access
    //pull SEMR low to access the flags
    PORTGbits.RG15 = 0;

    //write a zero to Flag    
    PMADDR = Flag;
    PMDIN = 0x0;
    while(PMMODEbits.BUSY == 1);
    
    ///SEM
    PORTGbits.RG15 = 1;
    
    //Flush PMDIN 
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);
    
    ///SEM
    PORTGbits.RG15 = 0;
    
    //Read the result
    //Dummy read
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    if(temp > 0)
    {
        //must do a read per datasheet
        //dummy read
        temp = PMDIN;
        while(PMMODEbits.BUSY == 1);
        
        temp = PMDIN;
        while(PMMODEbits.BUSY == 1);
        
        ///SEM
        PORTGbits.RG15 = 1;

        return false;
    }
        
    //Set SEMR
    PORTGbits.RG15 = 1;
    
    // /CS1 
    PORTDbits.RD3 = 0;

    PMADDR = address_70V05;
        
    PMDIN = mdata_70V05;
    while(PMMODEbits.BUSY == 1);
    
    // /CS1 
    PORTDbits.RD3 = 1;

    //Now relinquish control of SRAM
    //pull SEMR low to access the flags
    PORTGbits.RG15 = 0;

    //write a one to Flag    
    PMADDR = Flag;
    PMDIN = 0x1;
    while(PMMODEbits.BUSY == 1);
    
    //Set SEMR
    PORTGbits.RG15 = 1;

    // /CS1
    PORTDbits.RD3 = 1;
    
    //restore previous address
    PMADDR = d;

    return true;
}

int REN70V05_RD(uint32_t address_70V05)
{        
    uint8_t Flag = 0;
    //save previous address
    //this fixes a hang issue
    int d = PMADDR;

    //0 - 3ff
    if(address_70V05 < 0x400)
    {
        Flag = 0;
    }
    
    //400 - 7ff
    if(address_70V05 > 0x3ff && address_70V05 < 0x800)
    {
        Flag = 1;
    }
    
    //800 - bff
    if(address_70V05 > 0x7ff && address_70V05 < 0xc00)
    {
        Flag = 2;
    }
    
    //c00 - fff
    if(address_70V05 > 0xbff && address_70V05 < 0x1000)
    {
        Flag = 3;
    }
    
    //1000 - 13ff
    if(address_70V05 > 0xfff && address_70V05 < 0x1400)
    {
        Flag = 4;
    }
    
    //1400 - 17ff
    if(address_70V05 > 0x13ff && address_70V05 < 0x1800)
    {
        Flag = 5;
    }
    
    //1800 - 1bff
    if(address_70V05 > 0x17ff && address_70V05 < 0x1c00)
    {
        Flag = 6;
    }
    
    //1c00 - 1fff
    if(address_70V05 > 0x1bff)
    {
        Flag = 7;
    }
    
    //First we must use the semaphore to check and get access
    //pull SEMR low to access the flags
    PORTGbits.RG15 = 0;

    //write a zero to Flag    
    PMADDR = Flag;
    PMDIN = 0x0;
    while(PMMODEbits.BUSY == 1);
    
    ///SEM
    PORTGbits.RG15 = 1;
    
    //Flush PMDIN 
    PMDIN = 0x99;
    while(PMMODEbits.BUSY == 1);

    ///SEM
    PORTGbits.RG15 = 0;
        
    //Read the result
    //Dummy read
    int temp = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    LED_Port(temp);
    
    if(temp > 0)
    {
        //must do a read per datasheet
        //dummy read
        temp = PMDIN;
        while(PMMODEbits.BUSY == 1);
        
        temp = PMDIN;
        while(PMMODEbits.BUSY == 1);
        
        ///SEM
        PORTGbits.RG15 = 1;

        return -1;
    }
        
    //Set SEMR
    PORTGbits.RG15 = 1;
    
    PMADDR = address_70V05;
    
    // /CS1
    PORTDbits.RD3 = 0;
        
    //dummy read
    mdata_70V05 = PMDIN;
    while(PMMODEbits.BUSY == 1);
   
    mdata_70V05 = PMDIN;
    while(PMMODEbits.BUSY == 1);

    // /CS1 
    PORTDbits.RD3 = 1;

    //Now relinquish control of SRAM
    //pull SEMR low to access the flags
    PORTGbits.RG15 = 0;

    //write a one to Flag    
    PMADDR = Flag;
    PMDIN = 0x1;
    while(PMMODEbits.BUSY == 1);
    
    //Set SEMR
    PORTGbits.RG15 = 1;

    //restore previous address
    PMADDR = d;
    
    // /CS1
    PORTDbits.RD3 = 1;
        
    return mdata_70V05;    
}

void memtest_70V05(void)
{
    int a;
    int b;
    
    //Save the RD/WR Wait State Value
    int wait_m = PMMODEbits.WAITM;
    
    //Set new wait state = 0;
    PMMODEbits.WAITM = 1;
    
    /////////////////////////////
    //SRAM write all zeros
    ////////////////////////////
    b = 0x22;
    //8K = 8,191 = 0x1FFF
    for(a=0;a<0x2000;a++)
    {
        PMADDR = a;
        // /CS1 
        PORTDbits.RD3 = 0;

        mdata_70V05 = b;
        PMDIN = mdata_70V05;
        while(PMMODEbits.BUSY == 1);

        // /CS1
        PORTDbits.RD3 = 1;
    }
    /////////////////////////////
    
    //SRAM read and verify 
    for(a=0;a<0x2000;a++)
    {
        PMADDR = a;
        address_70V05 = a;
        mdata_70V05 = b;
        // /CS1
        PORTDbits.RD3 = 0;

        //dummy read
        mdata_70V05 = PMDIN;
        while(PMMODEbits.BUSY == 1);

        mdata_70V05 = PMDIN;
        while(PMMODEbits.BUSY == 1);

        //Test Fails
        if(mdata_70V05 != b)
        {
            sram_test = SRAM_FAIL;
            sram_test_data[a] = 0;
        }
        else //Test passes
        {
            sram_test = SRAM_PASS;
            sram_test_data[a] = 1;
        }
        // /CS1
        PORTDbits.RD3 = 1;
    }

    //Restore the RD/WR Wait State Value
    PMMODEbits.WAITM = wait_m;    
    
    return;
}
