giz menu works
[libpicofe.git] / gp2x / 940ctl.c
index 5c53761..075b827 100644 (file)
@@ -1,3 +1,6 @@
+// Code for communication with ARM940 and control of it.\r
+// (c) Copyright 2007, Grazvydas "notaz" Ignotas\r
+\r
 #include <stdio.h>\r
 #include <stdlib.h>\r
 #include <string.h>\r
@@ -11,8 +14,9 @@
 #include "gp2x.h"\r
 #include "emu.h"\r
 #include "menu.h"\r
-#include "asmutils.h"\r
 #include "mp3.h"\r
+#include "../common/arm_utils.h"\r
+#include "../common/menu.h"\r
 #include "../../Pico/PicoInt.h"\r
 #include "../../Pico/sound/mix.h"\r
 \r
 extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */\r
 extern volatile unsigned long  *gp2x_memregl;\r
 \r
+extern int reset_timing;\r
 static unsigned char *shared_mem = 0;\r
 static _940_data_t *shared_data = 0;\r
 _940_ctl_t *shared_ctl = 0;\r
 unsigned char *mp3_mem = 0;\r
 \r
-#define MP3_SIZE_MAX (0x1000000 - 4*640*480)\r
+#define MP3_SIZE_MAX (0x400000 + 0x800000) // 12M\r
+#define CODE940_FILE "pico940.bin"\r
 \r
 int crashed_940 = 0;\r
 \r
@@ -65,8 +71,10 @@ static int   writebuff_ptr = 0;
 \r
 \r
 /* OPN Mode Register Write */\r
-static void set_timers( int v )\r
+static int set_timers( int v )\r
 {\r
+       int change;\r
+\r
        /* b7 = CSM MODE */\r
        /* b6 = 3 slot mode */\r
        /* b5 = reset b */\r
@@ -75,6 +83,7 @@ static void set_timers( int v )
        /* b2 = timer enable a */\r
        /* b1 = load b */\r
        /* b0 = load a */\r
+       change = (ST_mode ^ v) & 0xc0;\r
        ST_mode = v;\r
 \r
        /* reset Timer b flag */\r
@@ -84,6 +93,8 @@ static void set_timers( int v )
        /* reset Timer a flag */\r
        if( v & 0x10 )\r
                ST_status &= ~1;\r
+\r
+       return change;\r
 }\r
 \r
 /* YM2612 write */\r
@@ -92,16 +103,25 @@ static void set_timers( int v )
 /* returns 1 if sample affecting state changed */\r
 int YM2612Write_940(unsigned int a, unsigned int v)\r
 {\r
-       int addr; //, ret=1;\r
+       int addr;\r
+       int upd = 1;    /* the write affects sample generation */\r
 \r
        v &= 0xff;      /* adjust to 8 bit bus */\r
        a &= 3;\r
 \r
+       //printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);\r
+\r
        switch( a ) {\r
        case 0: /* address port 0 */\r
+               if (!addr_A1 && ST_address == v)\r
+                       return 0;       /* address already selected, don't send this command to 940 */\r
                ST_address = v;\r
+               /* don't send DAC or timer related address changes to 940 */\r
+               if (!addr_A1 && (v & 0xf0) == 0x20 &&\r
+                       (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a))\r
+                               return 0;\r
                addr_A1 = 0;\r
-               //ret=0;\r
+               upd = 0;\r
                break;\r
 \r
        case 1: /* data port 0    */\r
@@ -145,14 +165,16 @@ int YM2612Write_940(unsigned int a, unsigned int v)
                                }\r
                                return 0;\r
                        case 0x27:      /* mode, timer control */\r
-                               set_timers( v );\r
-                               break; // other side needs ST.mode for 3slot mode\r
+                               if (set_timers( v ))\r
+                                       break; // other side needs ST.mode for 3slot mode\r
+                               return 0;\r
                        case 0x2a:      /* DAC data (YM2612) */\r
                                dacout = ((int)v - 0x80) << 6;  /* level unknown (notaz: 8 seems to be too much) */\r
                                return 0;\r
                        case 0x2b:      /* DAC Sel  (YM2612) */\r
                                /* b7 = dac enable */\r
                                dacen = v & 0x80;\r
+                               upd = 0;\r
                                break; // other side has to know this\r
                        default:\r
                                break;\r
@@ -162,9 +184,11 @@ int YM2612Write_940(unsigned int a, unsigned int v)
                break;\r
 \r
        case 2: /* address port 1 */\r
+               if (addr_A1 && ST_address == v)\r
+                       return 0;\r
                ST_address = v;\r
                addr_A1 = 1;\r
-               //ret=0;\r
+               upd = 0;\r
                break;\r
 \r
        case 3: /* data port 1    */\r
@@ -177,16 +201,27 @@ int YM2612Write_940(unsigned int a, unsigned int v)
                break;\r
        }\r
 \r
