/**
 *  Sega Saturn SatCom ARP FirmWare
 *  by cafe-alpha.
 *  WWW: http://ppcenter.free.fr/
 *
 *  Based on Sega Saturn VDP1 example program
 *  by Charles MacDonald
 *  WWW: http://cgfm2.emuviews.com
**/

#include "shared.h"


/* Define line filled with spaces in order to erase a line. */
char* empty_line = "                                     ";



/*------------------------------------------------------------------------*/
/*- ARP flashing related.                                                -*/
#ifdef FLASHMENU_INC

/* Gather all ARP data in a single structure. */

typedef struct
{
    char* name;          /* Description. */
    char* path;          /* Filename.    */
    unsigned char media; /* PC - CD-ROM  */

} arp_fw_t;
#define ARP_FW_MAXCOUNT 64
arp_fw_t arp_fw[ARP_FW_MAXCOUNT];



/**
 * Read the firmwares list file.
**/
unsigned char _fw_list_buff[16*1024];
char* _scfw_name = "SatCom firmware by cafe-alpha (PC)  ";
char* _scfw_path = "ARP\\FIRM.BIN";
int fw_init_list(void)
{
#ifdef FLASHMENU_CD_ADD
    unsigned long len, i;
    unsigned char c, d;
    int count;
    int field;

    /* Read firmware list from CD-ROM. */
    sc_file_t* fh = sc_fopen(/*SC_FILE_CDROM*/SC_FILE_CDROM, "ARP\\FWLIST.TXT");
    len = sc_fread(fh, 0/*offset*/, sizeof(_fw_list_buff)-1/*size*/, (void*)_fw_list_buff/*buff*/);
    sc_fclose(fh);

    /* Init list. */
    _fw_list_buff[len] = '\0';
    count = 0;
    field = 0;
    arp_fw[0].name  = NULL;
    arp_fw[0].path  = NULL;
    arp_fw[0].media = 0;

    /* Parse file contents. */
    if(len != 0)
    {
        arp_fw[count].name = (char*)_fw_list_buff;
        d = '\n';
        for(i=0; i<len; i++)
        {
            c = _fw_list_buff[i];

            /* New line ? -> new entry */
            if((c >= ' ') && (d < ' '))
            {
                if(count < (ARP_FW_MAXCOUNT-1)) count++;
                field = 0;
                arp_fw[count-1].name = _fw_list_buff + i;
                /* Init other fields with dummy values. */
                arp_fw[count-1].path  = _fw_list_buff + i;
                arp_fw[count-1].media = SC_FILE_PC;
            }
            /* Comma ? -> next field */
            if(d == ',')
            {
                if(field < 2) field++;
                switch(field)
                {
                case(0):
                case(1):
                    scd_logout(" SET M", 0);
                    arp_fw[count-1].media = (c == 'P' ? SC_FILE_PC : SC_FILE_CDROM);
                    break;

                case(2):
                default:
                    scd_logout(" SET P", 0);
                    arp_fw[count-1].path = _fw_list_buff + i;
                    break;
                }
            }

            d = c;
            /* Terminate strings. */
            if((c < ' ') || (c == ',')) _fw_list_buff[i] = '\0';
        }

        /* Add terminator entry. */
        arp_fw[count].name  = NULL;
        arp_fw[count].path  = NULL;
        arp_fw[count].media = 0;
    }
    return count;

#else
    /* In the case we don't use CD-ROM, add SatCom FW from PC. */
    arp_fw[0].name  = _scfw_name;
    arp_fw[0].path  = _scfw_path;
    arp_fw[0].media = SC_FILE_PC;

    /* Don't forget the terminator. */
    arp_fw[1].name  = NULL;
    arp_fw[1].path  = NULL;
    arp_fw[1].media = 0;

    return 1;
#endif
}

