⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 z80fmly.c

📁 这个是延伸mame的在wince平台下的游戏模拟器的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************

  Z80 FMLY.C   Z80 FAMILY CHIP EMURATOR for MAME Ver.0.1 alpha

  Support chip :  Z80PIO , Z80CTC

  Copyright(C) 1997 Tatsuyuki Satoh.

  This version are tested starforce driver.

  8/21/97 -- Heavily modified by Aaron Giles to be much more accurate for the MCR games
  8/27/97 -- Rewritten a second time by Aaron Giles, with the datasheets in hand

pending:
	Z80CTC , Counter mode & Timer with Trigrt start :not support Triger level

***************************************************************************/

#include <stdio.h>
#include "driver.h"
#include "z80fmly.h"
#include "timer.h"

typedef struct
{
	int vector;                           /* interrupt vector */
	int clock;                            /* system clock */
	double invclock16;                    /* 16/system clock */
	double invclock256;                   /* 256/system clock */
	void (*intr)(int which);              /* interrupt callback */
	void (*zc[4])(int offset, int data);  /* zero crossing callbacks */
	int notimer;                          /* no timer masks */
	int mask[4];                          /* masked channel flags */
	int mode[4];                          /* current mode */
	int tconst[4];                        /* time constant */
	int down[4];                          /* down counter (clock mode only) */
	int extclk[4];                        /* current signal from the external clock */
	void *timer[4];                       /* array of active timers */

	int int_state[4];                     /* interrupt status (for daisy chain) */
} z80ctc;

static z80ctc ctcs[MAX_CTC];


/* these are the bits of the incoming commands to the CTC */
#define INTERRUPT			0x80
#define INTERRUPT_ON 	0x80
#define INTERRUPT_OFF	0x00

#define MODE				0x40
#define MODE_TIMER		0x00
#define MODE_COUNTER		0x40

#define PRESCALER			0x20
#define PRESCALER_256	0x20
#define PRESCALER_16		0x00

#define EDGE				0x10
#define EDGE_FALLING		0x00
#define EDGE_RISING		0x10

#define TRIGGER			0x08
#define TRIGGER_AUTO		0x00
#define TRIGGER_CLOCK	0x08

#define CONSTANT			0x04
#define CONSTANT_LOAD	0x04
#define CONSTANT_NONE	0x00

#define RESET				0x02
#define RESET_CONTINUE	0x00
#define RESET_ACTIVE		0x02

#define CONTROL			0x01
#define CONTROL_VECTOR	0x00
#define CONTROL_WORD		0x01

/* these extra bits help us keep things accurate */
#define WAITING_FOR_TRIG	0x100


static void z80ctc_timercallback (int param);


void z80ctc_init (z80ctc_interface *intf)
{
	int i;

	memset (ctcs, 0, sizeof (ctcs));

	for (i = 0; i < intf->num; i++)
	{
		ctcs[i].clock = intf->baseclock[i];
		ctcs[i].invclock16 = 16.0 / (double)intf->baseclock[i];
		ctcs[i].invclock256 = 256.0 / (double)intf->baseclock[i];
		ctcs[i].notimer = intf->notimer[i];
		ctcs[i].intr = intf->intr[i];
		ctcs[i].zc[0] = intf->zc0[i];
		ctcs[i].zc[1] = intf->zc1[i];
		ctcs[i].zc[2] = intf->zc2[i];
		ctcs[i].zc[3] = 0;
		z80ctc_reset (i);
	}
}


double z80ctc_getperiod (int which, int ch)
{
	z80ctc *ctc = ctcs + which;
	double clock;
	int mode;

	/* keep channel within range, and get the current mode */
	ch &= 3;
	mode = ctc->mode[ch];

	/* if reset active */
	if( (mode & RESET) == RESET_ACTIVE) return 0;
	/* if counter mode */
	if( (mode & MODE) == MODE_COUNTER)
	{
		return 0;
	}

	/* compute the period */
	clock = ((mode & PRESCALER) == PRESCALER_16) ? ctc->invclock16 : ctc->invclock256;
	return clock * (double)ctc->tconst[ch];
}

/* interrupt request callback with daisy-chain circuit */
static void z80ctc_interrupt_check( z80ctc *ctc )
{
	int state = 0;
	int ch;

	for( ch = 3 ; ch >= 0 ; ch-- )
	{
		/* if IEO disable , same and lower IRQ is masking */
/* ASG: changed this line because this state could have an interrupt pending as well! */
/*		if( ctc->int_state[ch] & Z80_INT_IEO ) state  = Z80_INT_IEO;*/
		if( ctc->int_state[ch] & Z80_INT_IEO ) state  = ctc->int_state[ch];
		else                                   state |= ctc->int_state[ch];
	}
	/* change interrupt status */
	if (ctc->intr) (*ctc->intr)(state);
}


void z80ctc_reset (int which)
{
	z80ctc *ctc = ctcs + which;
	int i;

	/* set up defaults */
	for (i = 0; i < 4; i++)
	{
		ctc->mode[i] = RESET_ACTIVE;
		ctc->tconst[i] = 0x100;
		ctc->timer[i] = NULL;
		ctc->int_state[i] = 0;
	}
	z80ctc_interrupt_check( ctc );
}

void z80ctc_0_reset (void) { z80ctc_reset (0); }
void z80ctc_1_reset (void) { z80ctc_reset (1); }


