1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
|
// DGen/SDL v1.18+
// Megadrive 1 Frame module
// Many, many thanks to John Stiles for the new structure of this module! :)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "md.h"
int split_screen=0;
#ifdef COMPILE_WITH_STAR
void md::run_to_odo_star(int odo_to)
{
int odo_start = s68000readOdometer();
s68000exec(odo_to - odo_start);
}
#endif
#ifdef COMPILE_WITH_MUSA
void md::run_to_odo_musa(int odo_to)
{
odo += m68k_execute(odo_to - odo);
}
#endif
#ifdef COMPILE_WITH_M68KEM
void md::run_to_odo_m68kem(int odo_to)
{
odo += m68000_execute(odo_to - odo);
}
#endif
void md::run_to_odo_z80(int odo_to)
{
if(z80_online)
{
odo_to >>= 1;
int odo_start = mz80GetElapsedTicks(0);
mz80exec(odo_to - odo_start);
}
}
#define LINES_PER_FRAME_NTSC 0x106 // Number of scanlines in NTSC (w/ vblank)
#define LINES_PER_FRAME_PAL 0x138 // Number of scanlines in PAL (w/ vblank)
#define LINES_PER_FRAME (pal? LINES_PER_FRAME_PAL : LINES_PER_FRAME_NTSC)
#define VBLANK_LINE_NTSC 0xE0 // vblank location for NTSC (and PAL 28-cel mode)
#define VBLANK_LINE_PAL 0xF0 // vblank location for PAL 30-cel mode
#define VBLANK_LINE ((pal && (vdp.reg[1] & 8))? \
VBLANK_LINE_PAL : VBLANK_LINE_NTSC)
#define scanlength (pal? (7189547/50/0x138) : (8000000/60/0x106))
#ifdef COMPILE_WITH_STAR
int md::one_frame_star(struct bmap *bm, unsigned char retpal[256], struct sndinfo *sndi)
{
int hints, odom = 0;
star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
// Clear odos
s68000tripOdometer();
mz80GetElapsedTicks(1);
// Raster zero causes special things to happen :)
coo4 = 0x37; // Init status register
if(vdp.reg[12] & 0x2) coo5 ^= 0x10; // Toggle odd/even for interlace
if(vdp.reg[1] & 0x40) coo5 &= ~0x88; // Clear vblank and vint
if(!(vdp.reg[1] & 0x20)) coo5 |= 0x80; // If vint disabled, vint happened
// is permanently set
hints = vdp.reg[10]; // Set hint counter
// Video display! :D
for(ras = 0; ras < VBLANK_LINE; ++ras)
{
fm_timer_callback(); // update sound timers
if((vdp.reg[0] & 0x10) && (--hints < 0))
{
// Trigger hint
s68000interrupt(4, -1);
hints = vdp.reg[10];
may_want_to_get_pic(bm, retpal, 1);
} else
may_want_to_get_pic(bm, retpal, 0);
coo5 |= 4; // hblank comes before, about 36/209 of the whole scanline
run_to_odo_star(odom + (scanlength * 36/209));
// Do hdisplay now
odom += scanlength;
coo5 &= ~4;
run_to_odo_star(odom);
// Do Z80
run_to_odo_z80(odom);
}
// Now we're in vblank, more special things happen :)
// Blank everything, and trigger vint
coo5 |= 0x8C;
if(vdp.reg[1] & 0x20) s68000interrupt(6, -1);
if(z80_online) mz80int(0);
// Run the course of vblank
for(; ras < LINES_PER_FRAME; ++ras)
{
fm_timer_callback();
// No interrupts happen in vblank
odom += scanlength;
run_to_odo_star(odom);
run_to_odo_z80(odom);
}
// Fill the sound buffers
if(sndi) may_want_to_get_sound(sndi);
// Shut off mz80/star - VERY IMPORTANT!
star_mz80_off();
return 0;
}
#endif // COMPILE_WITH_STAR
#ifdef COMPILE_WITH_MUSA
int md::one_frame_musa(struct bmap *bm, unsigned char retpal[256], struct sndinfo *sndi)
{
int hints, odom = 0;
star_mz80_on(); // VERY IMPORTANT! Must call before using star/mz80
// Clear odos
odo = 0;
mz80GetElapsedTicks(1);
// Raster zero causes special things to happen :)
coo4 = 0x37; // Init status register
if(vdp.reg[12] & 0x2) coo5 ^= 0x10; // Toggle odd/even for interlace
if(vdp.reg[1] & 0x40) coo5 &= ~0x88; // Clear vblank and vint
if(!(vdp.reg[1] & 0x20)) coo5 |= 0x80; // If vint disabled, vint happened
// is permanently set
hints = vdp.reg[10]; // Set hint counter
// Video display! :D
for(ras = 0; ras < VBLANK_LINE; ++ras)
{
fm_timer_callback(); // update sound timers
if((vdp.reg[0] & 0x10) && (--hints < 0))
{
// Trigger hint
m68k_assert_irq(4); m68k_clear_irq(4);
hints = vdp.reg[10];
may_want_to_get_pic(bm, retpal, 1);
} else may_want_to_get_pic(bm, retpal, 0);
coo5 |= 4; // hblank comes before, about 36/209 of the whole scanline
run_to_odo_musa(odom + (scanlength * 36/209));
// Do hdisplay now
odom += scanlength;
coo5 &= ~4;
run_to_odo_musa(odom);
// Do Z80
run_to_odo_z80(odom);
}
// Now we're in vblank, more special things happen :)
// Blank everything, and trigger vint
coo5 |= 0x8C;
if(vdp.reg[1] & 0x20) { m68k_assert_irq(6); m68k_clear_irq(6); }
if(z80_online) mz80int(0);
// Run the course of vblank
for(; ras < LINES_PER_FRAME; ++ras)
{
fm_timer_callback();
// No interrupts happen in vblank :)
odom += scanlength;
run_to_odo_musa(odom);
run_to_odo_z80(odom);
}
// Fill the sound buffers
if(sndi) may_want_to_get_sound(sndi);
// Shut off mz80/star - VERY IMPORTANT!
star_mz80_off();
return 0;
}
#endif // COMPILE_WITH_MUSA
// FIXME: I'm not going to do this until I figure out 68kem better
#ifdef COMPILE_WITH_M68KEM
int md::one_frame_m68kem(struct bmap *bm, unsigned char retpal[256], struct sndinfo *sndi)
{}
#endif
int md::one_frame(
struct bmap *bm,unsigned char retpal[256],
struct sndinfo *sndi)
{
++frame;
switch(cpu_emu)
{
#ifdef COMPILE_WITH_STAR
case 0: return one_frame_star(bm, retpal, sndi);
#endif
#ifdef COMPILE_WITH_MUSA
case 1: return one_frame_musa(bm, retpal, sndi);
#endif
#ifdef COMPILE_WITH_M68KEM
case 2: return one_frame_m68kem(bm, retpal, sndi);
#endif
// Something's screwy here...
default: return 1;
}
}
int md::calculate_hcoord()
{
int x=0,hcoord;
// c00009 is the H counter (I believe it's (h-coord>>1)&0xff)
#ifdef COMPILE_WITH_STAR
if (cpu_emu==0) x = s68000readOdometer() - (ras * scanlength);
#endif
#if defined(COMPILE_WITH_MUSA) || defined(COMPILE_WITH_M68KEM)
if (cpu_emu==1) x = odo - (ras * scanlength);
#endif
// hcoord=-56 (inclusive) to 364 (inclusive) in 40 column mode
hcoord=(x*416)/scanlength;
hcoord-=56;
return hcoord;
}
unsigned char md::calculate_coo8()
{
int hvcount;
hvcount=ras;
// c00008 is the V counter
if (calculate_hcoord()>=330) hvcount++;
// v counter seems to be a bit ahead of where h counter wraps
if (hvcount>(VBLANK_LINE+0xa)) hvcount-=6; // vcounter E5-EA appears twice!
hvcount&=0xff;
return hvcount;
}
unsigned char md::calculate_coo9()
{
int coo9;
coo9=(calculate_hcoord()>>1)&0xff;
return coo9;
}
// *************************************
// May want to get pic or sound
// *************************************
inline int md::may_want_to_get_pic(struct bmap *bm,unsigned char retpal[256],int/*mark*/)
{
if (bm==NULL) return 0;
if (ras>=0 && ras<VBLANK_LINE )
vdp.draw_scanline(bm, ras);
if(retpal && ras == 100) get_md_palette(retpal, vdp.cram);
return 0;
}
int md::may_want_to_get_sound(struct sndinfo *sndi)
{
int i, len = sndi->len;
int in_dac, cur_dac = 0, acc_dac = len;
int *dac = dac_data - 1;
// Get the PSG
SN76496Update_16(0, sndi->l, len);
// We bring in the dac, but stretch it out to fit the real length.
for(i = 0; i < len; ++i)
{
acc_dac += LINES_PER_FRAME;
if(acc_dac >= len)
{
acc_dac -= len;
in_dac = *(++dac);
if(in_dac != 1) cur_dac = in_dac;
}
sndi->l[i] += cur_dac;
}
// Copy mono signal to center channel
memcpy(sndi->r, sndi->l, len * sizeof(short));
// Add in the stereo FM buffer
FMSAMPLE *buf[2];
buf[0] = (FMSAMPLE*) sndi->l;
buf[1] = (FMSAMPLE*) sndi->r;
YM2612UpdateOne(0, (void**)buf, len);
// Clear the dac for next frame
dac_clear();
return 0;
}
|