Import Debian changes 1.23-6
[debian-dgen.git] / mdfr.cpp
blobd2611765c559164065bb71942d2b5ef55e3d831b
1 // DGen/SDL v1.18+
2 // Megadrive 1 Frame module
3 // Many, many thanks to John Stiles for the new structure of this module! :)
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include "md.h"
11 int split_screen=0;
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);
19 #endif
21 #ifdef COMPILE_WITH_MUSA
22 void md::run_to_odo_musa(int odo_to)
24 odo += m68k_execute(odo_to - odo);
26 #endif
28 #ifdef COMPILE_WITH_M68KEM
29 void md::run_to_odo_m68kem(int odo_to)
31 odo += m68000_execute(odo_to - odo);
33 #endif
35 void md::run_to_odo_z80(int odo_to)
37 if(z80_online)
39 odo_to >>= 1;
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)
61 int hints, odom = 0;
63 star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
65 // Clear odos
66 s68000tripOdometer();
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
74 // is permanently set
75 hints = vdp.reg[10]; // Set hint counter
77 // Video display! :D
78 for(ras = 0; ras < VBLANK_LINE; ++ras)
80 fm_timer_callback(); // update sound timers
82 if((vdp.reg[0] & 0x10) && (--hints < 0))
84 // Trigger hint
85 s68000interrupt(4, -1);
86 hints = vdp.reg[10];
87 may_want_to_get_pic(bm, retpal, 1);
88 } else
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));
93 // Do hdisplay now
94 odom += scanlength;
95 coo5 &= ~4;
96 run_to_odo_star(odom);
98 // Do Z80
99 run_to_odo_z80(odom);
101 // Now we're in vblank, more special things happen :)
102 // Blank everything, and trigger vint
103 coo5 |= 0x8C;
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)
110 fm_timer_callback();
112 // No interrupts happen in vblank
114 odom += scanlength;
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!
123 star_mz80_off();
125 return 0;
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)
132 int hints, odom = 0;
134 star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
136 // Clear odos
137 odo = 0;
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
148 // Video display! :D
149 for(ras = 0; ras < VBLANK_LINE; ++ras)
151 fm_timer_callback(); // update sound timers
153 if((vdp.reg[0] & 0x10) && (--hints < 0))
155 // Trigger hint
156 m68k_assert_irq(4); m68k_clear_irq(4);
157 hints = vdp.reg[10];
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));
162 // Do hdisplay now
163 odom += scanlength;
164 coo5 &= ~4;
165 run_to_odo_musa(odom);
167 // Do Z80
168 run_to_odo_z80(odom);
170 // Now we're in vblank, more special things happen :)
171 // Blank everything, and trigger vint
172 coo5 |= 0x8C;
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)
179 fm_timer_callback();
181 // No interrupts happen in vblank :)
183 odom += scanlength;
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!
192 star_mz80_off();
194 return 0;
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)
202 #endif
204 int md::one_frame(
205 struct bmap *bm,unsigned char retpal[256],
206 struct sndinfo *sndi)
208 ++frame;
209 switch(cpu_emu)
211 #ifdef COMPILE_WITH_STAR
212 case 0: return one_frame_star(bm, retpal, sndi);
213 #endif
214 #ifdef COMPILE_WITH_MUSA
215 case 1: return one_frame_musa(bm, retpal, sndi);
216 #endif
217 #ifdef COMPILE_WITH_M68KEM
218 case 2: return one_frame_m68kem(bm, retpal, sndi);
219 #endif
220 // Something's screwy here...
221 default: return 1;
225 int md::calculate_hcoord()
227 int x=0,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);
231 #endif
232 #if defined(COMPILE_WITH_MUSA) || defined(COMPILE_WITH_M68KEM)
233 if (cpu_emu==1) x = odo - (ras * scanlength);
234 #endif
236 // hcoord=-56 (inclusive) to 364 (inclusive) in 40 column mode
238 hcoord=(x*416)/scanlength;
239 hcoord-=56;
241 return hcoord;
244 unsigned char md::calculate_coo8()
246 int hvcount;
247 hvcount=ras;
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!
255 hvcount&=0xff;
256 return hvcount;
259 unsigned char md::calculate_coo9()
261 int coo9;
262 coo9=(calculate_hcoord()>>1)&0xff;
264 return coo9;
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);
279 return 0;
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;
288 // Get the PSG
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;
295 if(acc_dac >= len)
297 acc_dac -= len;
298 in_dac = *(++dac);
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
307 FMSAMPLE *buf[2];
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
313 dac_clear();
314 return 0;