www.pudn.com > ncdzsrc.rar > pd4990a.c


/* 
 *	Emulation for the NEC PD4990A. 
 * 
 *	The PD4990A is a serial I/O Calendar & Clock IC used in the 
 *		NEO GEO and probably a couple of other machines. 
 */ 
 
#include "neogeocd.h" 
 
/* Set the data in the chip to Monday 09/09/73 00:00:00 	*/ 
/* If you ever read this Leejanne, you know what I mean :-) */ 
struct pd4990a_s pd4990a = 
{ 
	0x00,	/* seconds BCD */ 
	0x00,	/* minutes BCD */ 
	0x00,	/* hours   BCD */ 
	0x09,	/* days    BCD */ 
	9,		/* month   Hexadecimal form */ 
	0x73,	/* year    BCD */ 
	1		/* weekday BCD */ 
}; 
 
static int retraces = 0;	/* Assumes 60 retraces a second */ 
static int coinflip = 0;	/* Pulses a bit in order to simulate */ 
					/* test output */ 
static int outputbit=0; 
static int bitno=0; 
 
void pd4990a_addretrace (void) 
{ 
	coinflip ^= 1; 
	retraces++; 
	if (retraces < 60) 
		return; 
	retraces = 0; 
	pd4990a.seconds++; 
	if ( (pd4990a.seconds & 0x0f) < 10 ) 
		return; 
	pd4990a.seconds &= 0xf0; 
	pd4990a.seconds += 0x10; 
	if (pd4990a.seconds < 0x60) 
		return; 
	pd4990a.seconds = 0; 
	pd4990a.minutes++; 
	if ( (pd4990a.minutes & 0x0f) < 10 ) 
		return; 
	pd4990a.minutes &= 0xf0; 
	pd4990a.minutes += 0x10; 
	if (pd4990a.minutes < 0x60) 
		return; 
	pd4990a.minutes = 0; 
	pd4990a.hours++; 
	if ( (pd4990a.hours & 0x0f) < 10 ) 
		return; 
	pd4990a.hours &= 0xf0; 
	pd4990a.hours += 0x10; 
	if (pd4990a.hours < 0x24) 
		return; 
	pd4990a.hours = 0; 
	pd4990a_increment_day(); 
} 
 
void pd4990a_increment_day(void) 
{ 
	int real_year; 
 
	pd4990a.days++; 
	if ((pd4990a.days & 0x0f) >= 10) 
	{ 
		pd4990a.days &= 0xf0; 
		pd4990a.days += 0x10; 
	} 
 
	pd4990a.weekday++; 
	if (pd4990a.weekday == 7) 
		pd4990a.weekday=0; 
 
	switch(pd4990a.month) 
	{ 
	case 1: case 3: case 5: case 7: case 8: case 10: case 12: 
		if (pd4990a.days == 0x32) 
		{ 
			pd4990a.days = 1; 
			pd4990a_increment_month(); 
		} 
		break; 
	case 2: 
		real_year = (pd4990a.year>>4)*10 + (pd4990a.year&0xf); 
		if ((real_year % 4) && (!(real_year % 100) || (real_year % 400))) 
		{ 
			if (pd4990a.days == 0x29) 
			{ 
				pd4990a.days = 1; 
				pd4990a_increment_month(); 
			} 
		} 
		else 
		{ 
			if (pd4990a.days == 0x30) 
			{ 
				pd4990a.days = 1; 
				pd4990a_increment_month(); 
			} 
		} 
		break; 
	case 4: case 6: case 9: case 11: 
		if (pd4990a.days == 0x31) 
		{ 
			pd4990a.days = 1; 
			pd4990a_increment_month(); 
		} 
		break; 
	} 
} 
 
void pd4990a_increment_month(void) 
{ 
	pd4990a.month++; 
	if (pd4990a.month == 13) 
	{ 
		pd4990a.month = 1; 
		pd4990a.year++; 
		if ( (pd4990a.year & 0x0f) >= 10 ) 
		{ 
			pd4990a.year &= 0xf0; 
			pd4990a.year += 0x10; 
		} 
		if (pd4990a.year == 0xA0) 
			pd4990a.year = 0; 
	} 
} 
 
READ8_HANDLER( pd4990a_testbit_r ) 
{ 
	return (coinflip); 
} 
 
READ8_HANDLER( pd4990a_databit_r ) 
{ 
	return (outputbit); 
} 
 
WRITE8_HANDLER( pd4990a_control_w ) 
{ 
	switch (data) 
	{ 
	case 0x00:	/* Load Register */ 
		switch(bitno) 
		{ 
		case 0x00: case 0x01: case 0x02: case 0x03: 
		case 0x04: case 0x05: case 0x06: case 0x07: 
			outputbit=(pd4990a.seconds >> bitno) & 0x01; 
			break; 
		case 0x08: case 0x09: case 0x0a: case 0x0b: 
		case 0x0c: case 0x0d: case 0x0e: case 0x0f: 
			outputbit=(pd4990a.minutes >> (bitno-0x08)) & 0x01; 
			break; 
		case 0x10: case 0x11: case 0x12: case 0x13: 
		case 0x14: case 0x15: case 0x16: case 0x17: 
			outputbit=(pd4990a.hours >> (bitno-0x10)) & 0x01; 
			break; 
		case 0x18: case 0x19: case 0x1a: case 0x1b: 
		case 0x1c: case 0x1d: case 0x1e: case 0x1f: 
			outputbit=(pd4990a.days >> (bitno-0x18)) & 0x01; 
			break; 
		case 0x20: case 0x21: case 0x22: case 0x23: 
			outputbit=(pd4990a.weekday >> (bitno-0x20)) & 0x01; 
			break; 
		case 0x24: case 0x25: case 0x26: case 0x27: 
			outputbit=(pd4990a.month >> (bitno-0x24)) & 0x01; 
			break; 
		case 0x28: case 0x29: case 0x2a: case 0x2b: 
		case 0x2c: case 0x2d: case 0x2e: case 0x2f: 
			outputbit=(pd4990a.year >> (bitno-0x28)) & 0x01; 
			break; 
		} 
		break; 
 
	case 0x02:	/* shift one position */ 
		bitno++; 
		break; 
 
	case 0x04:	/* Start afresh with shifting */ 
		bitno = 0; 
		break; 
 
	default:	/* Unhandled value */ 
		break; 
	} 
} 
 
WRITE16_HANDLER( pd4990a_control_16_w ) 
{ 
	pd4990a_control_w(offset, data & 0xff); 
}