modified sn76489 cut-off frequency, modified Video synchronization

This commit is contained in:
ekeeke31 2009-01-06 17:15:28 +00:00
parent 0e86a15c09
commit 414a53ca1f
8 changed files with 412 additions and 371 deletions

View File

@ -125,33 +125,33 @@ bool fat_enabled = 0;
int main (int argc, char *argv[])
{
long long now, prev;
int RenderedFrameCount = 0;
int FrameCount = 0;
#ifdef HW_RVL
/* initialize Wii DVD interface first */
DI_Close();
DI_Init();
#endif
long long now, prev;
int RenderedFrameCount = 0;
int FrameCount = 0;
/* Initialize OGC subsystems */
/* initialize OGC subsystems */
ogc_video__init();
ogc_input__init();
ogc_audio__init();
#ifdef HW_DOL
/* Initialize GC DVD interface */
/* initialize GC DVD interface */
DVD_Init ();
dvd_drive_detect();
#endif
#ifdef HW_RVL
/* Power Button callback */
/* Power button callback */
SYS_SetPowerCallback(Power_Off);
#endif
/* Initialize FAT Interface */
/* initialize FAT Interface */
if (fatInitDefault() == true)
{
fat_enabled = 1;
@ -164,34 +164,50 @@ int main (int argc, char *argv[])
#endif
}
/* Default Config */
/* default Config */
legal();
set_config_defaults();
config_load();
/* Restore Recent Files list */
/* restore recent Files list */
set_history_defaults();
history_load();
/* Initialize Virtual Machine */
/* initialize VM */
init_machine ();
/* Load any injected rom */
/* load any injected rom */
if (genromsize)
{
ARAMFetch((char *)cart_rom, (void *)0x8000, genromsize);
reloadrom ();
}
/* Show Menu */
MainMenu();
ConfigRequested = 0;
/* show Menu first */
ConfigRequested = 1;
/* Emulation Loop */
/* main emulation loop */
while (1)
{
ogc_audio__start();
/* Check for Menu request */
if (ConfigRequested)
{
/* stop Audio */
ogc_audio__stop();
/* go to Menu */
MainMenu ();
ConfigRequested = 0;
/* reset frame sync */
frameticker = 0;
FrameCount = 0;
RenderedFrameCount = 0;
/* restart sound loop */
ogc_audio__start();
}
if (gc_pal < 0)
{
/* this code is NEVER executed */
@ -204,28 +220,31 @@ int main (int argc, char *argv[])
{
if (frameticker > 1)
{
/* frameskipping */
/* skip one frame */
frameticker--;
system_frame (1);
/* update audio only */
ogc_audio__update();
}
else
{
/* frame sync */
while (!frameticker) usleep(1);
while (frameticker < 1) usleep(1);
/* frame rendering */
/* render one frame */
system_frame (0);
RenderedFrameCount++;
/* update audio & video */
ogc_audio__update();
ogc_video__update();
}
frameticker--;
}
/* update video & audio */
ogc_audio__update();
ogc_video__update();
/* check rendered frames (FPS) */
/* check rendered frame count (FPS) */
FrameCount++;
if (FrameCount == vdp_rate)
{
@ -233,23 +252,7 @@ int main (int argc, char *argv[])
RenderedFrameCount = 0;
FrameCount = 0;
}
/* Check for Menu request */
if (ConfigRequested)
{
/* stop Audio */
ogc_audio__stop();
/* go to menu */
MainMenu ();
ConfigRequested = 0;
/* reset frame sync */
frameticker = 0;
FrameCount = 0;
RenderedFrameCount = 0;
}
}
return 0;
}

View File

@ -35,9 +35,6 @@ u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */
int mixbuffer;
/* Current DMA status (1: DMA in progress, 0: DMA stopped) */
static int IsPlaying = 0;
/* Current DMA length (required to be a factor of 32-bytes)
length is calculated regarding current emulation timings:
PAL timings : 50 frames/sec, 48000 samples/sec = 960 samples per frame = 3840 bytes (16 bits stereo samples)
@ -99,27 +96,22 @@ void ogc_audio__update(void)
***/
void ogc_audio__start(void)
{
if (!IsPlaying)
{
dma_len = vdp_pal ? 3840 : 3200;
memset(soundbuffer[0], 0, dma_len);
AUDIO_InitDMA((u32) soundbuffer[0], dma_len);
DCFlushRange(soundbuffer[0], dma_len);
AUDIO_StartDMA();
IsPlaying = 1;
mixbuffer = 1;
}
dma_len = vdp_pal ? 3840 : 3200;
memset(soundbuffer[0], 0, dma_len);
AUDIO_InitDMA((u32) soundbuffer[0], dma_len);
DCFlushRange(soundbuffer[0], dma_len);
AUDIO_StartDMA();
mixbuffer = 1;
}
/***
ogc_audio__stop
This function reset current Audio DMA process and clear soundbuffers
This function reset current Audio DMA process
This is called when going back to Main Menu
DMA need to be restarted when going back to the game (see above)
***/
void ogc_audio__stop(void)
{
AUDIO_StopDMA ();
IsPlaying = 0;
}

View File

@ -53,26 +53,28 @@ u8 *texturemem; /*** Texture Data ***/
static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN (32);
static GXTexObj texobj;
static u8 do_copy = GX_FALSE;
static Mtx view;
static u32 vwidth, vheight;
/*** custom Video modes (used to emulate original console video modes) ***/
/*** custom Video modes ***/
/* 288 lines progressive (PAL 50Hz) */
GXRModeObj TV50hz_288p =
{
VI_TVMODE_PAL_DS,// viDisplayMode
640, // fbWidth
286, // efbHeight
286, // xfbHeight
(VI_MAX_WIDTH_PAL - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_PAL/2 - 572/2)/2,// viYOrigin
720, // viWidth
572, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
VI_TVMODE_PAL_DS, // viDisplayMode
640, // fbWidth
286, // efbHeight
286, // xfbHeight
0, // viXOrigin
(VI_MAX_HEIGHT_PAL - 572)/2, // viYOrigin
VI_MAX_WIDTH_PAL, // viWidth
572, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
@ -82,102 +84,32 @@ GXRModeObj TV50hz_288p =
// vertical filter[7], 1/64 units, 6 bits each
{
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
}
};
/* 288 lines interlaced (PAL 50Hz) */
GXRModeObj TV50hz_288i =
{
VI_TVMODE_PAL_INT,// viDisplayMode
640, // fbWidth
286, // efbHeight
286, // xfbHeight
(VI_MAX_WIDTH_PAL - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_PAL/2 - 572/2)/2,// viYOrigin
720, // viWidth
572, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_TRUE, // field_rendering
GX_FALSE, // aa
VI_TVMODE_PAL_INT, // viDisplayMode
640, // fbWidth
286, // efbHeight
286, // xfbHeight
0, // viXOrigin
(VI_MAX_HEIGHT_PAL - 572)/2, // viYOrigin
VI_MAX_WIDTH_PAL, // viWidth
572, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_TRUE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
{6,6},{6,6},{6,6}, // pix 2
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
{
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
}
};
/* 576 lines interlaced (PAL 50Hz, scaled) */
GXRModeObj TV50hz_576i =
{
VI_TVMODE_PAL_INT,// viDisplayMode
640, // fbWidth
480, // efbHeight
574, // xfbHeight
(VI_MAX_WIDTH_PAL - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_PAL - 574)/2,// viYOrigin
720, // viWidth
574, // viHeight
VI_XFBMODE_DF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
{6,6},{6,6},{6,6}, // pix 2
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
{
8, // line n-1
8, // line n-1
10, // line n
12, // line n
10, // line n
8, // line n+1
8 // line n+1
}
};
/* 240 lines progressive (NTSC or PAL 60Hz) */
GXRModeObj TV60hz_240p =
{
VI_TVMODE_EURGB60_DS,// viDisplayMode
640, // fbWidth
240, // efbHeight
240, // xfbHeight
(VI_MAX_WIDTH_NTSC - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_NTSC/2 - 480/2)/2, // viYOrigin
720, // viWidth
480, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
@ -187,32 +119,102 @@ GXRModeObj TV60hz_240p =
// vertical filter[7], 1/64 units, 6 bits each
{
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
}
};
/* 576 lines interlaced (PAL 50Hz, scaled) */
GXRModeObj TV50hz_576i =
{
VI_TVMODE_PAL_INT, // viDisplayMode
640, // fbWidth
480, // efbHeight
VI_MAX_HEIGHT_PAL, // xfbHeight
0, // viXOrigin
0, // viYOrigin
VI_MAX_WIDTH_PAL, // viWidth
VI_MAX_HEIGHT_PAL, // viHeight
VI_XFBMODE_DF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
{6,6},{6,6},{6,6}, // pix 2
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
{
8, // line n-1
8, // line n-1
10, // line n
12, // line n
10, // line n
8, // line n+1
8 // line n+1
}
};
/* 240 lines progressive (NTSC or PAL 60Hz) */
GXRModeObj TV60hz_240p =
{
VI_TVMODE_EURGB60_DS, // viDisplayMode
640, // fbWidth
VI_MAX_HEIGHT_NTSC/2, // efbHeight
VI_MAX_HEIGHT_NTSC/2, // xfbHeight
0, // viXOrigin
0, // viYOrigin
VI_MAX_WIDTH_NTSC, // viWidth
VI_MAX_HEIGHT_NTSC, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
{6,6},{6,6},{6,6}, // pix 2
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
{
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
}
};
/* 240 lines interlaced (NTSC or PAL 60Hz) */
GXRModeObj TV60hz_240i =
{
VI_TVMODE_EURGB60_INT,// viDisplayMode
640, // fbWidth
240, // efbHeight
240, // xfbHeight
(VI_MAX_WIDTH_NTSC - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_NTSC/2 - 480/2)/2, // viYOrigin
720, // viWidth
480, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_TRUE, // field_rendering
GX_FALSE, // aa
VI_TVMODE_EURGB60_INT, // viDisplayMode
640, // fbWidth
VI_MAX_HEIGHT_NTSC/2, // efbHeight
VI_MAX_HEIGHT_NTSC/2, // xfbHeight
0, // viXOrigin
0, // viYOrigin
VI_MAX_WIDTH_NTSC, // viWidth
VI_MAX_HEIGHT_NTSC, // viHeight
VI_XFBMODE_SF, // xFBmode
GX_TRUE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
// sample points arranged in increasing Y order
{
{3,2},{9,6},{3,10}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{3,2},{9,6},{3,10}, // pix 1
@ -220,15 +222,15 @@ GXRModeObj TV60hz_240i =
{9,2},{3,6},{9,10} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
// vertical filter[7], 1/64 units, 6 bits each
{
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
0, // line n-1
0, // line n-1
21, // line n
22, // line n
21, // line n
0, // line n+1
0 // line n+1
}
};
@ -236,18 +238,18 @@ GXRModeObj TV60hz_240i =
GXRModeObj TV60hz_480i =
{
VI_TVMODE_EURGB60_INT,// viDisplayMode
640, // fbWidth
480, // efbHeight
480, // xfbHeight
(VI_MAX_WIDTH_NTSC - 720)/2, // viXOrigin
(VI_MAX_HEIGHT_NTSC - 480)/2, // viYOrigin
720, // viWidth
480, // viHeight
VI_XFBMODE_DF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
640, // fbWidth
VI_MAX_HEIGHT_NTSC, // efbHeight
VI_MAX_HEIGHT_NTSC, // xfbHeight
0, // viXOrigin
0, // viYOrigin
VI_MAX_WIDTH_NTSC, // viWidth
VI_MAX_HEIGHT_NTSC, // viHeight
VI_XFBMODE_DF, // xFBmode
GX_FALSE, // field_rendering
GX_FALSE, // aa
// sample points arranged in increasing Y order
// sample points arranged in increasing Y order
{
{6,6},{6,6},{6,6}, // pix 0, 3 sample points, 1/12 units, 4 bits each
{6,6},{6,6},{6,6}, // pix 1
@ -255,15 +257,15 @@ GXRModeObj TV60hz_480i =
{6,6},{6,6},{6,6} // pix 3
},
// vertical filter[7], 1/64 units, 6 bits each
// vertical filter[7], 1/64 units, 6 bits each
{
8, // line n-1
8, // line n-1
10, // line n
12, // line n
10, // line n
8, // line n+1
8 // line n+1
8, // line n-1
8, // line n-1
10, // line n
12, // line n
10, // line n
8, // line n+1
8 // line n+1
}
};
@ -489,6 +491,7 @@ static void gxScale(GXRModeObj *rmode)
square[4] = square[1] = yscale + yshift;
square[7] = square[10] = -yscale + yshift;
/* flush data from cache */
DCFlushRange (square, 32);
GX_InvVtxCache ();
}
@ -618,14 +621,37 @@ void ogc_video__update()
draw_square ();
GX_DrawDone ();
/* switch external framebuffers then copy EFB to XFB */
whichfb ^= 1;
GX_CopyDisp (xfb[whichfb], GX_TRUE);
GX_Flush ();
/* postpound XFB update */
do_copy = GX_TRUE;
}
/* set next XFB */
VIDEO_SetNextFramebuffer (xfb[whichfb]);
VIDEO_Flush ();
/* Pre-Retrace handler
synchronize XFB switch with VSYNC
*/
void xfb_switch(u32 cnt)
{
if (!ConfigRequested)
{
/* switch external framebuffers */
whichfb ^= 1;
/* set next XFB */
VIDEO_SetNextFramebuffer (xfb[whichfb]);
VIDEO_Flush ();
}
}
/* Post-Retrace handler
synchronize XFB copy with VSYNC */
void xfb_copy(u32 cnt)
{
if (do_copy)
{
/* copy EFB to XFB */
GX_CopyDisp (xfb[whichfb], GX_TRUE);
GX_Flush ();
do_copy = GX_FALSE;
}
}
/* Initialize VIDEO subsystem */
@ -720,6 +746,9 @@ void ogc_video__init(void)
/* Set the framebuffer to be displayed at next VBlank */
VIDEO_SetNextFramebuffer (xfb[0]);
VIDEO_SetPreRetraceCallback(xfb_switch);
VIDEO_SetPostRetraceCallback(xfb_copy);
/* Enable Video Interface */
VIDEO_SetBlack (FALSE);

