File:  [RetroPC.NET] / xmil / adv / advpsg.c
Revision 1.1: download - view: text, annotated - select for diffs
Fri Feb 4 15:42:07 2005 JST (20 years, 8 months ago) by yui
Branches: MAIN
CVS tags: HEAD
RetroPC CVS restarting 2005/02/04 (T.Yui)

#include	"compiler.h"
#include	"z80core.h"
#include	"pccore.h"
#include	"advpsg.h"


// #define	PSG0_DISABLE
// #define	PSG1_DISABLE
// #define	PSG2_DISABLE


enum {
	PSGENV_INC			= 15,
	PSGENV_ONESHOT		= 16,
	PSGENV_LASTON		= 32,
	PSGENV_ONECYCLE		= 64
};


// エンベロープパターン
static const UINT8 psgenv_pat[16] = {
					PSGENV_ONESHOT,
					PSGENV_ONESHOT,
					PSGENV_ONESHOT,
					PSGENV_ONESHOT,
					PSGENV_ONESHOT | PSGENV_INC,
					PSGENV_ONESHOT | PSGENV_INC,
					PSGENV_ONESHOT | PSGENV_INC,
					PSGENV_ONESHOT | PSGENV_INC,
					PSGENV_ONECYCLE,
					PSGENV_ONESHOT,
					0,
					PSGENV_ONESHOT | PSGENV_LASTON,
					PSGENV_ONECYCLE | PSGENV_INC,
					PSGENV_ONESHOT | PSGENV_INC | PSGENV_LASTON,
					PSGENV_INC,
					PSGENV_ONESHOT | PSGENV_INC};

#if 0
static const UINT32 advwavepat[16] = {
		0x00000000, 0x00001111, 0x00002222, 0x00003333,
		0x00004444, 0x00005555, 0x00006666, 0x00007777,
		0x00008888, 0x00009999, 0x0000aaaa, 0x0000bbbb,
		0x0000cccc, 0x0000dddd, 0x0000eeee, 0x0000ffff};
#else
static const UINT32 advwavepat[16] = {
		0x00000000, 0x11111111, 0x22222222, 0x33333333,
		0x44444444, 0x55555555, 0x66666666, 0x77777777,
		0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbbb,
		0xcccccccc, 0xdddddddd, 0xeeeeeeee, 0xffffffff};
#endif


// PSG 2MHz / (16 * x)
// -> GB (4,194,304Hz / 16 / x) >> y
// **** if x=0 assume x=0.5 instead

#define	NOISEDAT(x, y)	((x) + ((y) << 4))

static const UINT8 noisepat[32] = {
		NOISEDAT(1,0),	NOISEDAT(1,1),	NOISEDAT(1,2),	NOISEDAT(3,1),
		NOISEDAT(1,3),	NOISEDAT(5,1),	NOISEDAT(3,2),	NOISEDAT(7,1),
		NOISEDAT(1,4),	NOISEDAT(5,2),	NOISEDAT(5,2),	NOISEDAT(3,3),
		NOISEDAT(3,3),	NOISEDAT(7,2),	NOISEDAT(7,2),	NOISEDAT(1,5),
		NOISEDAT(1,5),	NOISEDAT(5,3),	NOISEDAT(5,3),	NOISEDAT(5,3),
		NOISEDAT(5,3),	NOISEDAT(5,3),	NOISEDAT(3,4),	NOISEDAT(3,4),
		NOISEDAT(3,4),	NOISEDAT(7,3),	NOISEDAT(7,3),	NOISEDAT(7,3),
		NOISEDAT(7,3),	NOISEDAT(1,6),	NOISEDAT(1,6),	NOISEDAT(1,6)};