/**
 * Prompt the user to select a firmware.
**/
int fw_get_index(unsigned short row)
{
    pad_t pad;
    int index = 0;

    /* Display confirmation message. */
    _printf( 2, row+0, COLOR_LIME, " Select firmware with arrow keys:   ");
    _printf( 2, row+1, COLOR_LIME, " Confirm: A or C, cancel with B     ");
    _printf( 2, row+2, COLOR_BG_FG(COLOR_RED, COLOR_YELLOW), " FLASH FIRMWARE AT YOUR OWN RISKS ! ");

    /* Main loop */
    for(;;)
    {
        /* SatCom: if needed, transfer data. */
        sc_check();

        /* Wait for V-Blank. */
        wait_vblank_out();
        wait_vblank_in();


        /* Poll joypad */
        pad_read(&pad);

        /* Change selection ? */
        if((pad.delta & PAD_LEFT) && (index >= 1))
        {
            index--;
        }
        if((pad.delta & PAD_RIGHT) && (arp_fw[index+1].name != NULL))
        {
            index++;
        }
        /* Display selected firmware. */
        _printf( 2, row+3, COLOR_AQUA, arp_fw[index].name);


        if((pad.delta & PAD_A)
        || (pad.delta & PAD_C))
        { /* User Confirmed. */
            _printf( 2, row+0, 0x20, empty_line);
            _printf( 2, row+1, 0x20, empty_line);
            _printf( 2, row+2, 0x20, empty_line);
            _printf( 2, row+3, 0x20, empty_line);
            return index;
        }

        if(pad.delta & PAD_B)
        { /* User canceled. */
            break;
        }
    }

    _printf( 2, row+0, 0x20, empty_line);
    _printf( 2, row+1, 0x20, empty_line);
    _printf( 2, row+2, 0x20, empty_line);
    _printf( 2, row+3, 0x20, empty_line);
    return -1;
}



/**
 * Callback used to display progress when reading
 * firmware data from CD-ROM.
**/
typedef struct fread_callback_t
{
    unsigned char row; /* Row where to write progress. */
} fread_callback_t;
fread_callback_t _fread_callback_data;
void fread_callback(unsigned long data_transfer, unsigned long data_total, void* callback_data)
{
    char txt[256];
    fread_callback_t* dat = (fread_callback_t*)callback_data;

    sprintf(txt, "Loading data = %3d / 100 ...    ", (int)((100*data_transfer)/data_total));
    _printf(2, dat->row, COLOR_SILVER, txt);
}



/**
 * Write data to flash memory.
 * src_len unit is byte.
 * row is the row where to write progress status.
**/
void flash_writemem(volatile unsigned short* src, unsigned long src_len, unsigned long erase_len, unsigned short row)
{
    char buffer[50];
    unsigned long rom_page = 0;
    unsigned long rom_len = src_len / 128 / 2;
    unsigned long ers_len = erase_len / 128 / 2;
    volatile unsigned short* const dst = (unsigned short*)0x22000000;

    /* Write last page, even if the rom size is not a multiple of 256 bytes. */
    if( ((rom_len+1) * 128 * 2) <= (256*1024) )
    {
        rom_len = rom_len+1;
    }

    /* Erase all data (useless ?). */
    _printf( 2, row, 0x20, empty_line);
    for (rom_page = 0; rom_page <= ers_len; rom_page++)
    {
        sprintf(buffer, "Erasing Page 0x%04X of 0x%04X", (int)rom_page, (int)ers_len);
        _printf( 2, row, COLOR_WHITE, buffer);

        sc_flash_write(NULL/*erase*/, dst + (rom_page * 128));
    }

    /* Erase, then write data. */
    _printf( 2, row, 0x20, empty_line);
    for(rom_page = 0; rom_page <= rom_len; rom_page++)
    {
        sprintf(buffer, "Writing Page 0x%04X of 0x%04X", (int)rom_page, (int)rom_len);
        _printf( 2, row, COLOR_WHITE, buffer);

        sc_flash_write(NULL/*erase*/, dst + (rom_page * 128));
        sc_flash_write(src + (rom_page * 128), dst + (rom_page * 128));
    }
}


#endif // FLASHMENU_INC
/*- ARP flashing related.                                                -*/
/*------------------------------------------------------------------------*/




/*
 * Index of the mode page we are using (switched with L/R buttons).
 * Also, index of the protocol we are currently editing. (0/1)
 */
unsigned char mode_index = 0;


/*
 * Refresh the state assigned to the X,Y,Z buttons.
 */
