2 // Megadrive 1 Frame module
3 // Many, many thanks to John Stiles for the new structure of this module! :)
13 #ifdef COMPILE_WITH_STAR
14 void md::run_to_odo_star(int odo_to
)
16 int odo_start
= s68000readOdometer();
17 s68000exec(odo_to
- odo_start
);
21 #ifdef COMPILE_WITH_MUSA
22 void md::run_to_odo_musa(int odo_to
)
24 odo
+= m68k_execute(odo_to
- odo
);
28 #ifdef COMPILE_WITH_M68KEM
29 void md::run_to_odo_m68kem(int odo_to
)
31 odo
+= m68000_execute(odo_to
- odo
);
35 void md::run_to_odo_z80(int odo_to
)
40 int odo_start
= mz80GetElapsedTicks(0);
41 mz80exec(odo_to
- odo_start
);
45 #define LINES_PER_FRAME_NTSC 0x106 // Number of scanlines in NTSC (w/ vblank)
46 #define LINES_PER_FRAME_PAL 0x138 // Number of scanlines in PAL (w/ vblank)
48 #define LINES_PER_FRAME (pal? LINES_PER_FRAME_PAL : LINES_PER_FRAME_NTSC)
50 #define VBLANK_LINE_NTSC 0xE0 // vblank location for NTSC (and PAL 28-cel mode)
51 #define VBLANK_LINE_PAL 0xF0 // vblank location for PAL 30-cel mode
53 #define VBLANK_LINE ((pal && (vdp.reg[1] & 8))? \
54 VBLANK_LINE_PAL : VBLANK_LINE_NTSC)
56 #define scanlength (pal? (7189547/50/0x138) : (8000000/60/0x106))
58 #ifdef COMPILE_WITH_STAR
59 int md::one_frame_star(struct bmap
*bm
, unsigned char retpal
[256], struct sndinfo
*sndi
)
63 star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
67 mz80GetElapsedTicks(1);
69 // Raster zero causes special things to happen :)
70 coo4
= 0x37; // Init status register
71 if(vdp
.reg
[12] & 0x2) coo5
^= 0x10; // Toggle odd/even for interlace
72 if(vdp
.reg
[1] & 0x40) coo5
&= ~0x88; // Clear vblank and vint
73 if(!(vdp
.reg
[1] & 0x20)) coo5
|= 0x80; // If vint disabled, vint happened
75 hints
= vdp
.reg
[10]; // Set hint counter
78 for(ras
= 0; ras
< VBLANK_LINE
; ++ras
)
80 fm_timer_callback(); // update sound timers
82 if((vdp
.reg
[0] & 0x10) && (--hints
< 0))
85 s68000interrupt(4, -1);
87 may_want_to_get_pic(bm
, retpal
, 1);
89 may_want_to_get_pic(bm
, retpal
, 0);
91 coo5
|= 4; // hblank comes before, about 36/209 of the whole scanline
92 run_to_odo_star(odom
+ (scanlength
* 36/209));
96 run_to_odo_star(odom
);
101 // Now we're in vblank, more special things happen :)
102 // Blank everything, and trigger vint
104 if(vdp
.reg
[1] & 0x20) s68000interrupt(6, -1);
105 if(z80_online
) mz80int(0);
107 // Run the course of vblank
108 for(; ras
< LINES_PER_FRAME
; ++ras
)
112 // No interrupts happen in vblank
115 run_to_odo_star(odom
);
116 run_to_odo_z80(odom
);
119 // Fill the sound buffers
120 if(sndi
) may_want_to_get_sound(sndi
);
122 // Shut off mz80/star - VERY IMPORTANT!
127 #endif // COMPILE_WITH_STAR
129 #ifdef COMPILE_WITH_MUSA
130 int md::one_frame_musa(struct bmap
*bm
, unsigned char retpal
[256], struct sndinfo
*sndi
)
134 star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
138 mz80GetElapsedTicks(1);
140 // Raster zero causes special things to happen :)
141 coo4
= 0x37; // Init status register
142 if(vdp
.reg
[12] & 0x2) coo5
^= 0x10; // Toggle odd/even for interlace
143 if(vdp
.reg
[1] & 0x40) coo5
&= ~0x88; // Clear vblank and vint
144 if(!(vdp
.reg
[1] & 0x20)) coo5
|= 0x80; // If vint disabled, vint happened
145 // is permanently set
146 hints
= vdp
.reg
[10]; // Set hint counter
149 for(ras
= 0; ras
< VBLANK_LINE
; ++ras
)
151 fm_timer_callback(); // update sound timers
153 if((vdp
.reg
[0] & 0x10) && (--hints
< 0))
156 m68k_assert_irq(4); m68k_clear_irq(4);
158 may_want_to_get_pic(bm
, retpal
, 1);
159 } else may_want_to_get_pic(bm
, retpal
, 0);
160 coo5
|= 4; // hblank comes before, about 36/209 of the whole scanline
161 run_to_odo_musa(odom
+ (scanlength
* 36/209));
165 run_to_odo_musa(odom
);
168 run_to_odo_z80(odom
);
170 // Now we're in vblank, more special things happen :)
171 // Blank everything, and trigger vint
173 if(vdp
.reg
[1] & 0x20) { m68k_assert_irq(6); m68k_clear_irq(6); }
174 if(z80_online
) mz80int(0);
176 // Run the course of vblank
177 for(; ras
< LINES_PER_FRAME
; ++ras
)
181 // No interrupts happen in vblank :)
184 run_to_odo_musa(odom
);
185 run_to_odo_z80(odom
);
188 // Fill the sound buffers
189 if(sndi
) may_want_to_get_sound(sndi
);
191 // Shut off mz80/star - VERY IMPORTANT!
196 #endif // COMPILE_WITH_MUSA
198 // FIXME: I'm not going to do this until I figure out 68kem better
199 #ifdef COMPILE_WITH_M68KEM
200 int md::one_frame_m68kem(struct bmap
*bm
, unsigned char retpal
[256], struct sndinfo
*sndi
)
205 struct bmap
*bm
,unsigned char retpal
[256],
206 struct sndinfo
*sndi
)
211 #ifdef COMPILE_WITH_STAR
212 case 0: return one_frame_star(bm
, retpal
, sndi
);
214 #ifdef COMPILE_WITH_MUSA
215 case 1: return one_frame_musa(bm
, retpal
, sndi
);
217 #ifdef COMPILE_WITH_M68KEM
218 case 2: return one_frame_m68kem(bm
, retpal
, sndi
);
220 // Something's screwy here...
225 int md::calculate_hcoord()
228 // c00009 is the H counter (I believe it's (h-coord>>1)&0xff)
229 #ifdef COMPILE_WITH_STAR
230 if (cpu_emu
==0) x
= s68000readOdometer() - (ras
* scanlength
);
232 #if defined(COMPILE_WITH_MUSA) || defined(COMPILE_WITH_M68KEM)
233 if (cpu_emu
==1) x
= odo
- (ras
* scanlength
);
236 // hcoord=-56 (inclusive) to 364 (inclusive) in 40 column mode
238 hcoord
=(x
*416)/scanlength
;
244 unsigned char md::calculate_coo8()
249 // c00008 is the V counter
250 if (calculate_hcoord()>=330) hvcount
++;
251 // v counter seems to be a bit ahead of where h counter wraps
253 if (hvcount
>(VBLANK_LINE
+0xa)) hvcount
-=6; // vcounter E5-EA appears twice!
259 unsigned char md::calculate_coo9()
262 coo9
=(calculate_hcoord()>>1)&0xff;
268 // *************************************
269 // May want to get pic or sound
270 // *************************************
272 inline int md::may_want_to_get_pic(struct bmap
*bm
,unsigned char retpal
[256],int/*mark*/)
274 if (bm
==NULL
) return 0;
276 if (ras
>=0 && ras
<VBLANK_LINE
)
277 vdp
.draw_scanline(bm
, ras
);
278 if(retpal
&& ras
== 100) get_md_palette(retpal
, vdp
.cram
);
282 int md::may_want_to_get_sound(struct sndinfo
*sndi
)
284 int i
, len
= sndi
->len
;
285 int in_dac
, cur_dac
= 0, acc_dac
= len
;
286 int *dac
= dac_data
- 1;
289 SN76496Update_16(0, sndi
->l
, len
);
291 // We bring in the dac, but stretch it out to fit the real length.
292 for(i
= 0; i
< len
; ++i
)
294 acc_dac
+= LINES_PER_FRAME
;
299 if(in_dac
!= 1) cur_dac
= in_dac
;
301 sndi
->l
[i
] += cur_dac
;
303 // Copy mono signal to center channel
304 memcpy(sndi
->r
, sndi
->l
, len
* sizeof(short));
306 // Add in the stereo FM buffer
308 buf
[0] = (FMSAMPLE
*) sndi
->l
;
309 buf
[1] = (FMSAMPLE
*) sndi
->r
;
310 YM2612UpdateOne(0, (void**)buf
, len
);
312 // Clear the dac for next frame