#ifndef __EMU_MACHINE_AVR8_H__
#define __EMU_MACHINE_AVR8_H__

// Helpful enums and defines for the Atmel 8-bit AVR series of microcontrollers

namespace Avr8
{

enum
{
	REGIDX_R0 = 0,
	REGIDX_R1,
	REGIDX_R2,
	REGIDX_R3,
	REGIDX_R4,
	REGIDX_R5,
	REGIDX_R6,
	REGIDX_R7,
	REGIDX_R8,
	REGIDX_R9,
	REGIDX_R10,
	REGIDX_R11,
	REGIDX_R12,
	REGIDX_R13,
	REGIDX_R14,
	REGIDX_R15,
	REGIDX_R16,
	REGIDX_R17,
	REGIDX_R18,
	REGIDX_R19,
	REGIDX_R20,
	REGIDX_R21,
	REGIDX_R22,
	REGIDX_R23,
	REGIDX_R24,
	REGIDX_R25,
	REGIDX_R26,
	REGIDX_R27,
	REGIDX_R28,
	REGIDX_R29,
	REGIDX_R30,
	REGIDX_R31,

	REGIDX_PINB = 0x23,
	REGIDX_DDRB,
	REGIDX_PORTB,
	REGIDX_PINC,
	REGIDX_DDRC,
	REGIDX_PORTC,
	REGIDX_PIND,
	REGIDX_DDRD,
	REGIDX_PORTD,

	REGIDX_TIFR0 = 0x35,
	REGIDX_TIFR1,
	REGIDX_TIFR2,

	REGIDX_PCIFR = 0x3b,
	REGIDX_EIFR,
	REGIDX_EIMSK,
	REGIDX_GPIOR0,
	REGIDX_EECR,
	REGIDX_EEDR,
	REGIDX_EEARL,
	REGIDX_EEARH,
	REGIDX_GTCCR,
	REGIDX_TCCR0A,
	REGIDX_TCCR0B,
	REGIDX_TCNT0,
	REGIDX_OCR0A,
	REGIDX_OCR0B,

	REGIDX_GPIOR1 = 0x4a,
	REGIDX_GPIOR2,
	REGIDX_SPCR,
	REGIDX_SPSR,
	REGIDX_SPDR,

	REGIDX_ACSR = 0x50,

	REGIDX_SMCR = 0x53,
	REGIDX_MCUSR,
	REGIDX_MCUCR,

	REGIDX_SPMCSR = 0x57,

	REGIDX_SPL = 0x5d,
	REGIDX_SPH,
	REGIDX_SREG,
	REGIDX_WDTCSR,
	REGIDX_CLKPR,

	REGIDX_PRR = 0x64,

	REGIDX_OSCCAL = 0x66,

	REGIDX_PCICR = 0x68,
	REGIDX_EICRA,

	REGIDX_PCMSK0 = 0x6B,
	REGIDX_PCMSK1,
	REGIDX_PCMSK2,
	REGIDX_TIMSK0,
	REGIDX_TIMSK1,
	REGIDX_TIMSK2,

	REGIDX_ADCL = 0x78,
	REGIDX_ADCH,
	REGIDX_ADCSRA,
	REGIDX_ADCSRB,
	REGIDX_ADMUX,

	REGIDX_DIDR0 = 0x7e,
	REGIDX_DIDR1,
	REGIDX_TCCR1A,
	REGIDX_TCCR1B,
	REGIDX_TCCR1C,

	REGIDX_TCNT1L = 0x84,
	REGIDX_TCNT1H,
	REGIDX_ICR1L,
	REGIDX_ICR1H,
	REGIDX_OCR1AL,
	REGIDX_OCR1AH,
	REGIDX_OCR1BL,
	REGIDX_OCR1BH,

	REGIDX_TCCR2A = 0xb0,
	REGIDX_TCCR2B,
	REGIDX_TCNT2,
	REGIDX_OCR2A,
	REGIDX_OCR2B,

	REGIDX_ASSR = 0xb6,

	REGIDX_TWBR = 0xb8,
	REGIDX_TWSR,
	REGIDX_TWAR,
	REGIDX_TWDR,
	REGIDX_TWCR,
	REGIDX_TWAMR,

	REGIDX_UCSR0A = 0xc0,
	REGIDX_UCSR0B,
	REGIDX_UCSR0C,

