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