static void updatevolume(ADVPSG psg, REG8 bitmap) {

	REG8		mix;
	REG8		vol;
	REG8		bank;
volatile UINT32	*r;
	UINT32		data;
	REG8		noise;

	mix = psg->reg.mixer;
#if !defined(PSG0_DISABLE)
	if (bitmap & 0x01) {
		vol = 0;
		if (!(mix & 0x01)) {
			vol = psg->reg.vol[0];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
		}
		if (psg->vol[0] != vol) {
			psg->vol[0] = vol;
			*REG_SOUND1CNT_H = (UINT16)((vol << ADVSNDBIT_ENV)
												+ (2 << ADVSNDBIT_DUTYCYCLE));
			*REG_SOUND1CNT_X = psg->freq[0];
		}
	}
#endif
#if !defined(PSG1_DISABLE)
	if (bitmap & 0x02) {
		vol = 0;
		if (!(mix & 0x02)) {
			vol = psg->reg.vol[1];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
		}
		if (psg->vol[1] != vol) {
			psg->vol[1] = vol;
			*REG_SOUND2CNT_L = (UINT16)((vol << ADVSNDBIT_ENV)
												+ (2 << ADVSNDBIT_DUTYCYCLE));
			*REG_SOUND2CNT_H = psg->freq[1];
		}
	}
#endif
#if !defined(PSG2_DISABLE)
	if (bitmap & 0x04) {
		vol = 0;
		if (!(mix & 0x04)) {
			vol = psg->reg.vol[2];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
		}
		if (psg->vol[2] != vol) {
			psg->vol[2] = vol;
			if (vol == 0) {
				*REG_SOUND3CNT_L = 0;
				psg->ch3bank = 0;
			}
			else {
				bank = psg->ch3bank ^ 1;
				psg->ch3bank = bank;
				data = advwavepat[vol];
				r = REG_WAVE_RAM0;
				r[0] = data;
				r[1] = 0; // data;
				r[2] = data;
				r[3] = 0; // data;
				*REG_SOUND3CNT_L =
						(1 << ADVSNDBIT_OUTPUT) + (bank << ADVSNDBIT_BANKSEL);
				*REG_SOUND3CNT_X = psg->freq[2];
			}
		}
	}
#endif
	if (bitmap & 0x38) {
		noise = 0;
		if (!(mix & 0x08)) {
			vol = psg->reg.vol[0];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
			noise = max(noise, vol);
		}
		if (!(mix & 0x10)) {
			vol = psg->reg.vol[1];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
			noise = max(noise, vol);
		}
		if (!(mix & 0x20)) {
			vol = psg->reg.vol[2];
			if (vol & 0x10) {
				vol = psg->envvol;
			}
			else {
				vol = vol & 0x0f;
			}
			noise = max(noise, vol);
		}
		if (psg->vol[3] != noise) {
			psg->vol[3] = noise;
			*REG_SOUND4CNT_L = (UINT16)(noise << ADVSNDBIT_ENV);
			*REG_SOUND4CNT_H = psg->freq[3];
		}
	}
}

void advpsg_sync(ADVPSG psg) {

	UINT32	clock;
	int		step;

	if (psg->envvolcnt < 0) {
		return;
	}
	clock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
	clock -= psg->lastclock;
	if (clock < psg->envmax) {
		return;
	}
	step = clock / psg->envmax;
	psg->lastclock += step * psg->envmax;
	if (psg->envvolcnt >= step) {
		psg->envvolcnt -= step;
		psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
	}
	else {
		if (psg->envmode & PSGENV_ONESHOT) {
			psg->envvolcnt = -1;
			psg->envvol = (psg->envmode & PSGENV_LASTON)?15:0;
		}
		else {
			psg->envvolcnt -= (step & 0x1f);
			while(psg->envvolcnt < 0) {
				psg->envvolcnt += 16;
				if (!(psg->envmode & PSGENV_ONECYCLE)) {
					psg->envmode ^= PSGENV_INC;
				}
			}
			psg->envvol = (psg->envvolcnt ^ psg->envmode) & 0x0f;
		}
	}
	updatevolume(psg, 0x3f);
}