	REGIDX_UBRR0L = 0xc4,
	REGIDX_UBRR0H,
	REGIDX_UDR0
};

enum
{
	WGM1_NORMAL = 0,
	WGM1_PWM_8_PC,
	WGM1_PWM_9_PC,
	WGM1_PWM_10_PC,
	WGM1_CTC_OCR,
	WGM1_FAST_PWM_8,
	WGM1_FAST_PWM_9,
	WGM1_FAST_PWM_10,
	WGM1_PWM_PFC_ICR,
	WGM1_PWM_PFC_OCR,
	WGM1_PWM_PC_ICR,
	WGM1_PWM_PC_OCR,
	WGM1_CTC_ICR,
	WGM1_RESERVED,
	WGM1_FAST_PWM_ICR,
	WGM1_FAST_PWM_OCR
};

enum
{
	WGM2_NORMAL = 0,
	WGM2_PWM_PC,
	WGM2_CTC_CMP,
	WGM2_FAST_PWM,
	WGM2_RESERVED0,
	WGM2_PWM_PC_CMP,
	WGM2_RESERVED1,
	WGM2_FAST_PWM_CMP
};

} // namespace AVR8

#define AVR8_OCR1BH				(state->m_regs[Avr8::REGIDX_OCR1BH])
#define AVR8_OCR1BL				(state->m_regs[Avr8::REGIDX_OCR1BL])
#define AVR8_OCR1AH				(state->m_regs[Avr8::REGIDX_OCR1AH])
#define AVR8_OCR1AL				(state->m_regs[Avr8::REGIDX_OCR1AL])
#define AVR8_ICR1H				(state->m_regs[Avr8::REGIDX_ICR1H])
#define AVR8_ICR1L				(state->m_regs[Avr8::REGIDX_ICR1L])
#define AVR8_TCNT1H				(state->m_regs[Avr8::REGIDX_TCNT1H])
#define AVR8_TCNT1L				(state->m_regs[Avr8::REGIDX_TCNT1L])

#define AVR8_TCCR1B					(state->m_regs[Avr8::REGIDX_TCCR1B])
#define AVR8_TCCR1B_ICNC1_MASK		0x80
#define AVR8_TCCR1B_ICNC1_SHIFT		7
#define AVR8_TCCR1B_ICES1_MASK		0x40
#define AVR8_TCCR1B_ICES1_SHIFT		6
#define AVR8_TCCR1B_WGM1_32_MASK	0x18
#define AVR8_TCCR1B_WGM1_32_SHIFT	3
#define AVR8_TCCR1B_CS_MASK			0x03
#define AVR8_TCCR1B_CS_SHIFT		0

#define AVR8_TCCR1A					(state->m_regs[Avr8::REGIDX_TCCR1A])
#define AVR8_TCCR1A_COM1A_MASK		0xc0
#define AVR8_TCCR1A_COM1A_SHIFT		6
#define AVR8_TCCR1A_COM1B_MASK		0x30
#define AVR8_TCCR1A_COM1B_SHIFT		4
#define AVR8_TCCR1A_WGM1_10_MASK	0x03
#define AVR8_TCCR1A_WGM1_10_SHIFT	0
#define AVR8_TCCR1A_COM1A			((AVR8_TCCR1A & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT)
#define AVR8_TCCR1A_COM1B			((AVR8_TCCR1A & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT)
#define AVR8_TCCR1A_WGM1_10			(AVR8_TCCR1A & AVR8_TCCR1A_WGM1_10_MASK)

#define AVR8_TIMSK1				(state->m_regs[Avr8::REGIDX_TIMSK1])
#define AVR8_TIMSK1_ICIE1_MASK	0x20
#define AVR8_TIMSK1_OCIE1B_MASK	0x04
#define AVR8_TIMSK1_OCIE1A_MASK	0x02
#define AVR8_TIMSK1_TOIE1_MASK	0x01
#define AVR8_TIMSK1_ICIE1		((AVR8_TIMSK1 & AVR8_TIMSK1_ICIE1_MASK) >> 5)
#define AVR8_TIMSK1_OCIE1B		((AVR8_TIMSK1 & AVR8_TIMSK1_OCIE1B_MASK) >> 2)
#define AVR8_TIMSK1_OCIE1A		((AVR8_TIMSK1 & AVR8_TIMSK1_OCIE1A_MASK) >> 1)
#define AVR8_TIMSK1_TOIE1		(AVR8_TIMSK1 & AVR8_TIMSK1_TOIE1_MASK)

#define AVR8_TCCR2B					(state->m_regs[Avr8::REGIDX_TCCR1B])
#define AVR8_TCCR2B_FOC2A_MASK		0x80
#define AVR8_TCCR2B_FOC2A_SHIFT		7
#define AVR8_TCCR2B_FOC2B_MASK		0x40
#define AVR8_TCCR2B_FOC2B_SHIFT		6
#define AVR8_TCCR2B_WGM2_2_MASK		0x08
#define AVR8_TCCR2B_WGM2_2_SHIFT	3
#define AVR8_TCCR2B_CS_MASK			0x03
#define AVR8_TCCR2B_CS_SHIFT		0
#define AVR8_TIMER2_CLOCK_SELECT	((AVR8_TCCR2B & AVR8_TCCR2B_CS_MASK) >> AVR8_TCCR2B_CS_SHIFT)