View File

@ -23,19 +23,22 @@
Modified for use with GenesisPlus Gamecube's port:
- made SN76489_Update outputs 16bits mono samples
- replaced volume table with VGM plugin's one
05/01/2009 Eke-Eke
Modified Cut-Off frequency (according to Steve Snake: http://www.smspower.org/forums/viewtopic.php?t=1746)
*/
#include "shared.h"
#include <float.h> // for FLT_MIN
#include <float.h> // for FLT_MIN
#include <string.h> // for memcpy
#define NoiseInitialState 0x8000 /* Initial state of shift register */
#define PSG_CUTOFF 0x6 /* Value below which PSG does not output */
#define PSG_CUTOFF 0x1 /* Value below which PSG does not output */
static const int PSGVolumeValues[2][16] = {
/* These values are taken from a real SMS2's output */
{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */
{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */
/* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1), normalised at 760 */
{1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0}
};
@ -44,47 +47,46 @@ static SN76489_Context SN76489[MAX_SN76489];
void SN76489_Init(int which, int PSGClockValue, int SamplingRate)
{
SN76489_Context *p = &SN76489[which];
p->dClock=(float)PSGClockValue/16/SamplingRate;
SN76489_Config(which, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 1);
SN76489_Reset(which);
SN76489_Context *p = &SN76489[which];
p->dClock=(float)PSGClockValue/16/SamplingRate;
SN76489_Config(which, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 1);
SN76489_Reset(which);
}
void SN76489_Reset(int which)
{
SN76489_Context *p = &SN76489[which];
int i;
SN76489_Context *p = &SN76489[which];
int i;
p->PSGStereo = 0xFF;
p->PSGStereo = 0xFF;
for(i = 0; i <= 3; i++)
{
/* Initialise PSG state */
p->Registers[2*i] = 1; /* tone freq=1 */
p->Registers[2*i+1] = 0xf; /* vol=off */
p->NoiseFreq = 0x10;
for(i = 0; i <= 3; i++)
{
/* Initialise PSG state */
p->Registers[2*i] = 1; /* tone freq=1 */
p->Registers[2*i+1] = 0xf; /* vol=off */
p->NoiseFreq = 0x10;
/* Set counters to 0 */
p->ToneFreqVals[i] = 0;
/* Set counters to 0 */
p->ToneFreqVals[i] = 0;
/* Set flip-flops to 1 */
p->ToneFreqPos[i] = 1;
/* Set flip-flops to 1 */
p->ToneFreqPos[i] = 1;
/* Set intermediate positions to do-not-use value */
p->IntermediatePos[i] = FLT_MIN;
/* Set intermediate positions to do-not-use value */
p->IntermediatePos[i] = FLT_MIN;
/* Set panning to centre */
p->panning[0]=127;
}
/* Set panning to centre */
p->panning[0]=127;
}
p->LatchedRegister=0;
p->LatchedRegister=0;
/* Initialise noise generator */
p->NoiseShiftRegister=NoiseInitialState;
/* Zero clock */
p->Clock=0;
/* Initialise noise generator */
p->NoiseShiftRegister=NoiseInitialState;
/* Zero clock */
p->Clock=0;
}
void SN76489_Shutdown(void)
@ -93,164 +95,172 @@ void SN76489_Shutdown(void)
void SN76489_Config(int which, int mute, int volume, int feedback, int sr_width, int boost_noise)
{
SN76489_Context *p = &SN76489[which];
SN76489_Context *p = &SN76489[which];
p->Mute = mute;
p->VolumeArray = volume;
p->WhiteNoiseFeedback = feedback;
p->SRWidth = sr_width;
p->BoostNoise = boost_noise;
p->Mute = mute;
p->VolumeArray = volume;
p->WhiteNoiseFeedback = feedback;
p->SRWidth = sr_width;
p->BoostNoise = boost_noise;
}
void SN76489_SetContext(int which, uint8 *data)
{
memcpy(&SN76489[which], data, sizeof(SN76489_Context));
memcpy(&SN76489[which], data, sizeof(SN76489_Context));
}
void SN76489_GetContext(int which, uint8 *data)
{
memcpy(data, &SN76489[which], sizeof(SN76489_Context));
memcpy(data, &SN76489[which], sizeof(SN76489_Context));
}
uint8 *SN76489_GetContextPtr(int which)
{
return (uint8 *)&SN76489[which];
return (uint8 *)&SN76489[which];
}
int SN76489_GetContextSize(void)
{
return sizeof(SN76489_Context);
return sizeof(SN76489_Context);
}
void SN76489_Write(int which, int data)
{
SN76489_Context *p = &SN76489[which];
SN76489_Context *p = &SN76489[which];
if (data&0x80) {
/* Latch/data byte %1 cc t dddd */
p->LatchedRegister=((data>>4)&0x07);
p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */
| (data&0xf); /* and replace with data */
} else {
/* Data byte %0 - dddddd */
if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5))
/* Tone register */
p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */
| ((data&0x3f)<<4); /* and replace with data */
if (data&0x80)
{
/* Latch/data byte %1 cc t dddd */
p->LatchedRegister=((data>>4)&0x07);
p->Registers[p->LatchedRegister] =
(p->Registers[p->LatchedRegister] & 0x3f0) | /* zero low 4 bits */
(data&0xf); /* and replace with data */
}
else
{
/* Data byte %0 - dddddd */
if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5))
/* Tone register */
p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x00f) | /* zero high 6 bits */
((data&0x3f)<<4); /* and replace with data */
else
/* Other register */
p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */
}
switch (p->LatchedRegister) {
case 0:
case 2:
/* Other register */
p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */
}
switch (p->LatchedRegister)
{
case 0:
case 2:
case 4: /* Tone channels */
if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */
break;
/* Zero frequency changed to 1 to avoid div/0 */
if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1;
break;
case 6: /* Noise */
p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */
p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */
break;
}
p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */
p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */
break;
}
}
void SN76489_GGStereoWrite(int which, int data)
{
SN76489_Context *p = &SN76489[which];
p->PSGStereo=data;
SN76489_Context *p = &SN76489[which];
p->PSGStereo=data;
}
void SN76489_Update(int which, INT16 *buffer, int length)
{
SN76489_Context *p = &SN76489[which];
int i, j;
SN76489_Context *p = &SN76489[which];
int i, j;
for(j = 0; j < length; j++)
{
for (i=0;i<=2;++i)
if (p->IntermediatePos[i]!=FLT_MIN)
p->Channels[i]=(short)((p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->IntermediatePos[i]);
else
p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->ToneFreqPos[i];
p->Channels[3]=(short)((p->Mute >> 3 & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[7]]*(p->NoiseShiftRegister & 0x1));
if (p->BoostNoise) p->Channels[3]<<=1; /* double noise volume */
buffer[j] =0;
for (i=0;i<=3;++i) buffer[j] += p->Channels[i];
p->Clock+=p->dClock;
p->NumClocksForSample=(int)p->Clock; /* truncates */
p->Clock-=p->NumClocksForSample; /* remove integer part */
/* Looks nicer in Delphi... */
/* Clock:=Clock+p->dClock; */
/* NumClocksForSample:=Trunc(Clock); */
/* Clock:=Frac(Clock); */
/* Decrement tone channel counters */
for (i=0;i<=2;++i)
p->ToneFreqVals[i]-=p->NumClocksForSample;
/* Noise channel: match to tone2 or decrement its counter */
if (p->NoiseFreq==0x80) p->ToneFreqVals[3]=p->ToneFreqVals[2];
else p->ToneFreqVals[3]-=p->NumClocksForSample;
/* Tone channels: */
for (i=0;i<=2;++i) {
if (p->ToneFreqVals[i]<=0) { /* If it gets below 0... */
if (p->Registers[i*2]>PSG_CUTOFF) {
/* Calculate how much of the sample is + and how much is - */
/* Go to floating point and include the clock fraction for extreme accuracy :D */
/* Store as long int, maybe it's faster? I'm not very good at this */
p->IntermediatePos[i]=(p->NumClocksForSample-p->Clock+2*p->ToneFreqVals[i])*p->ToneFreqPos[i]/(p->NumClocksForSample+p->Clock);
p->ToneFreqPos[i]=-p->ToneFreqPos[i]; /* Flip the flip-flop */
} else {
p->ToneFreqPos[i]=1; /* stuck value */
p->IntermediatePos[i]=FLT_MIN;
}
p->ToneFreqVals[i]+=p->Registers[i*2]*(p->NumClocksForSample/p->Registers[i*2]+1);
} else p->IntermediatePos[i]=FLT_MIN;
}
/* Noise channel */
if (p->ToneFreqVals[3]<=0) { /* If it gets below 0... */
p->ToneFreqPos[3]=-p->ToneFreqPos[3]; /* Flip the flip-flop */
if (p->NoiseFreq!=0x80) /* If not matching tone2, decrement counter */
p->ToneFreqVals[3]+=p->NoiseFreq*(p->NumClocksForSample/p->NoiseFreq+1);
if (p->ToneFreqPos[3]==1) { /* Only once per cycle... */
int Feedback;
if (p->Registers[6]&0x4) { /* White noise */
/* Calculate parity of fed-back bits for feedback */
switch (p->WhiteNoiseFeedback) {
/* Do some optimised calculations for common (known) feedback values */
case 0x0003: /* SC-3000, BBC %00000011 */
case 0x0009: /* SMS, GG, MD %00001001 */
/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
/* since that's (one or more bits set) && (not all bits set) */
Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && ((p->NoiseShiftRegister&p->WhiteNoiseFeedback)^p->WhiteNoiseFeedback));
break;
default: /* Default handler for all other feedback values */
Feedback=p->NoiseShiftRegister&p->WhiteNoiseFeedback;
Feedback^=Feedback>>8;
Feedback^=Feedback>>4;
Feedback^=Feedback>>2;
Feedback^=Feedback>>1;
Feedback&=1;
break;
}
} else /* Periodic noise */
Feedback=p->NoiseShiftRegister&1;
p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | (Feedback << (p->SRWidth-1));
/* Original code: */
/* p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | ((p->Registers[6]&0x4?((p->NoiseShiftRegister&0x9) && (p->NoiseShiftRegister&0x9^0x9)):p->NoiseShiftRegister&1)<<15); */
}
for(j = 0; j < length; j++)
{
/* update output */
for (i=0;i<=2;++i)
if (p->IntermediatePos[i]!=FLT_MIN)
p->Channels[i]=(short)((p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->IntermediatePos[i]);
else
p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->ToneFreqPos[i];
p->Channels[3]=(short)((p->Mute >> 3 & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[7]]*(p->NoiseShiftRegister & 0x1));
if (p->BoostNoise) p->Channels[3]<<=1; /* double noise volume */
buffer[j] =0;
for (i=0;i<=3;++i) buffer[j] += p->Channels[i];
/* update tone */
p->Clock+=p->dClock;
p->NumClocksForSample=(int)p->Clock; /* truncates */
p->Clock-=p->NumClocksForSample; /* remove integer part */
/* Looks nicer in Delphi... */
/* Clock:=Clock+p->dClock; */
/* NumClocksForSample:=Trunc(Clock); */
/* Clock:=Frac(Clock); */
/* Decrement tone channel counters */
for (i=0;i<=2;++i)
p->ToneFreqVals[i]-=p->NumClocksForSample;
/* Noise channel: match to tone2 or decrement its counter */
if (p->NoiseFreq==0x80) p->ToneFreqVals[3]=p->ToneFreqVals[2];
else p->ToneFreqVals[3]-=p->NumClocksForSample;
/* Tone channels: */
for (i=0;i<=2;++i) {
if (p->ToneFreqVals[i]<=0) { /* If it gets below 0... */
if (p->Registers[i*2]>PSG_CUTOFF) {
/* Calculate how much of the sample is + and how much is - */
/* Go to floating point and include the clock fraction for extreme accuracy :D */
/* Store as long int, maybe it's faster? I'm not very good at this */
p->IntermediatePos[i]=(p->NumClocksForSample-p->Clock+2*p->ToneFreqVals[i])*p->ToneFreqPos[i]/(p->NumClocksForSample+p->Clock);
p->ToneFreqPos[i]=-p->ToneFreqPos[i]; /* Flip the flip-flop */
} else {
p->ToneFreqPos[i]=1; /* stuck value */
p->IntermediatePos[i]=FLT_MIN;
}
p->ToneFreqVals[i]+=p->Registers[i*2]*(p->NumClocksForSample/p->Registers[i*2]+1);
} else p->IntermediatePos[i]=FLT_MIN;
}
/* Noise channel */
if (p->ToneFreqVals[3]<=0) { /* If it gets below 0... */
p->ToneFreqPos[3]=-p->ToneFreqPos[3]; /* Flip the flip-flop */
if (p->NoiseFreq!=0x80) /* If not matching tone2, reset counter */
p->ToneFreqVals[3]+=p->NoiseFreq*(p->NumClocksForSample/p->NoiseFreq+1);
if (p->ToneFreqPos[3]==1) { /* Only once per cycle... */
int Feedback;
if (p->Registers[6]&0x4) { /* White noise */
/* Calculate parity of fed-back bits for feedback */
switch (p->WhiteNoiseFeedback) {
/* Do some optimised calculations for common (known) feedback values */
case 0x0003: /* SC-3000, BBC %00000011 */
case 0x0009: /* SMS, GG, MD %00001001 */
/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
/* since that's (one or more bits set) && (not all bits set) */
Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && ((p->NoiseShiftRegister&p->WhiteNoiseFeedback)^p->WhiteNoiseFeedback));
break;
default: /* Default handler for all other feedback values */
Feedback=p->NoiseShiftRegister&p->WhiteNoiseFeedback;
Feedback^=Feedback>>8;
Feedback^=Feedback>>4;
Feedback^=Feedback>>2;
Feedback^=Feedback>>1;
Feedback&=1;
break;
}
} else /* Periodic noise */
Feedback=p->NoiseShiftRegister&1;
p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | (Feedback << (p->SRWidth-1));
/* Original code: */
/* p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | ((p->Registers[6]&0x4?((p->NoiseShiftRegister&0x9) && (p->NoiseShiftRegister&0x9^0x9)):p->NoiseShiftRegister&1)<<15); */
}
}
}
}
/*void SN76489_UpdateOne(int which, int *l, int *r)

View File

@ -28,7 +28,7 @@
#ifndef _SN76489_H_
#define _SN76489_H_
#define MAX_SN76489 4
#define MAX_SN76489 1
/*
More testing is needed to find and confirm feedback patterns for

View File

@ -12,7 +12,7 @@
CC = gcc
AS = nasm -f coff
LDFLAGS =
FLAGS = -I. -I.. -I../z80 -I../m68k -I../dos -I../sound -I../sound/SRC -I../cart_hw -I../cart_hw/svp \
FLAGS = -I. -I.. -I../z80 -I../m68k -I../dos -I../sound -I../sound/SRC -I../cart_hw -I../cart_hw/svp -I../ntsc \
-Wall -g \
-O6 -march=i686 -fomit-frame-pointer \
-DLSB_FIRST -DX86_ASM -DDOS
@ -61,6 +61,9 @@ OBJ += obj/dos.o \
obj/fileio.o \
obj/loadrom.o
OBJ += obj/sms_ntsc.o \
obj/md_ntsc.o
EXE = ../gen.exe
all : $(EXE)
@ -102,6 +105,10 @@ obj/%.o : ../m68k/%.c ../m68k/%.h
obj/%.o : ./%.c ./%.h
$(CC) -c $< -o $@ $(FLAGS)
obj/%.o : ../ntsc/%.c ../ntsc/%.h
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@
pack :
strip $(EXE)
upx -1 $(EXE)

View File

@ -58,7 +58,7 @@ OBJECTS += obj/main.o \
obj/loadrom.o
OBJECTS += obj/sms_ntsc.o \
obj/md_ntsc.o
obj/md_ntsc.o
OBJECTS += obj/icon.o

View File

@ -249,8 +249,8 @@ void vdp_restore(uint8 *vdp_regs)
bitmap.viewport.changed = 1;
/* restore VDP timings */
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
fifo_latency = (reg[12] & 1) ? 27 : 30;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2;
/* remake cache */
for (i=0;i<0x800;i++)