/*
 * (Generic) 6522 VIA emulation
 */

#ifndef VIA6522_H
#define VIA6522_H

#include "types.h"
#include "MemEmul.h"

class VIA6522: public MMIO_Dev
{
protected:
	enum VIA_Regs
	{
		VIA_ORB = 0,
		VIA_ORA = 1,
		VIA_DDRB = 2,
		VIA_DDRA = 3,
		VIA_T1CL = 4,
		VIA_T1CH = 5,
		VIA_T1LL = 6,
		VIA_T1LH = 7,
		VIA_T2CL = 8,
		VIA_T2CH = 9,
		VIA_SR = 0xa,
		VIA_ACR = 0xb,
		VIA_PCR = 0xc,
		VIA_IFR = 0xd,
		VIA_IER = 0xe,
		VIA_ORA_nh = 0xf,	// non-handshaking
		VIA_IRA_nh = 0xf,
		VIA_T2LL = 0x10,
		VIA_IRB = 0x11,
		VIA_IRA = 0x12
	};
	
	byte DDRA, DDRB;
	byte ORB, ORA, IRB, IRA, PinA, PinB;
	
	wordu T1L, T2L;
	
	virtual void PinAchange (void) = 0;
	virtual void PinBchange (void) = 0;
	
	byte SR;
	
	byte ACR;
	enum ACR_bits
	{
		T1_SetPB7 = 0x80,
		T1_Continuous = 0x40,
		T2_PulseCount = 0x20,
		Latch_B = 0x2,
		Latch_A = 0x1
	};
	
	byte PCR;
	inline byte PCR_CA1Control (void) { return PCR & 0x01; }
	inline byte PCR_CA2Control (void) { return (PCR >> 1) & 0x07; }
	inline byte PCR_CB1Control (void) { return PCR & 0x10; }
	inline byte PCR_CB2Control (void) { return (PCR >> 5) & 0x07; }
	
	byte IFR, IER;
	
	int Timer1;
	int Timer2;
	byte T1CL, T1CH, T2CL, T2CH;
	int Timer2_running;
	
	byte CA1, CA2, CB1, CB2;
	
	void SetInts (byte val);
	void ClearInts (byte val);
	
	inline void SetCA1 (byte val) { if (PCR_CA1Control () == val)
		SetInts (INT_CA1); CA1 = val; }
	void SetCA2 (byte val);
	inline void SetCB1 (byte val) { if (PCR_CB1Control () == val)
		SetInts (INT_CB1); CB1 = val; }
	void SetCB2 (byte val);
	
	void ClearPortAints (void);
	void ClearPortBints (void);
	
	enum VIA_Ints
	{
		INT_CA2 = 0x1,
		INT_CA1 = 0x2,
		INT_SR = 0x4,
		INT_CB2 = 0x8,
		INT_CB1 = 0x10,
		INT_T2 = 0x20,
		INT_T1 = 0x40,
		INT_ANY = 0x80
	};
	enum VIA_Int_HS
	{
		HS1_NEG_ACTIVE = 0x00,
		HS2_POS_ACTIVE = 0x01,
		
		HS2_NEG = 0x00,
		HS2_NEG_IND = 0x01,
		HS2_POS = 0x02,
		HS2_POS_IND = 0x03,
		HS2_OUTPUT = 0x04,
		HS2_PULSE = 0x05,
		HS2_LOW = 0x06,
		HS2_HIGH = 0x07,
	};
	virtual void DoTimers (void);
	
public:
	VIA6522 (int m, int a): MMIO_Dev (m, a) { addr.reg_mask = 0x0f; }
	virtual void Reset (void);
	virtual byte MMIO_Read (int addr);
	virtual void MMIO_Write (int addr, byte val);
	virtual void DoTicks (int ticks);
	
	inline void DoITicks (int ticks);
};

void VIA6522::DoITicks (int ticks)
{
	Timer1 -= ticks;
	Timer2 -= ticks;
	if (Timer1 <= 0 || Timer2 <= 0)
		DoTimers ();
}

#endif /* VIA6522_H */

/* End of file. */