int xyz_row = 0;
void display_xyz_mode(void)
{
    int row = xyz_row;

    if(mode_index == 0)
    { /* Main mode when L/R are not pressed. */
#ifdef FLASHMENU_INC
        _printf(2, row++, COLOR_BG_FG(COLOR_RED, COLOR_WHITE), "X: Flash FirmWare to Action Replay  ");
#else
        _printf(2, row++, COLOR_WHITE, "X         : Unavailable             ");
#endif
#ifdef SC_USE_CDROM
        _printf(2, row++, COLOR_WHITE, "Y         : Unlock CD-ROM           ");
#else
        _printf(2, row++, COLOR_WHITE, "Y         : Unavailable             ");
#endif // SC_USE_CDROM
        _printf(2, row++, COLOR_WHITE, "Z         : Turn debug mode OFF/ON  ");
    }
    else
    { /* Sub mode when L/R is pressed. */

        _printf(2, row++, COLOR_YELLOW, "X         : SatCom log test         ");
        _printf(2, row++, COLOR_YELLOW, "Y         : SatCom prompt test      ");
#ifdef SC_USE_CDROM
        _printf(2, row++, COLOR_YELLOW, "Z         : SatCom CD-ROM test      ");
#else
        _printf(2, row++, COLOR_YELLOW, "Z         : Unavailable             ");
#endif // SC_USE_CDROM
    }

}



/*------------------------------------------------------------------------*/
/*- SatCom logging related.                                              -*/
void satcom_debug_print(int col, int row, char* string, ...)
{
    char buff[50];
    va_list ap;
    va_start(ap, string);
    vsprintf(buff, string, ap);
    va_end(ap);
    _printstr(col+1, row+2, COLOR_WHITE, buff);
}

#define DBG_ROW_START 11
#define DBG_ROW_COUNT 32
int _debug_row = 0;
void satcom_debug_console(char* string, ...)
{
    char* empty_line_half = "                   ";
    int col_id = (_debug_row < (DBG_ROW_COUNT/2) ? 0 : 1);

    /* Format debug message. */
    char buff[50];
    va_list ap;
    va_start(ap, string);
    vsprintf(buff, string, ap);
    va_end(ap);

    /* Display debug message. */
    _printstr(1 + col_id*19/*col*/, DBG_ROW_START+_debug_row - col_id*(DBG_ROW_COUNT/2), COLOR_GRAY, buff);

    /* Update line number. */
    _debug_row = ((_debug_row + 1) % DBG_ROW_COUNT);
    col_id = (_debug_row < (DBG_ROW_COUNT/2) ? 0 : 1);
    /* Clear next line. */
    _printstr(1 + col_id*19/*col*/, DBG_ROW_START+_debug_row - col_id*(DBG_ROW_COUNT/2), COLOR_GRAY, empty_line_half);
}