#define AVR8_TCCR2A					(state->m_regs[Avr8::REGIDX_TCCR1A])
#define AVR8_TCCR2A_COM2A_MASK		0xc0
#define AVR8_TCCR2A_COM2A_SHIFT		6
#define AVR8_TCCR2A_COM2B_MASK		0x30
#define AVR8_TCCR2A_COM2B_SHIFT		4
#define AVR8_TCCR2A_WGM2_10_MASK	0x03
#define AVR8_TCCR2A_WGM2_10_SHIFT	0
#define AVR8_TCCR2A_COM2A			((AVR8_TCCR2A & AVR8_TCCR2A_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT)
#define AVR8_TCCR2A_COM2B			((AVR8_TCCR2A & AVR8_TCCR2A_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT)
#define AVR8_TCCR2A_WGM2_10			(AVR8_TCCR2A & AVR8_TCCR1A_WGM2_10_MASK)

#define AVR8_SPSR				(state->m_regs[Avr8::REGIDX_SPSR])
#define AVR8_SPSR_SPIF_MASK		0x80
#define AVR8_SPSR_SPIF_SHIFT	7
#define AVR8_SPSR_SPR2X_MASK	0x01
#define AVR8_SPSR_SPR2X			(AVR8_SPSR & AVR8_SPSR_SPR2X_MASK)

#define AVR8_SPCR				(state->m_regs[Avr8::REGIDX_SPCR])
#define AVR8_SPCR_SPIE_MASK		0x80
#define AVR8_SPCR_SPE_MASK		0x40
#define AVR8_SPCR_DORD_MASK		0x20
#define AVR8_SPCR_MSTR_MASK		0x10
#define AVR8_SPCR_CPOL_MASK		0x08
#define AVR8_SPCR_CPHA_MASK		0x04
#define AVR8_SPCR_SPR_MASK		0x03
#define AVR8_SPCR_SPIE			((AVR8_SPCR & AVR8_SPCR_SPIE_MASK) >> 7)
#define AVR8_SPCR_SPE			((AVR8_SPCR & AVR8_SPCR_SPE_MASK) >> 6)
#define AVR8_SPCR_DORD			((AVR8_SPCR & AVR8_SPCR_DORD_MASK) >> 5)
#define AVR8_SPCR_MSTR			((AVR8_SPCR & AVR8_SPCR_MSTR_MASK) >> 4)
#define AVR8_SPCR_CPOL			((AVR8_SPCR & AVR8_SPCR_CPOL_MASK) >> 3)
#define AVR8_SPCR_CPHA			((AVR8_SPCR & AVR8_SPCR_CPHA_MASK) >> 2)
#define AVR8_SPCR_SPR			(AVR8_SPCR & AVR8_SPCR_SPR_MASK)

#define AVR8_TIFR1				(state->m_regs[Avr8::REGIDX_TIFR1])
#define AVR8_TIFR1_ICF1_MASK	0x20
#define AVR8_TIFR1_ICF1_SHIFT	5
#define AVR8_TIFR1_OCF1B_MASK	0x04
#define AVR8_TIFR1_OCF1B_SHIFT	2
#define AVR8_TIFR1_OCF1A_MASK	0x02
#define AVR8_TIFR1_OCF1A_SHIFT	1
#define AVR8_TIFR1_TOV1_MASK	0x01
#define AVR8_TIFR1_TOV1_SHIFT	0

#define AVR8_DDRD				(state->m_regs[Avr8::REGIDX_DDRD])
#define AVR8_DDRC				(state->m_regs[Avr8::REGIDX_DDRC])
#define AVR8_PORTB				(state->m_regs[Avr8::REGIDX_PORTB])
#define AVR8_DDRB				(state->m_regs[Avr8::REGIDX_DDRB])

#define AVR8_OCR1A				((AVR8_OCR1AH << 8) | AVR8_OCR1AL)
#define AVR8_OCR1B				((AVR8_OCR1BH << 8) | AVR8_OCR1BL)
#define AVR8_ICR1				((AVR8_ICR1H  << 8) | AVR8_ICR1L)
#define AVR8_TCNT1				((AVR8_TCNT1H << 8) | AVR8_TCNT1L)
#define AVR8_WGM1				(((AVR8_TCCR1B & 0x18) >> 1) | (AVR8_TCCR1A & 0x03))
#define AVR8_TCNT1_DIR			(state->m_tcnt1_direction)

#define AVR8_OCR2B				state->m_regs[Avr8::REGIDX_OCR2B]
#define AVR8_OCR2A				state->m_regs[Avr8::REGIDX_OCR2A]
#define AVR8_TCNT2				state->m_regs[Avr8::REGIDX_TCNT2]
#define AVR8_WGM2				(((AVR8_TCCR2B & 0x08) >> 1) | (AVR8_TCCR2A & 0x03))

#endif // __EMU_MACHINE_AVR8_H__