void advpsg_setreg(ADVPSG psg, REG8 reg, REG8 value) {

	REG8	modify;
	REG8	ch;
	UINT32	freq;

	if (reg >= 14) {
		return;
	}
	modify = ((UINT8 *)&psg->reg)[reg] ^ value;
	if ((!modify) && (reg != 13)) {
		return;
	}
	advpsg_sync(psg);
	((UINT8 *)&psg->reg)[reg] = value;
	switch(reg) {
#if !defined(PSG0_DISABLE)
		case 0:
		case 1:
#endif
#if !defined(PSG1_DISABLE)
		case 2:
		case 3:
#endif
#if !defined(PSG2_DISABLE)
		case 4:
		case 5:
#endif
			ch = reg >> 1;
			freq = psg->reg.tune[ch][0] +
										((psg->reg.tune[ch][1] & 0x0f) << 8);
			freq = (freq * 68719) >> 16;
#if 0
			if (ch == 2) {
				freq <<= 1;
			}
#endif
			if (freq == 0) {
				freq = 1;
			}
			else if (freq > 2048) {
				freq = 2048;
			}
			freq = (1 << ADVSNDBIT_RESET) + 0x800 - freq;
			psg->freq[ch] = freq;
			REG_SOUND1CNT_X[ch * 4] = freq;
			break;

		case 6:
			freq = (1 << ADVSNDBIT_RESET) + noisepat[value & 0x1f];
			psg->freq[3] = freq;
			*REG_SOUND4CNT_H = freq;
			break;

		case 7:
			if (modify & 0x3f) {
				updatevolume(psg, modify);
			}
			break;

#if !defined(PSG0_DISABLE)
		case 8:
#endif
#if !defined(PSG1_DISABLE)
		case 9:
#endif
#if !defined(PSG2_DISABLE)
		case 10:
#endif
			updatevolume(psg, (REG8)(0x09 << (reg - 8)));
			break;

		case 11:
		case 12:
			freq = LOADINTELWORD(psg->reg.envtime);
			if (freq == 0) {
				freq = 1 << 16;
			}
#if defined(FIX_Z80A)
			freq = freq * 16 * 2;
#else
			freq = freq * 16 * pccore.multiple;
#endif
			psg->envmax = freq;
			break;

		case 13:
			psg->envmode = psgenv_pat[value & 0x0f];
			psg->envvolcnt = 15;
			psg->envvol = (~psg->envmode) & 15;
			psg->lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
			updatevolume(psg, 0x3f);
			break;
	}
}

REG8 psggen_getreg(ADVPSG psg, REG8 reg) {

	return(((UINT8 *)&psg->reg)[reg & 15]);
}


// ----

void advpsg_reset(ADVPSG psg) {

	ZeroMemory(psg, sizeof(_ADVPSG));
	psg->reg.mixer = 0x3f;
	psg->reg.io1 = 0xff;
	psg->reg.io2 = 0xff;

	psg->envmode = PSGENV_ONESHOT;
	psg->envvolcnt = 15;
	psg->envvol = 15;
	psg->lastclock = CPU_CLOCK;
	psg->envmax = (1 << 16) * 32;

	*REG_SOUNDCNT_X	= 0x80;
	*REG_SOUNDCNT_L	= 0xff66;
	*REG_SOUNDCNT_H	= 2;

	*REG_SOUND1CNT_L = 0;
	*REG_SOUND1CNT_H = (2 << ADVSNDBIT_DUTYCYCLE);
	*REG_SOUND1CNT_X = (1 << ADVSNDBIT_RESET);
	*REG_SOUND2CNT_L = (2 << ADVSNDBIT_DUTYCYCLE);
	*REG_SOUND2CNT_H = (1 << ADVSNDBIT_RESET);

	*REG_SOUND3CNT_L = 0;
	*REG_SOUND3CNT_H = (1 << ADVSNDBIT_VOLRATIO);
	*REG_SOUND3CNT_X = (1 << ADVSNDBIT_RESET);

	*REG_SOUND4CNT_L = 0;
	*REG_SOUND4CNT_H = 0;

	*REG_WAVE_RAM0 = 0;
	*REG_WAVE_RAM1 = 0;
	*REG_WAVE_RAM2 = 0;
	*REG_WAVE_RAM3 = 0;

	*REG_SOUNDBIAS = 0x200 + (3 << 14);
}


RetroPC.NET-CVS <cvs@retropc.net>