void z80ctc_w (int which, int offset, int data)
{
	z80ctc *ctc = ctcs + which;
	int mode, ch;

	/* keep channel within range, and get the current mode */
	ch = offset & 3;
	mode = ctc->mode[ch];

	/* if we're waiting for a time constant, this is it */
	if ((mode & CONSTANT) == CONSTANT_LOAD)
	{
		/* set the time constant (0 -> 0x100) */
		ctc->tconst[ch] = data ? data : 0x100;

		/* clear the internal mode -- we're no longer waiting */
		ctc->mode[ch] &= ~CONSTANT;

		/* also clear the reset, since the constant gets it going again */
		ctc->mode[ch] &= ~RESET;

		/* if we're in timer mode.... */
		if ((mode & MODE) == MODE_TIMER)
		{
			/* if we're triggering on the time constant, reset the down counter now */
			if ((mode & TRIGGER) == TRIGGER_AUTO)
			{
				double clock = ((mode & PRESCALER) == PRESCALER_16) ? ctc->invclock16 : ctc->invclock256;
				if (ctc->timer[ch])
					timer_remove (ctc->timer[ch]);
				if (!(ctc->notimer & (1<<ch)))
					ctc->timer[ch] = timer_pulse (clock * (double)ctc->tconst[ch], (which << 2) + ch, z80ctc_timercallback);
			}

			/* else set the bit indicating that we're waiting for the appropriate trigger */
			else
				ctc->mode[ch] |= WAITING_FOR_TRIG;
		}

		/* also set the down counter in case we're clocking externally */
		ctc->down[ch] = ctc->tconst[ch];

		/* all done here */
		return;
	}

	/* if we're writing the interrupt vector, handle it specially */
#if 0	/* Tatsuyuki Satoh changes */
	/* The 'Z80family handbook' wrote,                            */
	/* interrupt vector is able to set for even channel (0 or 2)  */
	if ((data & CONTROL) == CONTROL_VECTOR && (ch&1) == 0)
#else
	if ((data & CONTROL) == CONTROL_VECTOR && ch == 0)
#endif
	{
		ctc->vector = data & 0xf8;
		return;
	}

	/* this must be a control word */
	if ((data & CONTROL) == CONTROL_WORD)
	{
		/* set the new mode */
		ctc->mode[ch] = data;

		/* if we're being reset, clear out any pending timers for this channel */
		if ((data & RESET) == RESET_ACTIVE)
		{
			if (ctc->timer[ch])
				timer_remove (ctc->timer[ch]);
			ctc->timer[ch] = NULL;

			if( ctc->int_state[ch] != 0 )
			{
				/* clear interrupt service , request */
				ctc->int_state[ch] = 0;
				z80ctc_interrupt_check( ctc );
			}
		}

		/* all done here */
		return;
	}
}

void z80ctc_0_w (int offset, int data) { z80ctc_w (0, offset, data); }
void z80ctc_1_w (int offset, int data) { z80ctc_w (1, offset, data); }


int z80ctc_r (int which, int ch)
{
	z80ctc *ctc = ctcs + which;
	int mode;

	/* keep channel within range */
	ch &= 3;
	mode = ctc->mode[ch];

	/* if we're in counter mode, just return the count */
	if ((mode & MODE) == MODE_COUNTER)
		return ctc->down[ch];

	/* else compute the down counter value */
	else
	{
		double clock = ((mode & PRESCALER) == PRESCALER_16) ? ctc->invclock16 : ctc->invclock256;

		if (ctc->timer[ch])
			return ((int)(timer_timeleft (ctc->timer[ch]) / clock) + 1) & 0xff;
		else
			return 0;
	}
}

int z80ctc_0_r (int offset) { return z80ctc_r (0, offset); }
int z80ctc_1_r (int offset) { return z80ctc_r (1, offset); }


int z80ctc_interrupt( int which )
{
	z80ctc *ctc = ctcs + which;
	int ch;

	for( ch = 0 ; ch < 4 ; ch++ )
	{
		if( ctc->int_state[ch] )
		{
			if( ctc->int_state[ch] == Z80_INT_REQ)
				ctc->int_state[ch] = Z80_INT_IEO;
			break;
		}
	}
	if( ch > 3 )
	{
		ch = 0;
	}
	z80ctc_interrupt_check( ctc );
	return ctc->vector + ch * 2;
}

/* when operate RETI , soud be call this function for request pending interrupt */
void z80ctc_reti( int which )
{
	z80ctc *ctc = ctcs + which;
	int ch;

	for( ch = 0 ; ch < 4 ; ch++ )
	{
		if( ctc->int_state[ch] & Z80_INT_IEO )
		{
			/* highest served interrupt found */
			/* clear interrupt status */
			ctc->int_state[ch] &= ~Z80_INT_IEO;
			/* search next interrupt */
			break;
		}
	}
	/* set next interrupt stattus */
	z80ctc_interrupt_check( ctc );
}

static void z80ctc_timercallback (int param)
{
	int which = param >> 2;
	int ch = param & 3;
	z80ctc *ctc = ctcs + which;

	/* down counter has reached zero - see if we should interrupt */
	if ((ctc->mode[ch] & INTERRUPT) == INTERRUPT_ON)
	{
		if( !(ctc->int_state[ch] & Z80_INT_REQ) )
		{
			ctc->int_state[ch] |= Z80_INT_REQ;
			z80ctc_interrupt_check( ctc );
		}
	}
	/* generate the clock pulse */
	if (ctc->zc[ch])
	{
		(*ctc->zc[ch])(0,1);
		(*ctc->zc[ch])(0,0);
	}

	/* reset the down counter */
	ctc->down[ch] = ctc->tconst[ch];
}


void z80ctc_trg_w (int which, int trg, int offset, int data)
{
	z80ctc *ctc = ctcs + which;
	int ch = trg & 3;
	int mode;

	data = data ? 1 : 0;
	mode = ctc->mode[ch];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -