/*
  Saturn FT2232 Transfer Client
  By Anders Montonen (http://www.iki.fi/~antime/)
  Version 20060318

  This program is released into the public domain.
*/


static void ExitToMultiplayer(void)
{
    /* Exit to multiplayer. */
    (**(volatile void(**)(void))0x600026C)();
}

#define DDR1        (*(volatile unsigned char  *)0x20100079)
#define DDR2        (*(volatile unsigned char  *)0x2010007B)
#define IOSEL       (*(volatile unsigned char  *)0x2010007D)
#define EXLE        (*(volatile unsigned char  *)0x2010007F)
static void pad_init(void)
{
    DDR1    = 0x60; /* TH,TR out, TL,D3-D0 in */
    DDR2    = 0x60; /* TH,TR out, TL,D3-D0 in */
    IOSEL   = 0x03; /* Manual mode for both ports */
    EXLE    = 0x00;
}
#define PDR1       (*(volatile unsigned char  *)0x20100075)
static void TestPadConnection(void)
{
    unsigned char temp;
    int count;

    PDR1 = 0x60;
    for(count=0; count < 16; count++)
        asm("nop");
    temp = PDR1;

    if((temp&0x1) != 0x00)
    { /* Pad1 is diconnected. */
        ExitToMultiplayer();
    }
}

#include "../mf_address.h"


//---------------------------------------------------------------------------------------

//#define _DEBUGON
#ifdef _DEBUGON
static void _debug(unsigned char index, unsigned long val)
{
    ((volatile unsigned long*)(0x06004000))[index] = val;
}
#endif


//---------------------------------------------------------------------------------------
int main(void)
{
    /* In the case no pad connected, emergency exit to multiplayer. */
    pad_init();
    TestPadConnection();

    /* Pointer to the parameters (length, execution start address). */
    unsigned long* params = (unsigned long*)(FC_ARP_ADDRESS + FC_PARAMS_OFFSET);
    /* Retrieve each parameters. */
    unsigned char* src_adr = (unsigned char*)(FC_ARP_ADDRESS+FC_DATA_OFFSET);
    unsigned long length   =                 params[FC_PDATALEN_INDEX];
    unsigned char* dst_adr = (unsigned char*)params[FC_EXEADDRS_INDEX];

#ifdef _DEBUGON
    { // DEBUG STT
        _debug(0, 42);
        _debug(1, (unsigned long)src_adr);
        _debug(2, length);
        _debug(3, (unsigned long)dst_adr);
        asm("nop"); asm("nop"); asm("nop"); asm("nop");
        //while(1) {;}
    } // DEBUG END
#endif

    /* Copy the target program from the buffer to the execution area. */
    unsigned long ret;
    for(ret=0; ret<length; ret++)
    {
        dst_adr[ret] = src_adr[ret];
    }

//    { /* Tried to implement decompression, but it was buggy (stack too small ?). */
//      //#include "../../../satcom_lib/sc_common.h"
//#ifdef _DEBUGON
//        ret = decomp_exec(src_adr, length, dst_adr);
//        if(ret == 0)
//        { /* Decompression error. */
//            ExitToMultiplayer();
//        }
//#else
//        ExitToMultiplayer();
//#endif
//    }

    /* Execute the target program (-> quit this program).
     * (code scrap from antime's satclient.c, http://www.iki.fi/~antime/)
     */
    void (*pFun)(void);
    pFun = (void(*)(void))dst_adr;
    (*pFun)();

    return 0;
}

