gen/cd frame loops merged
[picodrive.git] / Pico / PicoFrameHints.c
1 #define CYCLES_M68K_LINE     488 // suitable for both PAL/NTSC
2 #define CYCLES_M68K_VINT_LAG  68
3 #define CYCLES_M68K_ASD      148
4 #define CYCLES_Z80_LINE      228
5 #define CYCLES_Z80_ASD        69
6 #define CYCLES_S68K_LINE     795
7 #define CYCLES_S68K_ASD      241
8
9 // pad delay (for 6 button pads)
10 #define PAD_DELAY \
11   if (PicoOpt&0x20) { \
12     if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
13     if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
14   }
15
16 #define Z80_RUN(z80_cycles) \
17 { \
18   if ((PicoOpt&4) && Pico.m.z80Run) \
19   { \
20     if (Pico.m.z80Run & 2) z80CycleAim += z80_cycles; \
21     else { \
22       int cnt = SekCyclesDone() - z80startCycle; \
23       cnt = (cnt>>1)-(cnt>>5); \
24       if (cnt > (z80_cycles)) cnt = z80_cycles; \
25       Pico.m.z80Run |= 2; \
26       z80CycleAim+=cnt; \
27     } \
28     total_z80+=z80_run(z80CycleAim-total_z80); \
29   } \
30 }
31
32 // CPUS_RUN
33 #ifndef PICO_CD
34 #define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
35     SekRunM68k(m68k_cycles); \
36     Z80_RUN(z80_cycles);
37 #else
38 #define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
39 { \
40     if ((PicoOpt & 0x2000) && (Pico_mcd->m.busreq&3) == 1) { \
41       SekRunPS(m68k_cycles, s68k_cycles); /* "better/perfect sync" */ \
42     } else { \
43       SekRunM68k(m68k_cycles); \
44       if ((Pico_mcd->m.busreq&3) == 1) /* no busreq/no reset */ \
45         SekRunS68k(s68k_cycles); \
46     } \
47     Z80_RUN(z80_cycles); \
48 }
49 #endif
50
51 // Accurate but slower frame which does hints
52 static int PicoFrameHints(void)
53 {
54   struct PicoVideo *pv=&Pico.video;
55   int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample;
56   int skip=PicoSkipFrame || (PicoOpt&0x10);
57   int hint; // Hint counter
58
59   if (Pico.m.pal) {
60     //cycles_68k = (int) ((double) OSC_PAL  /  7 / 50 / 312 + 0.4); // should compile to a constant (488)
61     //cycles_z80 = (int) ((double) OSC_PAL  / 15 / 50 / 312 + 0.4); // 228
62     line_sample = 68;
63     if(pv->reg[1]&8) lines_vis = 240;
64   } else {
65     //cycles_68k = (int) ((double) OSC_NTSC /  7 / 60 / 262 + 0.4); // 488
66     //cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
67     line_sample = 93;
68   }
69
70   SekCyclesReset();
71 #ifdef PICO_CD
72   SekCyclesResetS68k();
73 #endif
74
75   pv->status&=~0x88; // clear V-Int, come out of vblank
76
77   hint=pv->reg[10]; // Load H-Int counter
78   //dprintf("-hint: %i", hint);
79
80   // This is to make active scan longer (needed for Double Dragon 2, mainly)
81   CPUS_RUN(CYCLES_M68K_ASD, CYCLES_Z80_ASD, CYCLES_S68K_ASD);
82
83   for (y=0;y<lines_vis;y++)
84   {
85     Pico.m.scanline=(short)y;
86
87     // VDP FIFO
88     pv->lwrite_cnt -= 12;
89     if (pv->lwrite_cnt <= 0) {
90       pv->lwrite_cnt=0;
91       Pico.video.status|=0x200;
92     }
93
94     PAD_DELAY
95 #ifdef PICO_CD
96     check_cd_dma();
97 #endif
98
99     // H-Interrupts:
100     if (--hint < 0) // y <= lines_vis: Comix Zone, Golden Axe
101     {
102       hint=pv->reg[10]; // Reload H-Int counter
103       pv->pending_ints|=0x10;
104       if (pv->reg[0]&0x10) {
105         elprintf(EL_INTS, "hint: @ %06x [%i]", SekPc, SekCycleCnt);
106         SekInterrupt(4);
107       }
108     }
109
110     // decide if we draw this line
111 #if CAN_HANDLE_240_LINES
112     if(!skip && ((!(pv->reg[1]&8) && y<224) || (pv->reg[1]&8)) )
113 #else
114     if(!skip && y<224)
115 #endif
116       PicoLine(y);
117
118     if(PicoOpt&1)
119       sound_timers_and_dac(y);
120
121 #ifndef PICO_CD
122     // get samples from sound chips
123     if(y == 32 && PsndOut)
124       emustatus &= ~1;
125     else if((y == 224 || y == line_sample) && PsndOut)
126       getSamples(y);
127 #endif
128
129     // Run scanline:
130     if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
131     CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
132
133 #ifdef PICO_CD
134     update_chips();
135 #endif
136   }
137
138   // V-int line (224 or 240)
139   Pico.m.scanline=(short)y;
140
141   // VDP FIFO
142   pv->lwrite_cnt=0;
143   Pico.video.status|=0x200;
144
145   PAD_DELAY
146 #ifdef PICO_CD
147   check_cd_dma();
148 #endif
149
150   // Last H-Int:
151   if (--hint < 0)
152   {
153     hint=pv->reg[10]; // Reload H-Int counter
154     pv->pending_ints|=0x10;
155     //printf("rhint: %i @ %06x [%i|%i]\n", hint, SekPc, y, SekCycleCnt);
156     if (pv->reg[0]&0x10) SekInterrupt(4);
157   }
158
159   // V-Interrupt:
160   pv->status|=0x08; // go into vblank
161   pv->pending_ints|=0x20;
162
163   // the following SekRun is there for several reasons:
164   // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
165   // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
166   // also delay between last H-int and V-int (Golden Axe 3)
167   SekRunM68k(CYCLES_M68K_VINT_LAG);
168   if (pv->reg[1]&0x20) {
169     elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCycleCnt);
170     SekInterrupt(6);
171   }
172   if (Pico.m.z80Run && (PicoOpt&4))
173     z80_int();
174
175   if (PicoOpt&1)
176     sound_timers_and_dac(y);
177
178   // get samples from sound chips
179 #ifndef PICO_CD
180   if (y == 224)
181 #endif
182     if (PsndOut)
183       getSamples(y);
184
185   // Run scanline:
186   if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
187   CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG - CYCLES_M68K_ASD,
188     CYCLES_Z80_LINE - CYCLES_Z80_ASD, CYCLES_S68K_LINE - CYCLES_S68K_ASD);
189
190 #ifdef PICO_CD
191     update_chips();
192 #endif
193
194   // PAL line count might actually be 313 according to Steve Snake, but that would complicate things.
195   lines = Pico.m.pal ? 312 : 262;
196
197   for (y++;y<lines;y++)
198   {
199     Pico.m.scanline=(short)y;
200
201     PAD_DELAY
202 #ifdef PICO_CD
203     check_cd_dma();
204 #endif
205
206     if(PicoOpt&1)
207       sound_timers_and_dac(y);
208
209     // Run scanline:
210     if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
211     CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
212
213 #ifdef PICO_CD
214     update_chips();
215 #endif
216   }
217
218   // draw a frame just after vblank in alternative render mode
219   if (!PicoSkipFrame && (PicoOpt&0x10))
220     PicoFrameFull();
221
222   return 0;
223 }
224
225 #undef PAD_DELAY
226 #undef Z80_RUN
227 #undef CPUS_RUN
228