new timing for main and cd
[picodrive.git] / pico / pico_cmn.c
1 /*
2  * common code for pico.c and cd/pico.c
3  * (C) notaz, 2007-2009
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8
9 #define CYCLES_M68K_LINE     488 // suitable for both PAL/NTSC
10 #define CYCLES_M68K_VINT_LAG  68
11 #define CYCLES_M68K_ASD      148
12
13 // pad delay (for 6 button pads)
14 #define PAD_DELAY() { \
15   if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
16   if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
17 }
18
19 // CPUS_RUN
20 #ifndef CPUS_RUN
21 #define CPUS_RUN(m68k_cycles) \
22   SekRunM68k(m68k_cycles)
23 #endif
24
25 static __inline void SekRunM68k(int cyc)
26 {
27   int cyc_do;
28   pprof_start(m68k);
29   pevt_log_m68k_o(EVT_RUN_START);
30
31   SekCycleAim += cyc;
32   while ((cyc_do = SekCycleAim - SekCycleCnt) > 0) {
33     SekCycleCnt += cyc_do;
34
35 #if defined(EMU_C68K)
36     PicoCpuCM68k.cycles = cyc_do;
37     CycloneRun(&PicoCpuCM68k);
38     SekCycleCnt -= PicoCpuCM68k.cycles;
39 #elif defined(EMU_M68K)
40     SekCycleCnt += m68k_execute(cyc_do) - cyc_do;
41 #elif defined(EMU_F68K)
42     SekCycleCnt += fm68k_emulate(cyc_do, 0, 0) - cyc_do;
43 #endif
44   }
45
46   SekCyclesLeft = 0;
47
48   SekTrace(0);
49   pevt_log_m68k_o(EVT_RUN_END);
50   pprof_end(m68k);
51 }
52
53 static int PicoFrameHints(void)
54 {
55   struct PicoVideo *pv=&Pico.video;
56   int lines, y, lines_vis = 224, line_sample, skip, vcnt_wrap;
57   unsigned int cycles;
58   int hint; // Hint counter
59
60   pevt_log_m68k_o(EVT_FRAME_START);
61   pv->v_counter = Pico.m.scanline = 0;
62
63   if ((PicoOpt&POPT_ALT_RENDERER) && !PicoSkipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
64     // draw a frame just after vblank in alternative render mode
65     // yes, this will cause 1 frame lag, but this is inaccurate mode anyway.
66     PicoFrameFull();
67 #ifdef DRAW_FINISH_FUNC
68     DRAW_FINISH_FUNC();
69 #endif
70     skip = 1;
71   }
72   else skip=PicoSkipFrame;
73
74   if (Pico.m.pal) {
75     line_sample = 68;
76     if (pv->reg[1]&8) lines_vis = 240;
77   } else {
78     line_sample = 93;
79   }
80
81   z80_resetCycles();
82   PsndDacLine = 0;
83   emustatus &= ~1;
84
85   pv->status&=~0x88; // clear V-Int, come out of vblank
86
87   hint=pv->reg[10]; // Load H-Int counter
88   //dprintf("-hint: %i", hint);
89
90   // This is to make active scan longer (needed for Double Dragon 2, mainly)
91   CPUS_RUN(CYCLES_M68K_ASD);
92
93   for (y = 0; y < lines_vis; y++)
94   {
95     pv->v_counter = Pico.m.scanline = y;
96     if ((pv->reg[12]&6) == 6) { // interlace mode 2
97       pv->v_counter <<= 1;
98       pv->v_counter |= pv->v_counter >> 8;
99       pv->v_counter &= 0xff;
100     }
101
102     // VDP FIFO
103     pv->lwrite_cnt -= 12;
104     if (pv->lwrite_cnt <= 0) {
105       pv->lwrite_cnt=0;
106       Pico.video.status|=0x200;
107     }
108
109     PAD_DELAY();
110
111     // H-Interrupts:
112     if (--hint < 0) // y <= lines_vis: Comix Zone, Golden Axe
113     {
114       hint=pv->reg[10]; // Reload H-Int counter
115       pv->pending_ints|=0x10;
116       if (pv->reg[0]&0x10) {
117         elprintf(EL_INTS, "hint: @ %06x [%i]", SekPc, SekCyclesDone());
118         SekInterrupt(4);
119       }
120     }
121
122     // decide if we draw this line
123     if (!skip && (PicoOpt & POPT_ALT_RENDERER))
124     {
125       // find the right moment for frame renderer, when display is no longer blanked
126       if ((pv->reg[1]&0x40) || y > 100) {
127         PicoFrameFull();
128 #ifdef DRAW_FINISH_FUNC
129         DRAW_FINISH_FUNC();
130 #endif
131         skip = 1;
132       }
133     }
134
135     // get samples from sound chips
136     if ((y == 224 || y == line_sample) && PsndOut)
137     {
138       cycles = SekCyclesDone();
139
140       if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
141         PicoSyncZ80(cycles);
142       if (ym2612.dacen && PsndDacLine <= y)
143         PsndDoDAC(y);
144 #ifdef PICO_CD
145       pcd_sync_s68k(cycles);
146 #endif
147 #ifdef PICO_32X
148       p32x_sync_sh2s(cycles);
149 #endif
150       PsndGetSamples(y);
151     }
152
153     // Run scanline:
154     if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
155     CPUS_RUN(CYCLES_M68K_LINE);
156
157     if (PicoLineHook) PicoLineHook();
158     pevt_log_m68k_o(EVT_NEXT_LINE);
159   }
160
161   if (!skip)
162   {
163     if (DrawScanline < y)
164       PicoDrawSync(y - 1, 0);
165 #ifdef DRAW_FINISH_FUNC
166     DRAW_FINISH_FUNC();
167 #endif
168   }
169
170   // V-int line (224 or 240)
171   Pico.m.scanline = y;
172   pv->v_counter = 0xe0; // bad for 240 mode
173   if ((pv->reg[12]&6) == 6) pv->v_counter = 0xc1;
174
175   // VDP FIFO
176   pv->lwrite_cnt=0;
177   Pico.video.status|=0x200;
178
179   memcpy(PicoPadInt, PicoPad, sizeof(PicoPadInt));
180   PAD_DELAY();
181
182   // Last H-Int:
183   if (--hint < 0)
184   {
185     hint=pv->reg[10]; // Reload H-Int counter
186     pv->pending_ints|=0x10;
187     //printf("rhint: %i @ %06x [%i|%i]\n", hint, SekPc, y, SekCyclesDone());
188     if (pv->reg[0]&0x10) SekInterrupt(4);
189   }
190
191   pv->status|=0x08; // go into vblank
192   pv->pending_ints|=0x20;
193
194   // the following SekRun is there for several reasons:
195   // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
196   // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
197   // also delay between last H-int and V-int (Golden Axe 3)
198   CPUS_RUN(CYCLES_M68K_VINT_LAG);
199
200   if (pv->reg[1]&0x20) {
201     elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCyclesDone());
202     SekInterrupt(6);
203   }
204
205   cycles = SekCyclesDone();
206   if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80)) {
207     PicoSyncZ80(cycles);
208     elprintf(EL_INTS, "zint");
209     z80_int();
210   }
211
212 #ifdef PICO_CD
213   pcd_sync_s68k(cycles);
214 #endif
215 #ifdef PICO_32X
216   p32x_sync_sh2s(cycles);
217   p32x_start_blank();
218 #endif
219
220   // get samples from sound chips
221   if (y == 224 && PsndOut)
222   {
223     if (ym2612.dacen && PsndDacLine <= y)
224       PsndDoDAC(y);
225     PsndGetSamples(y);
226   }
227
228   // Run scanline:
229   if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
230   CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG - CYCLES_M68K_ASD);
231
232   if (PicoLineHook) PicoLineHook();
233   pevt_log_m68k_o(EVT_NEXT_LINE);
234
235   lines = scanlines_total;
236   vcnt_wrap = Pico.m.pal ? 0x103 : 0xEB; // based on Gens, TODO: verify
237
238   for (y++; y < lines; y++)
239   {
240     pv->v_counter = Pico.m.scanline = y;
241     if (y >= vcnt_wrap)
242       pv->v_counter -= Pico.m.pal ? 56 : 6;
243     if ((pv->reg[12]&6) == 6)
244       pv->v_counter = (pv->v_counter << 1) | 1;
245     pv->v_counter &= 0xff;
246
247     PAD_DELAY();
248
249     // Run scanline:
250     if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
251     CPUS_RUN(CYCLES_M68K_LINE);
252
253     if (PicoLineHook) PicoLineHook();
254     pevt_log_m68k_o(EVT_NEXT_LINE);
255   }
256
257   // sync cpus
258   cycles = SekCyclesDone();
259   if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
260     PicoSyncZ80(cycles);
261   if (PsndOut && ym2612.dacen && PsndDacLine <= lines-1)
262     PsndDoDAC(lines-1);
263
264 #ifdef PICO_CD
265   pcd_sync_s68k(cycles);
266 #endif
267 #ifdef PICO_32X
268   p32x_sync_sh2s(cycles);
269 #endif
270   timers_cycle();
271
272   return 0;
273 }
274
275 #undef PAD_DELAY
276 #undef CPUS_RUN
277
278 // vim:shiftwidth=2:ts=2:expandtab