e006ea2494190a29178e5ca842e3f800e1ebac15
[cyclone68000.git] / Pico / Pico.cpp
1 \r
2 // This file is part of the PicoDrive Megadrive Emulator\r
3 \r
4 // This code is licensed under the GNU General Public License version 2.0 and the MAME License.\r
5 // You can choose the license that has the most advantages for you.\r
6 \r
7 // SVN repository can be found at http://code.google.com/p/cyclone68000/\r
8 \r
9 #include "PicoInt.h"\r
10 \r
11 int PicoVer=0x0030;\r
12 struct Pico Pico;\r
13 int PicoOpt=0;\r
14 \r
15 int PicoPad[2]; // Joypads, format is SACB RLDU\r
16 \r
17 int PicoInit()\r
18 {\r
19   // Blank space for state:\r
20   memset(&Pico,0,sizeof(Pico));\r
21   memset(&PicoPad,0,sizeof(PicoPad));\r
22   Pico.m.dirtyPal=1;\r
23 \r
24   // Init CPU:\r
25   SekInit();\r
26 \r
27   // Setup memory callbacks:\r
28   PicoMemInit();\r
29   PsndReset();\r
30 \r
31 #ifdef MSOUND\r
32   YM2612Init(1,7670443,PsndRate,NULL,NULL);\r
33 #endif\r
34   return 0;\r
35 }\r
36 \r
37 void PicoExit()\r
38 {\r
39 #ifdef MSOUND\r
40   YM2612Shutdown();\r
41 #endif\r
42 \r
43   memset(&Pico,0,sizeof(Pico));\r
44 }\r
45 \r
46 int PicoReset()\r
47 {\r
48   unsigned int region=0;\r
49   int support=0,hw=0,i=0;\r
50   unsigned char pal=0;\r
51 \r
52   if (Pico.romsize<=0) return 1;\r
53 \r
54   SekReset();\r
55   PsndReset();\r
56 #ifdef MSOUND\r
57   YM2612ResetChip(0);\r
58 #endif\r
59 \r
60   // Read cartridge region data:\r
61   region=PicoRead32(0x1f0);\r
62 \r
63   for (i=0;i<4;i++)\r
64   {\r
65     int c=0;\r
66     \r
67     c=region>>(i<<3); c&=0xff;\r
68     if (c<=' ') continue;\r
69 \r
70          if (c=='J') support|=1;\r
71     else if (c=='U') support|=4;\r
72     else if (c=='E') support|=8;\r
73     else\r
74     {\r
75       // New style code:\r
76       char s[2]={0,0};\r
77       s[0]=(char)c;\r
78       support|=strtol(s,NULL,16);\r
79     }\r
80 \r
81   }\r
82 \r
83   // Try to pick the best hardware value for English/60hz:\r
84        if (support&4)   hw=0x80;          // USA\r
85   else if (support&8) { hw=0xc0; pal=1; } // Europe\r
86   else if (support&1)   hw=0x00;          // Japan NTSC\r
87   else if (support&2) { hw=0x40; pal=1; } // Japan PAL\r
88   else hw=0x80; // USA\r
89 \r
90   Pico.m.hardware=(unsigned char)(hw|0x20); // No disk attached\r
91   Pico.m.pal=pal;\r
92 \r
93   return 0;\r
94 }\r
95 \r
96 static int CheckIdle()\r
97 {\r
98   unsigned char state[0x88];\r
99 \r
100   memset(state,0,sizeof(state));\r
101 \r
102   // See if the state is the same after 2 steps:\r
103   SekState(state); SekRun(0); SekRun(0); SekState(state+0x44);\r
104   if (memcmp(state,state+0x44,0x44)==0) return 1;\r
105 \r
106   return 0;\r
107 }\r
108 \r
109 // Accurate but slower frame which does hints\r
110 static int PicoFrameHints()\r
111 {\r
112   struct PicoVideo *pv=&Pico.video;\r
113   int total=0,aim=0;\r
114   int y=0;\r
115   int hint=0x400; // Hint counter\r
116 \r
117   pv->status|=0x08; // Go into vblank\r
118 \r
119   for (y=-38;y<224;y++)\r
120   {\r
121     if (y==0)\r
122     {\r
123       hint=pv->reg[10]; // Load H-Int counter\r
124       if (pv->reg[1]&0x40) pv->status&=~8; // Come out of vblank if display enabled\r
125     }\r
126 \r
127     // H-Interrupts:\r
128     if (hint<0)\r
129     {\r
130       hint=pv->reg[10]; // Reload H-Int counter\r
131       if (pv->reg[0]&0x10) SekInterrupt(4);\r
132     }\r
133 \r
134     // V-Interrupt:\r
135     if (y==-37)\r
136     {\r
137       pv->status|=0x80; // V-Int happened\r
138       if (pv->reg[1]&0x20) SekInterrupt(6);\r
139     }\r
140 \r
141     Pico.m.scanline=(short)y;\r
142 \r
143     // Run scanline:\r
144     aim+=489; total+=SekRun(aim-total);\r
145 \r
146     hint--;\r
147 \r
148     if (PicoScan && y>=0) PicoLine(y);\r
149   }\r
150 \r
151   SekInterrupt(0); // Cancel interrupt\r
152 \r
153   return 0;\r
154 }\r
155 \r
156 // Simple frame without H-Ints\r
157 static int PicoFrameSimple()\r
158 {\r
159   int total=0,y=0,aim=0;\r
160   \r
161   Pico.m.scanline=-64;\r
162 \r
163   // V-Blanking period:\r
164   if (Pico.video.reg[1]&0x20) SekInterrupt(6); // Set IRQ\r
165   Pico.video.status|=0x88; // V-Int happened / go into vblank\r
166   total+=SekRun(18560);\r
167 \r
168   // Active Scan:\r
169   if (Pico.video.reg[1]&0x40) Pico.video.status&=~8; // Come out of vblank if display is enabled\r
170   SekInterrupt(0); // Clear IRQ\r
171 \r
172   // Run in sections:\r
173   for (aim=18560+6839; aim<=18560+6839*16; aim+=6839)\r
174   {\r
175     int add=0;\r
176     if (CheckIdle()) break;\r
177     add=SekRun(aim-total);\r
178     total+=add;\r
179   }\r
180 \r
181   if (PicoMask&0x100)\r
182   if (PicoScan)\r
183   {\r
184     // Draw the screen\r
185     for (y=0;y<224;y++) PicoLine(y);\r
186   }\r
187 \r
188   return 0;\r
189 }\r
190 \r
191 int PicoFrame()\r
192 {\r
193   int hints=0;\r
194 \r
195   if (Pico.rom==NULL) return 1; // No Rom plugged in\r
196 \r
197 \r
198   PmovUpdate();\r
199 \r
200   hints=Pico.video.reg[0]&0x10;\r
201 \r
202   if (hints) PicoFrameHints();\r
203   else PicoFrameSimple();\r
204 \r
205   PsndRender();\r
206 \r
207   return 0;\r
208 }\r
209 \r
210 static int DefaultCram(int cram)\r
211 {\r
212   int high=0x0841;\r
213   // Convert 0000bbbb ggggrrrr\r
214   // to      rrrr1ggg g10bbbb1\r
215   high|=(cram&0x00f)<<12; // Red\r
216   high|=(cram&0x0f0)<< 3; // Green\r
217   high|=(cram&0xf00)>> 7; // Blue\r
218   return high;\r
219 }\r
220 \r
221 // Function to convert Megadrive Cram into a native colour:\r
222 int (*PicoCram)(int cram)=DefaultCram;\r