File:  [RetroPC.NET] / np2 / io / pic.c
Revision 1.18: download - view: text, annotated - select for diffs
Tue Mar 30 16:12:03 2004 JST (21 years, 7 months ago) by yui
Branches: MAIN
CVS tags: HEAD
fix 86PCM (T.Yui)

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


enum {
	PIC_OCW2_L		= 0x07,
	PIC_OCW2_EOI	= 0x20,
	PIC_OCW2_SL		= 0x40,
	PIC_OCW2_R		= 0x80,

	PIC_OCW3_RIS	= 0x01,
	PIC_OCW3_RR		= 0x02,
	PIC_OCW3_P		= 0x04,
	PIC_OCW3_SMM	= 0x20,
	PIC_OCW3_ESMM	= 0x40
};


static const _PICITEM def_master = {
								{0x11, 0x08, 0x80, 0x1d},
								0x7d, 0, 0, 0, 0, 0};

static const _PICITEM def_slave = {
								{0x11, 0x10, 0x07, 0x09},
								0x71, 0, 0, 0, 0, 0};


// ----

void pic_irq(void) {

	PIC		p;
	REG8	imr;
	REG8	mir;
	REG8	mis;
	REG8	sir;
	REG8	sis;
	REG8	dat;
	REG8	num;
	REG8	bit;
	REG8	slave;
	REG8	master;

	// 割込み許可?
	if (!CPU_isEI) {
		return;
	}
	p = &pic;

	// マスター
	imr = p->pi[0].imr;
	mir = p->pi[0].irr;
	mis = p->pi[0].isr;
	if (!(p->pi[0].ocw3 & PIC_OCW3_SMM)) {
		mir &= ~imr;
	}
	else {
		mis &= imr;
	}
	mir &= ~mis;
	slave = p->pi[0].icw[2];
	if (mir) {
		dat = mir | mis;
		num = p->pi[0].pry;
		bit = 1 << num;
		while(!(dat & bit)) {
			num = (num + 1) & 7;
			bit = 1 << num;
		}
		if ((mir & bit) && (!(slave & bit))) {
			p->pi[0].isr |= bit;
			p->pi[0].irr &= ~bit;
			if (num == 0) {
				nevent_reset(NEVENT_PICMASK);
			}
//			TRACEOUT(("hardware-int %.2x", (p->pi[0].icw[1] & 0xf8) | num));
			CPU_INTERRUPT((REG8)((p->pi[0].icw[1] & 0xf8) | num), 0);
			return;
		}
	}

	// スレーヴ許可?
	dat = slave | mis;
	if (!dat) {
		return;
	}
	num = p->pi[0].pry;
	bit = 1 << num;
	while(!(dat & bit)) {
		num = (num + 1) & 7;
		bit = 1 << num;
	}
	if (!(slave & bit)) {
		return;
	}

	// スレーヴ
	imr = p->pi[1].imr;
	sir = p->pi[1].irr;
	sis = p->pi[1].isr;
	if (!(p->pi[1].ocw3 & PIC_OCW3_SMM)) {
		sir &= ~imr;
	}
	else {
		sis &= imr;
	}
	sir &= ~sis;
	if (sir) {
		dat = sir | sis;
		num = p->pi[1].pry;
		bit = 1 << num;
		while(!(dat & bit)) {
			num = (num + 1) & 7;
			bit = 1 << num;
		}
		if (sir & bit) {
			p->pi[1].isr |= bit;
			p->pi[1].irr &= ~bit;
			master = 1 << (p->pi[1].icw[2] & 7);
			if (!(p->pi[0].isr & master)) {
				p->pi[0].isr |= master;
				p->pi[0].irr &= ~master;
			}
//			TRACEOUT(("hardware-int %.2x", (p->pi[1].icw[1] & 0xf8) | num));
			CPU_INTERRUPT((REG8)((p->pi[1].icw[1] & 0xf8) | num), 0);
			return;
		}
	}
}


// 簡易モード(SYSTEM TIMERだけ)
void picmask(NEVENTITEM item) {

	PICITEM		pi;

	if (item->flag & NEVENT_SETEVENT) {
		pi = &pic.pi[0];
		pi->irr &= ~(pi->imr & PIC_SYSTEMTIMER);
	}
}