void _main(void)
{
    pad_t pad;
    char* str = NULL;

    /* SatCom: initialization. */
    sc_init();

    /* SatCom: retrieve informations from backup memory. */
    sc_bup_data_t prot;
    sc_getprot(&prot); /* Automatically initialized when nothing in backup memory. */

    /* SatCom: debugger mode check I/O.
     * (here is a good timing for debugging programs I/O, because
     * screen registers hasn't been modified yet).
     * In order to upload code here, simply send from PC when
     * Saturn "Produced by or under license etc" screen is displayed.
     * Of course, you need to enable the debugger mode to do this.
     */
    if(prot.debug == 1)
    {
        do
        {
            sc_check();
            /* Poll joypad */
            pad_read(&pad);
        } while(pad.new == 0);
    }



    vdp_init();
    conio_init();
    pad_init();

    /* Set up VDP1 to appear under VDP2 graphics (0=hide, 1-7=visible) */
    PRISA = 0x0101;
    PRISB = 0x0101;
    PRISC = 0x0101;
    PRISD = 0x0101;

    /* Set up VDP1 registers */
    TVMR = 0x0000;
    FBCR = 0x0000;
    PTMR = 0x0002;
    EWDR = COLOR(7,7,7);    /* Erase color: gray */
    EWLR = 0x0000;          /* Erase range: (0,0) -> (352,240) */
    EWRR = 0x50DF;



    /* Init starfield stuff. */
    sf_init();


    /* Start Filling VDP1 command list with buffer common stuff. */
    vdp1_add_system_clip(320, 224);
    vdp1_add_user_clip(0, 0, 319, 223);
    vdp1_add_local_coords(0, 0);

    /* Set VDP1 command list stuff. */
    vdp1_mesh(0);
    vdp1_start(2/*double buffering*/, 2000/*max commands count.*/);

    /* Screen on */
    TVMD = 0x8000;
    TVMR = 0x0000;
    FBCR = 0x0001;
    EWRR = 0x50DF;



    /* Display SatCom-related log messages on screen. */
    if(prot.debug == 2)
    {
        _printf(2, 1/*row*/, COLOR_YELLOW, "=/ SatCom DEBUG  (Start to quit) \\=");
        /* Set debug callbacks. */
        scl_set_callbacks(satcom_debug_print, satcom_debug_console);

        do
        {
            sc_check();

            /* Wait for V-Blank. */
            wait_vblank_out();
            wait_vblank_in();

            /* Draw starfield stuff on the screen. */
            sf_animate();
            sf_draw();
            vdp1_flip();

            /* Poll joypad */
            pad_read(&pad);
        } while(pad.new == 0);

        /* Reset debug callbacks. */
        scl_set_callbacks(NULL, NULL);
        /* Clear debug stuff on screen. */
        int i;
        for(i=0; i<28; i++)
        {
            _printf(0/*col*/, i/*row*/, COLOR_WHITE, empty_line, 0);
        }
    }




    /* Print message */
    int row=1, datarow;

#ifdef FLASHMENU_INC
#   ifdef FLASHMENU_CD_ADD
    /* When use from CD. */
    //_printf(2, row++, COLOR_TEAL, "=/  Saturn Communication Live CD  \\=");
    _printf(2, row++, COLOR_WHITE, "=/ S.A.T.U.R.N contest - Live CD \\=");
#   else
    /* When use as a binary to upload. */
    //_printf(2, row++, COLOR_TEAL, "=/  Saturn Communication Program  \\=");
    _printf(2, row++, COLOR_WHITE, "=/ S.A.T.U.R.N contest - Program \\=");
#   endif // FLASHMENU_CD_ADD
#else
    /* When use as an ARP firmware. */
    //_printf(2, row++, COLOR_TEAL, "=/  Saturn Communication FirmWare \\=");
    _printf(2, row++, COLOR_WHITE, "=/ S.A.T.U.R.N contest - FirmWare\\=");
#endif // FLASHMENU_INC
    _printf(2, row++, COLOR_YELLOW, "= By cafe-alpha (ppcenter.free.fr) =");
    _printf(2, row++, COLOR_YELLOW, "Build on " RELEASE_DATE);
    _printf(2, row++, COLOR_SILVER, "From VDP1EX by Charles MacDonald    ");
    row++;
    _printf(2, row++, COLOR_BLUE,   "L/R       : Switch selection screen ");
    _printf(2, row++, COLOR_WHITE,  "Left/Right: Select main protocol    ");
    _printf(2, row++, COLOR_WHITE,  "Up/Down   : Select ARP address      ");
    xyz_row = row; row+=3; /* Skip 3 lines for X,Y,Z functions. */
    _printf(2, row++, COLOR_WHITE,  "Start     : Exit to multiplayer     ");
    /* Help screen end. */
    row++;
    datarow=row;





    /* Main loop */
    unsigned short fctr=0;

    /* Force mode display. */
    mode_index = 0;
    display_xyz_mode();
    unsigned char prot_refresh = 1;

    for(;;)
    { fctr++;

        /* SatCom: if needed, transfer data. */
        sc_check();

        /* Wait for V-Blank. */
        wait_vblank_out();
        wait_vblank_in();

        /* Poll joypad */
        pad_read(&pad);


        /* Start - Quit program */
        if(pad.new & PAD_START)
        { /* Exit to multiplayer. */
            int (*pFun)(void);
            pFun = (int(*)(void))0x600026C;
            (*pFun)();
        }



        /* Update mode. */
        unsigned char prev_mode_index = mode_index;
        if((pad.delta & PAD_LBUTTON) || (pad.delta & PAD_RBUTTON))
        {
            mode_index = 1-mode_index;
        }
        /* Need to refresh screen ? */
        if(mode_index != prev_mode_index)
        {
            display_xyz_mode();
            prot_refresh = 1;
        }



        /* Select protocol. */
        if(pad.delta & PAD_LEFT)
        {
            if(prot.type[mode_index] == 0)
                prot.type[mode_index] = SC_PROTOCOLS_COUNT - 1;
            else
                prot.type[mode_index] = (prot.type[mode_index] - 1) % SC_PROTOCOLS_COUNT;
            prot_refresh = 1;
        }
        if(pad.delta & PAD_RIGHT)
        {
            prot.type[mode_index] = (prot.type[mode_index] + 1) % SC_PROTOCOLS_COUNT;
            prot_refresh = 1;
        }
        /* Select Action Replay register address. */
        if( (prot.type[0] == SC_PROT_LEGACY) || (prot.type[0] == SC_PROT_EXTENDED)
        ||  (prot.type[1] == SC_PROT_LEGACY) || (prot.type[1] == SC_PROT_EXTENDED) )
        {
            if(pad.delta & PAD_DOWN)
            {
                if(prot.arp_address == 0)
                    prot.arp_address = 2;
                else
                    prot.arp_address = (prot.arp_address - 1) % 3;
                prot_refresh = 1;
            }
            if(pad.delta & PAD_UP)
            {
                prot.arp_address = (prot.arp_address + 1) % 3;
                prot_refresh = 1;
            }
        }





        /* Print selected protocol. */
        row=datarow;


        if(prot_refresh != 0)
        {
            sc_setprot(&prot);
            if(mode_index == 0)
            {
                _printf( 2, row+0, COLOR_LIME, "Main Protocol:                       ");
            }
            else
            {
                _printf( 2, row+0, COLOR_LIME, "Sub Protocol :                       ");
            }
            _printf(17, row+0, COLOR_AQUA, sc_get_protname(prot.type[mode_index]));

            _printf( 2, row+1, 0x20, empty_line);
            _printf( 2, row+2, 0x20, empty_line);
            _printf( 2, row+3, 0x20, empty_line);
            if( (prot.type[0] == SC_PROT_LEGACY) || (prot.type[0] == SC_PROT_EXTENDED)
            ||  (prot.type[1] == SC_PROT_LEGACY) || (prot.type[1] == SC_PROT_EXTENDED) )
            {
                _printf( 2, row+1, COLOR_LIME, "AR Type :                            ");
                switch(prot.arp_address)
                {
                case(0x01):
                    _printf(12, row+1, COLOR_AQUA, "EMS");
                    break;
                case(0x02):
                    _printf(12, row+1, COLOR_AQUA, "Datel");
                    break;
                default:
                    _printf(12, row+1, COLOR_AQUA, "Auto Detect");
                }
                /* Display vendor/device ID */
                char buffer[50];
                sprintf(buffer, "Vendor ID: 0x%04X Device ID: 0x%04X", (int)sc_flash_getid(1), (int)sc_flash_getid(0));
                _printf(2, row+2, COLOR_GRAY, buffer);
            }
            _printf( 2, row+3, COLOR_LIME, "DBG flag:                            ");
            switch(prot.debug)
            {
            default:
            case(0):
                /* Display infos + starfield on screen. */
                _printf(12, row+3, COLOR_AQUA, "Normal use");
                break;
            case(1):
                /* Don't change screen settings. (better compatibility when executing binaries) */
                _printf(12, row+3, COLOR_AQUA, "No screen on next startup");
                break;
            case(2):
                /* Display log messages on screen. */
                _printf(12, row+3, COLOR_AQUA, "Display log to screen");
                break;
            }

            prot_refresh = 0;
        }
        row++; /* Protocol */
        row++; /* Address */
        row++; /* Vendor ID / Device ID */
        row++; /* Debug flag. */






        /*** X,Y,Z buttons related functions, START. ***/
        row=datarow + 5;
        if(mode_index == 0)
        { /* Main mode. */

#ifdef FLASHMENU_INC
            /* Flash to Action Replay / Exec firmware. */
            if(pad.delta & PAD_X)
            {
                _printf(2, row+0, COLOR_WHITE, empty_line);
                _printf(2, row+1, COLOR_WHITE, empty_line);

                _printf(2, row+0, COLOR_WHITE, "Read firmware list file ...");
                int arp_count = fw_init_list();
                if(arp_count <= 0)
                { /* No firmware found ! */
                    _printf(2, row+0, COLOR_WHITE, empty_line);
                    _printf(2, row+0, COLOR_BG_FG(COLOR_RED, COLOR_WHITE), "No firmware list found !            ");
                }
                else
                {
                    _printf(2, row+0, COLOR_WHITE, empty_line);
                    int arp_index = fw_get_index(row);
                    /* Display "select firmware" screen. */

                    if(arp_index >= 0)
                    { /* Selected a firmware. */

                        unsigned long  fw_len = 256 * 1024;
                        unsigned char* fw_adr = (unsigned char*)0x06004000;

                        /* Extract firmware to low-work RAM. */
                        _printf( 2, row, COLOR_WHITE, "  Read firmware data ...            ");

                        /* First, reset area for firmware. */
                        memset((void*)fw_adr, 0xFF, fw_len);

                        /* Read ARP firmware from CD, and update firmware lenght. */
                        sc_file_t* fh = sc_fopen(arp_fw[arp_index].media, arp_fw[arp_index].path);
                        fw_len = sc_fsize(fh);
                        if(fw_len < 2048)
                        {
                            sc_fclose(fh);
                            if(arp_fw[arp_index].media == SC_FILE_CDROM)
                            {
                                _printf( 2, row, COLOR_WHITE, "  No FirmWare file on CD-ROM !      ");
                            }
                            else
                            {
                                _printf( 2, row, COLOR_WHITE, "  No FirmWare file on your PC !     ");
                            }
                        }
                        else
                        {
                            _fread_callback_data.row = row;
                            unsigned long ret;
                            ret = sc_callback_fread(fh, 0/*offset*/, fw_len/*size*/, (void*)fw_adr/*buff*/, 
                                                    10/*callback_count*/, 
                                                    fread_callback/*callback_fct*/, (void*)(&_fread_callback_data)/*callback_data*/);
                            sc_fclose(fh);

                            /* In the case read failed, cancel operation. */
                            if(ret != fw_len)
                            {
                                _printf( 2, row, COLOR_WHITE, "  FirmWare data read failed !       ");
                            }
                            else
                            {
                                _printf( 2, row, 0x20, empty_line);
                                flash_writemem((unsigned short*)fw_adr/*SRC*/, fw_len/*LEN*/, 256*1024/*ERASE LEN*/, row/*ROW*/);
                                _printf( 2, row, COLOR_BG_FG(COLOR_RED, COLOR_YELLOW), "  Action Replay Flashing OK !       ");
                            }
                        }
                    }
                }
            }
#endif // FLASHMENU_INC

#ifdef SC_USE_CDROM
            /* Initialize the CD-ROM when testing with PAR. */
            if(pad.delta & PAD_Y)
            {
                _printf(2, row+0, COLOR_WHITE, empty_line);
                _printf(2, row+1, COLOR_WHITE, empty_line);

                _printf(2, row, COLOR_WHITE, "Unlock CD-ROM ...");
                sc_cdrom_unlock();
                _printf(2, row, COLOR_WHITE, "Unlock CD-ROM OK!");
            }
#endif // SC_USE_CDROM

            /* Select debug flag. */
            if(pad.delta & PAD_Z)
            {
                prot.debug = (prot.debug+1) % 3;
                prot_refresh = 1;
            }


        }
        else if(mode_index == 1)
        { /* Sub mode. */

            /* Send debug message to PC. */
            if(pad.new & PAD_X)
            {
                _printf(2, row+0, COLOR_WHITE, empty_line);
                _printf(2, row+1, COLOR_WHITE, empty_line);

                _printf(2, row, COLOR_WHITE, "Send dummy log (%d)", fctr);

                scd_logout("==FRAME=%d, rand1=0x%04X, rand2=0x%04X", fctr, rand()&0xFFFF, rand()&0xFFFF);
                if(fctr%2 == 0) scd_logout("**[%d]Test %d", fctr, 42);
            }

            /* Prompt message from PC. */
            if(pad.delta & PAD_Y)
            {
                _printf(2, row+0, COLOR_WHITE, empty_line);
                _printf(2, row+1, COLOR_WHITE, empty_line);

                _printf(2, row, COLOR_WHITE, "What's your name ?");
                str = scd_prompt("Your name:");
                _printf(2, row, COLOR_WHITE, empty_line);
                _printf(2, row, COLOR_WHITE, "Hello %s !", str);

            }

#ifdef SC_USE_CDROM
            /* Read file from CD-ROM. */
            if(pad.delta & PAD_Z)
            {
                _printf(2, row+0, COLOR_WHITE, empty_line);
                _printf(2, row+1, COLOR_WHITE, empty_line);

                sc_file_t* fh1 = NULL;
                unsigned long ret;
                fh1 = sc_fopen(SC_FILE_CDROM, "ABS.TXT");
                unsigned long s1 = sc_fsize(fh1);
                _printf(2, row+0, COLOR_WHITE, "ABS.TXT = %d bytes", s1);
                char buff[30];
                memset((void*)buff, '\0', sizeof(buff));
                ret = sc_fread(fh1, 0/*offset*/, sizeof(buff)-1/*size*/, (void*)buff/*buff*/);
                if(ret != 0)
                {
                    _printf(2, row+1, COLOR_WHITE, "-> %s", buff);
                }
            }
#endif // SC_USE_CDROM
        }
        /*** X,Y,Z buttons related functions, END. ***/


        /* Draw starfield stuff on the screen. */
        sf_animate();
        sf_draw();
        vdp1_flip();
    }

    vdp_shutdown();
    pad_shutdown();
}

