File:  [RetroPC.NET] / np2 / io / pit.c
Revision 1.15: download - view: text, annotated - select for diffs
Thu Jan 22 10:10:04 2004 JST (21 years, 9 months ago) by yui
Branches: MAIN
CVS tags: VER_0_74, HEAD
update v0.74core (T.Yui)

// 
// μPD8253C タイマLSI
// 

#include	"compiler.h"
#include	"cpucore.h"
#include	"pccore.h"
#include	"iocore.h"
#include	"sound.h"
#include	"beep.h"


// #define	uPD71054					// NP2はuPD8253Cベース
#define	BEEPCOUNTEREX					// BEEPアイドル時のカウンタをα倍に


// --- Interval timer

static void setsystimerevent(BOOL absolute) {

	SINT32	cnt;

	cnt = pit.value[0];
	if (cnt > 8) {									// 根拠なし
		cnt *= pccore.multiple;
	}
	else {
		cnt = pccore.multiple << 16;
	}
	nevent_set(NEVENT_ITIMER, cnt, systimer, absolute);
}

void systimer(NEVENTITEM item) {

	if (item->flag & NEVENT_SETEVENT) {
		if (pit.intr[0]) {
			pit.intr[0] = 0;
			pic_setirq(0);
		}
		if ((pit.mode[0] & 0x0c) == 0x04) {
			// レートジェネレータ
			pit.intr[0] = 1;
			setsystimerevent(NEVENT_RELATIVE);
		}
		else {
			nevent_set(NEVENT_ITIMER, pccore.multiple << 16,
												systimer, NEVENT_RELATIVE);
		}
	}
}


// --- Beep

#if defined(BEEPCOUNTEREX)
static void setbeepeventex(BOOL absolute) {

	UINT32	cnt;

	cnt = pit.value[1];
	if (cnt > 2) {
		cnt *= pccore.multiple;
	}
	else {
		cnt = pccore.multiple << 16;
	}
	while(cnt < 0x100000) {
		cnt <<= 1;
	}
	nevent_set(NEVENT_BEEP, (SINT32)cnt, beeponeshot, absolute);
}
#endif

static void setbeepevent(BOOL absolute) {

	SINT32	cnt;

	cnt = pit.value[1];
	if (cnt > 2) {
		cnt *= pccore.multiple;
	}
	else {
		cnt = pccore.multiple << 16;
	}
	nevent_set(NEVENT_BEEP, cnt, beeponeshot, absolute);
}

void beeponeshot(NEVENTITEM item) {

	if (item->flag & NEVENT_SETEVENT) {
		if (!(pit.mode[1] & 0x0c)) {								// ver0.30
			beep_lheventset(0);
		}
#if defined(uPD71054)
		if ((pit.mode[1] & 0x06) == 0x02)
#else
		if (pit.mode[1] & 0x02)
#endif
		{
#if defined(BEEPCOUNTEREX)
			setbeepeventex(NEVENT_RELATIVE);
#else
			setbeepevent(NEVENT_RELATIVE);
#endif
		}
	}
}


// --- RS-232C

static void setrs232cevent(BOOL absolute) {

	SINT32	cnt;

	if (pit.value[2] > 1) {
		cnt = pccore.multiple * pit.value[2] * rs232c.mul;
	}
	else {
		cnt = (pccore.multiple << 16) * rs232c.mul;
	}
	nevent_set(NEVENT_RS232C, cnt, rs232ctimer, absolute);
}

void rs232ctimer(NEVENTITEM item) {

	if (item->flag & NEVENT_SETEVENT) {
		if ((pit.mode[2] & 0x0c) == 0x04) {
			// レートジェネレータ
			setrs232cevent(NEVENT_RELATIVE);
		}
	}
	rs232c_callback();
}


// ---------------------------------------------------------------------------

static UINT pit_latch(int ch) {

	SINT32	clock;

	if (ch == 1) {
		switch(pit.mode[1] & 0x06) {
#ifdef uPD71054				// ?
			case 0x00:
#endif
			case 0x04:
				return(pit.value[1]);
#ifdef uPD71054
			case 0x06:
				return(pit.value[1] & (~1));
#endif
		}
#if defined(BEEPCOUNTEREX)
		clock = nevent_getremain(NEVENT_ITIMER + ch);
		if (clock < 0) {
			return(0);
		}
		clock /= pccore.multiple;
		if (pit.value[1] > 2) {
			clock %= pit.value[1];
		}
		else {
			clock = LOW16(clock);
		}
		return(clock);
#endif
	}
	clock = nevent_getremain(NEVENT_ITIMER + ch);
	if (clock >= 0) {
		return(clock / pccore.multiple);
	}
	return(0);
}