void pic_setirq(REG8 irq) {

	PICITEM	pi;
	REG8	bit;

	pi = pic.pi;
	bit = 1 << (irq & 7);
	if (!(irq & 8)) {
		pi[0].irr |= bit;
		if (pi[0].imr & bit) {
			if (bit & PIC_SYSTEMTIMER) {
				if ((pit.ch[0].ctrl & 0x0c) == 0x04) {
					SINT32 cnt;										// ver0.29
					if (pit.ch[0].value > 8) {
						cnt = pccore.multiple * pit.ch[0].value;
						cnt >>= 2;
					}
					else {
						cnt = pccore.multiple << (16 - 2);
					}
					nevent_set(NEVENT_PICMASK, cnt, picmask, NEVENT_ABSOLUTE);
				}
			}
		}
		if (pi[0].isr & bit) {
			if (bit & PIC_CRTV) {
				pi[0].irr &= ~PIC_CRTV;
				gdc.vsyncint = 1;
			}
		}
	}
	else {
		pi[1].irr |= bit;
	}
}

void pic_resetirq(REG8 irq) {

	PICITEM		pi;

	pi = pic.pi + ((irq >> 3) & 1);
	pi->irr &= ~(1 << (irq & 7));
}


// ---- I/O

static void IOOUTCALL pic_o00(UINT port, REG8 dat) {

	PICITEM	picp;
	REG8	level;
	UINT8	ocw3;

//	TRACEOUT(("pic %x %x", port, dat));
	picp = &pic.pi[(port >> 3) & 1];
	picp->writeicw = 0;
	switch(dat & 0x18) {
		case 0x00:						// ocw2
			if (dat & PIC_OCW2_SL) {
				level = dat & PIC_OCW2_L;
			}
			else {
				if (!picp->isr) {
					break;
				}
				level = picp->pry;
				while(!(picp->isr & (1 << level))) {
					level = (level + 1) & 7;
				}
			}
			if (dat & PIC_OCW2_R) {
				picp->pry = (level + 1) & 7;
			}
			if (dat & PIC_OCW2_EOI) {
				picp->isr &= ~(1 << level);
			}
			nevent_forceexit();				// mainloop exit
			break;

		case 0x08:							// ocw3
			ocw3 = picp->ocw3;
			if (!(dat & PIC_OCW3_RR)) {
				dat &= PIC_OCW3_RIS;
				dat |= (ocw3 & PIC_OCW3_RIS);
			}
			if (!(dat & PIC_OCW3_ESMM)) {
				dat &= ~PIC_OCW3_SMM;
				dat |= (ocw3 & PIC_OCW3_SMM);
			}
			picp->ocw3 = dat;
			break;

		default:
			picp->icw[0] = dat;
			picp->imr = 0;
			picp->irr = 0;
			picp->ocw3 = 0;
#if 0
			picp->levels = 0;
			picp->isr = 0;
#endif
			picp->pry = 0;
			picp->writeicw = 1;
			break;
	}
}

static void IOOUTCALL pic_o02(UINT port, REG8 dat) {

	PICITEM		picp;

//	TRACEOUT(("pic %x %x", port, dat));
	picp = &pic.pi[(port >> 3) & 1];
	if (!picp->writeicw) {
#if 1
		UINT8	set;
		set = picp->imr & (~dat);
		// リセットされたビットは割り込みある?
		if ((CPU_isDI) || (!(picp->irr & set))) {
			picp->imr = dat;
			return;
		}
#endif
		picp->imr = dat;
	}
	else {
		picp->icw[picp->writeicw] = dat;
		picp->writeicw++;
		if (picp->writeicw >= (3 + (picp->icw[0] & 1))) {
			picp->writeicw = 0;
		}
	}
	nevent_forceexit();
}

static REG8 IOINPCALL pic_i00(UINT port) {

	PICITEM		picp;

	picp = &pic.pi[(port >> 3) & 1];
	if (!(picp->ocw3 & PIC_OCW3_RIS)) {
		return(picp->irr);			// read irr
	}
	else {
		return(picp->isr);			// read isr
	}
}

static REG8 IOINPCALL pic_i02(UINT port) {

	PICITEM		picp;

	picp = &pic.pi[(port >> 3) & 1];
	return(picp->imr);
}


// ---- I/F

#if !defined(SUPPORT_PC9821)
static const IOOUT pico00[2] = {
					pic_o00,	pic_o02};

static const IOINP pici00[2] = {
					pic_i00,	pic_i02};
#else
static const IOOUT pico00[4] = {
					pic_o00,	pic_o02,	NULL,	NULL};

static const IOINP pici00[4] = {
					pic_i00,	pic_i02,	NULL,	NULL};
#endif

void pic_reset(void) {

	pic.pi[0] = def_master;
	pic.pi[1] = def_slave;
}

void pic_bind(void) {

#if !defined(SUPPORT_PC9821)
	iocore_attachsysoutex(0x0000, 0x0cf1, pico00, 2);
	iocore_attachsysinpex(0x0000, 0x0cf1, pici00, 2);
#else
	iocore_attachsysoutex(0x0000, 0x0cf1, pico00, 4);
	iocore_attachsysinpex(0x0000, 0x0cf1, pici00, 4);
#endif
}


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