
#include "copystub.h"



#ifdef COPYSTUB_TEST
#   define HRAM_STT 200
#   define HRAM_END 210

#   define LRAM_STT 100
#   define LRAM_END 110

/* When debugging on PC, display crappy debug messages to stdout. */
#   define USE_CRAPPY_DBG
#   include <stdio.h>
#   define CRAP_DBG(STR) printf("DBG=%s\n", STR)


#else

/* Set Saturn compile options here. */
//#define USE_CRAPPY_DBG
#   ifdef USE_CRAPPY_DBG
#       include "../debugger/scd_crappy_dbg.h"
#   else
#       define CRAP_DBG(STR) 
#   endif

// HRAM 0x06004000 ~ 0x060C0000-4KB for copystub
#   define HRAM_STT 0x06004000
#   define HRAM_END COPYSTUB_START_ADRESS

// LRAM
#   define LRAM_STT 0x00200000
#   define LRAM_END 0x00300000
#endif





#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))



#ifdef COPYSTUB_TEST
int main(int argc, char** argv)
#else
int main(void)
#endif
{
    /* Retrieve the parameters (buffer address, length, execution start address). */
#ifdef COPYSTUB_TEST
    unsigned char* src_stt = (unsigned char*)(atoi(argv[1]) & 0x0FFFFFFF);
    unsigned long length   =                  atoi(argv[2]);
    unsigned char* dst_stt = (unsigned char*)(atoi(argv[3]) & 0x0FFFFFFF);
#else
    sc_global_t* sc_global = (sc_global_t*)SC_GLOBAL_DATA_ADR;

    unsigned char* src_stt = (unsigned char*)(sc_global->cs_src_stt & 0x0FFFFFFF);
    unsigned long length   =                  sc_global->cs_lenght;
    unsigned char* dst_stt = (unsigned char*)(sc_global->cs_dst_stt & 0x0FFFFFFF);
#endif
    unsigned char* dst_end = dst_stt + length;

    /* Data used for copy/erase. */
    unsigned char* ptr1;
    unsigned char* ptr2;
    /* Data used for erase only. */
    unsigned long erase_area[2/*start-end*/];
    unsigned char i, j;


    CRAP_DBG("CS::copyPG");
    CRAP_DBG("DBG");

    /* Copy the target program from the source buffer to the execution area. */
    if(src_stt != dst_stt)
    { /* In the case src=dst, don't need to copy anything. */
        if( (dst_stt >  src_stt         )
        &&  (dst_stt < (src_stt+length)) )
        { /* Special case when buffers overlap. */
            ptr1 = src_stt+length - 1;
            ptr2 = dst_end        - 1;
            while((ptr2+1) != dst_stt)
            {
#ifdef COPYSTUB_TEST
                printf("Copy byte from index %3d to %3d [backward]\n", ptr1, ptr2);
                ptr1--;
                ptr2--;
#else
                *(ptr2--) = *(ptr1--);
#endif
            }
        }
        else
        { /* Normal copy when buffers don't overlap. */
            ptr1 = src_stt;
            ptr2 = dst_stt;
            while(ptr2 != dst_end)
            {
#ifdef COPYSTUB_TEST
                printf("Copy byte from index %3d to %3d\n", ptr1, ptr2);
                ptr1++;
                ptr2++;
#else
                *(ptr2++) = *(ptr1++);
#endif
            }
        }
    }

// Note: when uploading code from-to 0x06004000, copystub freezes.
//  I don't know why, but removing the memory erase code makes it working, so it is disabled for the moment.
//  (please do program that init memory before using it, and this bug will be fixed %) )
// 
//    /* Clear High/Low RAM */
//    CRAP_DBG("CS::clear");
//    for(i=0; i<2; i++)
//    { /* HRAM-LRAM */
//        for(j=0; j<2; j++)
//        { /* cropped zone1-cropped zone2 */
//
//            if(i==0)
//            { /* Erase LRAM. */
//                /* In order not to erase target program, crop the zone to erase. */
//                if(j==0)
//                { /* Start zone. */
//                    erase_area[0] = LRAM_STT;
//                    erase_area[1] = CLAMP((unsigned long)dst_stt, LRAM_STT, LRAM_END);
//                }
//                else
//                { /* End zone. */
//                    erase_area[0] = CLAMP((unsigned long)dst_end, LRAM_STT, LRAM_END);
//                    erase_area[1] = LRAM_END;
//                }
//            }
//            else
//            { /* Erase HRAM. */
//                /* In order not to erase target program, crop the zone to erase. */
//                if(j==0)
//                { /* Start zone. */
//                    erase_area[0] = HRAM_STT;
//                    erase_area[1] = CLAMP((unsigned long)dst_stt, HRAM_STT, HRAM_END);
//                }
//                else
//                { /* End zone. */
//                    erase_area[0] = CLAMP((unsigned long)dst_end, HRAM_STT, HRAM_END);
//                    erase_area[1] = HRAM_END;
//                }
//            }
//
//            /* Erase cropped zone. */
//            ptr1 = (unsigned char*)erase_area[0];
//            ptr2 = (unsigned char*)erase_area[1];
//            while(ptr1 != ptr2)
//            {
//#ifdef COPYSTUB_TEST
//                printf("Erase byte at index %3d\n", ptr1);
//                ptr1++;
//#else
//                *(ptr1++) = 0;
//#endif
//            }
//        }
//    }


    /* Execute the target program (-> quit this program).
     * (code scrap from antime's satclient.c, http://www.iki.fi/~antime/)
     */
    CRAP_DBG("CS::EXEC");

#ifdef COPYSTUB_TEST
    printf("Execute code from index %3d\n", dst_stt);
#else
    void (*pFun)(void);
    pFun = (void(*)(void))dst_stt;
    (*pFun)();
#endif

    return 0;
}