+       //printf("ym pass\n");\r
+\r
        if(currentConfig.EmuOpt & 4) {\r
-               /* queue this write for 940 */\r
-               if (writebuff_ptr < 2047) {\r
-                       if (shared_ctl->writebuffsel == 1) {\r
-                               shared_ctl->writebuff0[writebuff_ptr++] = (a<<8)|v;\r
-                       } else {\r
-                               shared_ctl->writebuff1[writebuff_ptr++] = (a<<8)|v;\r
+               UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;\r
+\r
+               /* detect rapid ym updates */\r
+               if (upd && !(writebuff_ptr & 0x80000000) && Pico.m.scanline < 224) {\r
+                       int mid = Pico.m.pal ? 68 : 93;\r
+                       if (Pico.m.scanline > mid) {\r
+                               //printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, Pico.m.scanline);\r
+                               writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;\r
+                               writebuff_ptr |= 0x80000000;\r
+                               //printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, Pico.m.scanline, addr, v, upd);\r
                        }\r
+               }\r
+\r
+               /* queue this write for 940 */\r
+               if ((writebuff_ptr&0xffff) < 2047) {\r
+                       writebuff[writebuff_ptr++ & 0xffff] = (a<<8)|v;\r
                } else {\r
-                       printf("warning: writebuff_ptr > 2047\n");\r
+                       printf("warning: writebuff_ptr > 2047 ([%i] %02x)\n", a, v);\r
                }\r
        }\r
 \r
@@ -255,7 +290,7 @@ static void wait_busy_940(int job)
                gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);\r
        printf("last lr: %08x, lastjob: %i\n", shared_ctl->last_lr, shared_ctl->lastjob);\r
 \r
-       strcpy(menuErrorMsg, "940 crashed.");\r
+       strcpy(menuErrorMsg, "940 crashed, too much overclock?");\r
        engineState = PGS_Menu;\r
        crashed_940 = 1;\r
 }\r
@@ -280,6 +315,12 @@ void YM2612PicoStateLoad_940(void)
 {\r
        int i, old_A1 = addr_A1;\r
 \r
+       /* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */\r
+       add_job_940(JOB940_PICOSTATELOAD);\r
+       if (CHECK_BUSY(JOB940_PICOSTATELOAD)) wait_busy_940(JOB940_PICOSTATELOAD);\r
+\r
+       writebuff_ptr = 0;\r
+\r
        // feed all the registers and update internal state\r
        for(i = 0; i < 0x100; i++) {\r
                YM2612Write_940(0, i);\r
@@ -291,8 +332,6 @@ void YM2612PicoStateLoad_940(void)
        }\r
 \r
        addr_A1 = old_A1;\r
-\r
-       add_job_940(JOB940_PICOSTATELOAD);\r
 }\r
 \r
 \r
@@ -323,7 +362,7 @@ void sharedmem_init(void)
        shared_data = (_940_data_t *) (shared_mem+0x100000);\r
        /* this area must not get buffered on either side */\r
        shared_ctl =  (_940_ctl_t *)  (shared_mem+0x200000);\r
-       mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x3000000);\r
+       mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2400000);\r
        if (mp3_mem == MAP_FAILED)\r
        {\r
                printf("mmap(mp3_mem) failed with %i\n", errno);\r
@@ -372,15 +411,15 @@ void YM2612Init_940(int baseclock, int rate)
                binpath[1023] = 0;\r
                for (i = strlen(binpath); i > 0; i--)\r
                        if (binpath[i] == '/') { binpath[i] = 0; break; }\r
-               strcat(binpath, "/code940.bin");\r
+               strcat(binpath, "/" CODE940_FILE);\r
 \r
                fp = fopen(binpath, "rb");\r
                if(!fp)\r
                {\r
-                       memset(gp2x_screen, 0, 320*240);\r
-                       gp2x_text_out8(10, 100, "failed to open required file:");\r
-                       gp2x_text_out8(10, 110, "code940.bin");\r
-                       gp2x_video_flip();\r
+                       memset(gp2x_screen, 0, 320*240*2);\r
+                       text_out16(10, 100, "failed to open required file:");\r
+                       text_out16(10, 110, CODE940_FILE);\r
+                       gp2x_video_flip2();\r
                        printf("failed to open %s\n", binpath);\r
                        exit(1);\r
                }\r
@@ -456,9 +495,9 @@ int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)
        else memset32(buffer, 0, length<<stereo);\r
 \r
        if (shared_ctl->writebuffsel == 1) {\r
-               shared_ctl->writebuff0[writebuff_ptr] = 0xffff;\r
+               shared_ctl->writebuff0[writebuff_ptr & 0xffff] = 0xffff;\r
        } else {\r
-               shared_ctl->writebuff1[writebuff_ptr] = 0xffff;\r
+               shared_ctl->writebuff1[writebuff_ptr & 0xffff] = 0xffff;\r
        }\r
        writebuff_ptr = 0;\r
 \r
@@ -562,11 +601,15 @@ void mp3_start_play(FILE *f, int pos) // pos is 0-1023
 \r
        if (loaded_mp3 != f)\r
        {\r
-               // printf("loading mp3... "); fflush(stdout);\r
+               if (PicoMessage != NULL)\r
+               {\r
+                       fseek(f, 0, SEEK_END);\r
+                       if (ftell(f) > 2*1024*1024)\r
+                               PicoMessage("Loading MP3...");\r
+               }\r
                fseek(f, 0, SEEK_SET);\r
                fread(mp3_mem, 1, MP3_SIZE_MAX, f);\r
-               // if (feof(f)) printf("done.\n");\r
-               // else printf("done. mp3 too large, not all data loaded.\n");\r
+               if (!feof(f)) printf("Warning: mp3 was too large, not all data loaded.\n");\r
                shared_ctl->mp3_len = ftell(f);\r
                loaded_mp3 = f;\r
 \r
@@ -575,6 +618,7 @@ void mp3_start_play(FILE *f, int pos) // pos is 0-1023
                        if (CHECK_BUSY(JOB940_MP3DECODE)) wait_busy_940(JOB940_MP3DECODE);\r
                        add_job_940(JOB940_INVALIDATE_DCACHE);\r
                }\r
+               reset_timing = 1;\r
        }\r
 \r
        // seek..\r