void pit_setflag(int ch, REG8 value) {

	pit.flag[ch] = 0;
	if (value & 0x30) {
		pit.mode[ch] = (UINT8)value;
	}
	else {														// latch
		pit.mode[ch] &= ~0x30;
		pit.latch[ch] = (UINT16)pit_latch(ch);
	}
}

BOOL pit_setcount(int ch, REG8 value) {

	switch(pit.mode[ch] & 0x30) {
		case 0x10:		// access low
			pit.value[ch] = value;
			break;

		case 0x20:		// access high
			pit.value[ch] = value << 8;
			break;

		case 0x30:		// access word
			if (!(pit.flag[ch] & 2)) {
				pit.value[ch] &= 0xff00;
				pit.value[ch] += value;
				pit.flag[ch] ^= 2;
				return(TRUE);
			}
			pit.value[ch] &= 0x00ff;
			pit.value[ch] += value << 8;
			pit.flag[ch] ^= 2;
			break;
	}
	return(FALSE);
}

REG8 pit_getcount(int ch) {

	REG8	ret;
	REG16	w;

	if (!(pit.mode[ch] & 0x30)) {
		w = pit.latch[ch];
	}
	else {
		w = pit_latch(ch);
	}
	switch(pit.mode[ch] & 0x30) {
		case 0x10:						// access low
			return((UINT8)w);

		case 0x20:						// access high
			return((UINT8)(w >> 8));
	}
	if (!(pit.flag[ch] & 1)) {			// access word
		ret = (UINT8)w;
	}
	else {
		ret = (UINT8)(w >> 8);
	}
	pit.flag[ch] ^= 1;
	return(ret);
}


// ---- I/O

// system timer
static void IOOUTCALL pit_o71(UINT port, REG8 dat) {

//	TRACEOUT(("pic o71: %x", dat));
	if (pit_setcount(0, dat)) {
		return;
	}
	pic.pi[0].irr &= (~1);
	pit.intr[0] = 1;
	setsystimerevent(NEVENT_ABSOLUTE);
	(void)port;
}

// beep
static void IOOUTCALL pit_o73(UINT port, REG8 dat) {

	if (pit_setcount(1, dat)) {
		return;
	}
	setbeepevent(NEVENT_ABSOLUTE);
	if (!(pit.mode[1] & 0x0c)) {
		beep_lheventset(1);
	}
	else {
		beep_hzset(pit.value[1]);
	}
	(void)port;
}

// rs-232c
static void IOOUTCALL pit_o75(UINT port, REG8 dat) {

	if (pit_setcount(2, dat)) {
		return;
	}
	rs232c_open();
	setrs232cevent(NEVENT_ABSOLUTE);
	(void)port;
}

// ctrl
static void IOOUTCALL pit_o77(UINT port, REG8 dat) {

	int		ch;

//	TRACEOUT(("pic o77: %x", dat));
	ch = (dat >> 6) & 3;
	if (ch != 3) {
		pit_setflag(ch, dat);
		if (ch == 0) {			// 書込みで itimerのirrがリセットされる…
			pic.pi[0].irr &= (~1);
			if (dat & 0x30) {	// 一応ラッチ時は割り込みをセットしない
				pit.intr[0] = 1;
//				setsystimerevent(NEVENT_ABSOLUTE);
			}
		}
		if (ch == 1) {
			beep_modeset();
		}
	}
	(void)port;
}

static REG8 IOINPCALL pit_i71(UINT port) {

	return(pit_getcount((port >> 1) & 3));
}


// ---- I/F

static const IOOUT pito71[4] = {
					pit_o71,	pit_o73,	pit_o75,	pit_o77};

static const IOINP piti71[4] = {
					pit_i71,	pit_i71,	pit_i71,	NULL};

void itimer_reset(void) {

	ZeroMemory(&pit, sizeof(pit));
	if (pccore.cpumode & CPUMODE_8MHz) {
		pit.value[1] = 998;				// 4MHz
	}
	else {
		pit.value[1] = 1229;			// 5MHz
	}
	pit.intr[0] = 1;
	pit.mode[0] = 0x30;
	pit.mode[1] = 0x56;
	pit.mode[2] = 0xb6;
	pit.mode[3] = 0x36;
	setsystimerevent(NEVENT_ABSOLUTE);
	beep_hzset(pit.value[1]);
}

void itimer_bind(void) {

	iocore_attachsysoutex(0x0071, 0x0cf1, pito71, 4);
	iocore_attachsysinpex(0x0071, 0x0cf1, piti71, 4);
	iocore_attachout(0x3fdb, pit_o73);
	iocore_attachout(0x3fdf, pit_o77);
	iocore_attachinp(0x3fdb, pit_i71);
}


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