summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/avr8/avr8.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/avr8/avr8.c')
-rw-r--r--src/devices/cpu/avr8/avr8.c3930
1 files changed, 3930 insertions, 0 deletions
diff --git a/src/devices/cpu/avr8/avr8.c b/src/devices/cpu/avr8/avr8.c
new file mode 100644
index 00000000000..0f15c655cb4
--- /dev/null
+++ b/src/devices/cpu/avr8/avr8.c
@@ -0,0 +1,3930 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz, Sandro Ronco, Felipe Sanches
+/***************************************************************************
+
+ Atmel 8-bit AVR simulator
+
+ - Notes -
+ Cycle counts are generally considered to be 100% accurate per-instruction, does not support mid-instruction
+ interrupts although no software has been countered yet that requires it. Evidence of cycle accuracy is given
+ in the form of the demoscene 'wild' demo, Craft, by [lft], which uses an ATmega88 to write video out a 6-bit
+ RGB DAC pixel-by-pixel, synchronously with the frame timing. Intentionally modifying the timing of any of
+ the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the
+ existing timing is 100% correct.
+
+ Unimplemented opcodes: SPM, SPM Z+, SLEEP, BREAK, WDR, EICALL, JMP, CALL
+
+ - Changelist -
+ 05 Jul. 2015 [Felipe Sanches]
+ - Implemented EIJMP instruction
+
+ 29 Dec. 2013 [Felipe Sanches]
+ - Added crude boilerplate code for Timer/Counter #4
+
+ 25 Dec. 2013 [Felipe Sanches]
+ - Updated AVR8_REGIDX_* enum based on ATMEGA640/1280/2560 datasheet
+
+ 24 Dec. 2013 [Felipe Sanches]
+ - update data memory mapping so that all 0x200 register addresses are accessible
+
+ 23 Dec. 2013 [Felipe Sanches]
+ - Added ELPM instructions
+ - Added fuse bits macros
+ - Added reset logic to decide initial program counter based on fuse bits configuration
+ - Added initial support for ATMEGA1280 and ATMEGA2560
+ - Use register names in the disassembly of IN and OUT instructions
+
+ 23 Dec. 2012 [Sandro Ronco]
+ - Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes
+ - Fixed Z flag in CPC, SBC and SBCI opcodes
+ - Fixed V and C flags in SBIW opcode
+
+ 30 Oct. 2012
+ - Added FMUL, FMULS, FMULSU opcodes [MooglyGuy]
+ - Fixed incorrect flag calculation in ROR opcode [MooglyGuy]
+ - Fixed incorrect bit testing in SBIC/SBIS opcodes [MooglyGuy]
+
+ 25 Oct. 2012
+ - Added MULS, ANDI, STI Z+, LD -Z, LD -Y, LD -X, LD Y+q, LD Z+q, SWAP, ASR, ROR and SBIS opcodes [MooglyGuy]
+ - Corrected cycle counts for LD and ST opcodes [MooglyGuy]
+ - Moved opcycles init into inner while loop, fixes 2-cycle and 3-cycle opcodes effectively forcing
+ all subsequent 1-cycle opcodes to be 2 or 3 cycles [MooglyGuy]
+ - Fixed register behavior in MULSU, LD -Z, and LD -Y opcodes [MooglyGuy]
+
+ 18 Oct. 2012
+ - Added OR, SBCI, ORI, ST Y+, ADIQ opcodes [MooglyGuy]
+ - Fixed COM, NEG, LSR opcodes [MooglyGuy]
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "avr8.h"
+
+#define VERBOSE_LEVEL (0)
+
+#define ENABLE_VERBOSE_LOG (0)
+
+#if ENABLE_VERBOSE_LOG
+INLINE void ATTR_PRINTF(3,4) verboselog(UINT16 pc, int n_level, const char *s_fmt, ...)
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ logerror( "%05x: %s", pc << 1, buf );
+ }
+}
+#else
+#define verboselog(x,y,z, ...)
+#endif
+
+//**************************************************************************
+// ENUMS AND MACROS
+//**************************************************************************
+
+enum
+{
+ AVR8_SREG_C = 0,
+ AVR8_SREG_Z,
+ AVR8_SREG_N,
+ AVR8_SREG_V,
+ AVR8_SREG_S,
+ AVR8_SREG_H,
+ AVR8_SREG_T,
+ AVR8_SREG_I
+};
+
+// I/O Enums
+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
+{
+ WGM02_NORMAL = 0,
+ WGM02_PWM_PC,
+ WGM02_CTC_CMP,
+ WGM02_FAST_PWM,
+ WGM02_RESERVED0,
+ WGM02_PWM_PC_CMP,
+ WGM02_RESERVED1,
+ WGM02_FAST_PWM_CMP
+};
+
+enum
+{
+ WGM4_NORMAL = 0,
+ WGM4_PWM_8_PC,
+ WGM4_PWM_9_PC,
+ WGM4_PWM_10_PC,
+ WGM4_CTC_OCR,
+ WGM4_FAST_PWM_8,
+ WGM4_FAST_PWM_9,
+ WGM4_FAST_PWM_10,
+ WGM4_PWM_PFC_ICR,
+ WGM4_PWM_PFC_OCR,
+ WGM4_PWM_PC_ICR,
+ WGM4_PWM_PC_OCR,
+ WGM4_CTC_ICR,
+ WGM4_RESERVED,
+ WGM4_FAST_PWM_ICR,
+ WGM4_FAST_PWM_OCR
+};
+
+enum
+{
+ WGM5_NORMAL = 0,
+ WGM5_PWM_8_PC,
+ WGM5_PWM_9_PC,
+ WGM5_PWM_10_PC,
+ WGM5_CTC_OCR,
+ WGM5_FAST_PWM_8,
+ WGM5_FAST_PWM_9,
+ WGM5_FAST_PWM_10,
+ WGM5_PWM_PFC_ICR,
+ WGM5_PWM_PFC_OCR,
+ WGM5_PWM_PC_ICR,
+ WGM5_PWM_PC_OCR,
+ WGM5_CTC_ICR,
+ WGM5_RESERVED,
+ WGM5_FAST_PWM_ICR,
+ WGM5_FAST_PWM_OCR
+};
+
+//static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' };
+
+#define SREG_R(b) ((m_r[AVR8_REGIDX_SREG] & (1 << (b))) >> (b))
+#define SREG_W(b,v) m_r[AVR8_REGIDX_SREG] = (m_r[AVR8_REGIDX_SREG] & ~(1 << (b))) | ((v) << (b))
+#define NOT(x) (1 - (x))
+
+// Opcode-Parsing Defines
+#define RD2(op) (((op) >> 4) & 0x0003)
+#define RD3(op) (((op) >> 4) & 0x0007)
+#define RD4(op) (((op) >> 4) & 0x000f)
+#define RD5(op) (((op) >> 4) & 0x001f)
+#define RR3(op) ((op) & 0x0007)
+#define RR4(op) ((op) & 0x000f)
+#define RR5(op) ((((op) >> 5) & 0x0010) | ((op) & 0x000f))
+#define DCONST(op) (((op) >> 4) & 0x0003)
+#define KCONST6(op) ((((op) >> 2) & 0x0030) | ((op) & 0x000f))
+#define KCONST7(op) (((op) >> 3) & 0x007f)
+#define KCONST8(op) ((((op) >> 4) & 0x00f0) | ((op) & 0x000f))
+#define KCONST22(op) (((((UINT32)(op) >> 3) & 0x003e) | ((UINT32)(op) & 0x0001)) << 16)
+#define QCONST6(op) ((((op) >> 8) & 0x0020) | (((op) >> 7) & 0x0018) | ((op) & 0x0007))
+#define ACONST5(op) (((op) >> 3) & 0x001f)
+#define ACONST6(op) ((((op) >> 5) & 0x0030) | ((op) & 0x000f))
+#define MULCONST2(op) ((((op) >> 6) & 0x0002) | (((op) >> 3) & 0x0001))
+
+// Register Defines
+#define XREG ((m_r[27] << 8) | m_r[26])
+#define YREG ((m_r[29] << 8) | m_r[28])
+#define ZREG ((m_r[31] << 8) | m_r[30])
+#define SPREG ((m_r[AVR8_REGIDX_SPH] << 8) | m_r[AVR8_REGIDX_SPL])
+
+// I/O Defines
+#define AVR8_OCR1CH (m_r[AVR8_REGIDX_OCR1CH])
+#define AVR8_OCR1CL (m_r[AVR8_REGIDX_OCR1CL])
+#define AVR8_OCR1BH (m_r[AVR8_REGIDX_OCR1BH])
+#define AVR8_OCR1BL (m_r[AVR8_REGIDX_OCR1BL])
+#define AVR8_OCR1AH (m_r[AVR8_REGIDX_OCR1AH])
+#define AVR8_OCR1AL (m_r[AVR8_REGIDX_OCR1AL])
+#define AVR8_ICR1H (m_r[AVR8_REGIDX_ICR1H])
+#define AVR8_ICR1L (m_r[AVR8_REGIDX_ICR1L])
+#define AVR8_TCNT1H (m_r[AVR8_REGIDX_TCNT1H])
+#define AVR8_TCNT1L (m_r[AVR8_REGIDX_TCNT1L])
+
+#define AVR8_OCR3CH (m_r[AVR8_REGIDX_OCR3CH])
+#define AVR8_OCR3CL (m_r[AVR8_REGIDX_OCR3CL])
+#define AVR8_OCR3BH (m_r[AVR8_REGIDX_OCR3BH])
+#define AVR8_OCR3BL (m_r[AVR8_REGIDX_OCR3BL])
+#define AVR8_OCR3AH (m_r[AVR8_REGIDX_OCR3AH])
+#define AVR8_OCR3AL (m_r[AVR8_REGIDX_OCR3AL])
+#define AVR8_ICR3H (m_r[AVR8_REGIDX_ICR3H])
+#define AVR8_ICR3L (m_r[AVR8_REGIDX_ICR3L])
+#define AVR8_TCNT3H (m_r[AVR8_REGIDX_TCNT3H])
+#define AVR8_TCNT3L (m_r[AVR8_REGIDX_TCNT3L])
+
+#define AVR8_OCR4CH (m_r[AVR8_REGIDX_OCR4CH])
+#define AVR8_OCR4CL (m_r[AVR8_REGIDX_OCR4CL])
+#define AVR8_OCR4BH (m_r[AVR8_REGIDX_OCR4BH])
+#define AVR8_OCR4BL (m_r[AVR8_REGIDX_OCR4BL])
+#define AVR8_OCR4AH (m_r[AVR8_REGIDX_OCR4AH])
+#define AVR8_OCR4AL (m_r[AVR8_REGIDX_OCR4AL])
+#define AVR8_ICR4H (m_r[AVR8_REGIDX_ICR4H])
+#define AVR8_ICR4L (m_r[AVR8_REGIDX_ICR4L])
+#define AVR8_TCNT4H (m_r[AVR8_REGIDX_TCNT4H])
+#define AVR8_TCNT4L (m_r[AVR8_REGIDX_TCNT4L])
+
+#define AVR8_OCR5CH (m_r[AVR8_REGIDX_OCR5CH])
+#define AVR8_OCR5CL (m_r[AVR8_REGIDX_OCR5CL])
+#define AVR8_OCR5BH (m_r[AVR8_REGIDX_OCR5BH])
+#define AVR8_OCR5BL (m_r[AVR8_REGIDX_OCR5BL])
+#define AVR8_OCR5AH (m_r[AVR8_REGIDX_OCR5AH])
+#define AVR8_OCR5AL (m_r[AVR8_REGIDX_OCR5AL])
+#define AVR8_ICR5H (m_r[AVR8_REGIDX_ICR5H])
+#define AVR8_ICR5L (m_r[AVR8_REGIDX_ICR5L])
+#define AVR8_TCNT5H (m_r[AVR8_REGIDX_TCNT5H])
+#define AVR8_TCNT5L (m_r[AVR8_REGIDX_TCNT5L])
+
+#define AVR8_TCCR0B (m_r[AVR8_REGIDX_TCCR0B])
+#define AVR8_TCCR0B_FOC0A_MASK 0x80
+#define AVR8_TCCR0B_FOC0A_SHIFT 7
+#define AVR8_TCCR0B_FOC0B_MASK 0x40
+#define AVR8_TCCR0B_FOC0B_SHIFT 6
+#define AVR8_TCCR0B_WGM0_2_MASK 0x08
+#define AVR8_TCCR0B_WGM0_2_SHIFT 3
+#define AVR8_TCCR0B_CS_MASK 0x07
+#define AVR8_TCCR0B_CS_SHIFT 0
+#define AVR8_TIMER0_CLOCK_SELECT (AVR8_TCCR0B & AVR8_TCCR0B_CS_MASK)
+
+#define AVR8_TCCR0A (m_r[AVR8_REGIDX_TCCR0A])
+#define AVR8_TCCR0A_COM0A_MASK 0xc0
+#define AVR8_TCCR0A_COM0A_SHIFT 6
+#define AVR8_TCCR0A_COM0B_MASK 0x30
+#define AVR8_TCCR0A_COM0B_SHIFT 4
+#define AVR8_TCCR0A_WGM0_10_MASK 0x03
+#define AVR8_TCCR0A_WGM0_10_SHIFT 0
+#define AVR8_TCCR0A_COM0A ((AVR8_TCCR0A & AVR8_TCCR0A_COM0A_MASK) >> AVR8_TCCR0A_COM0A_SHIFT)
+#define AVR8_TCCR0A_COM0B ((AVR8_TCCR0A & AVR8_TCCR0A_COM0B_MASK) >> AVR8_TCCR0A_COM0B_SHIFT)
+#define AVR8_TCCR0A_WGM0_10 (AVR8_TCCR0A & AVR8_TCCR0A_WGM0_10_MASK)
+
+#define AVR8_TIMSK0 (m_r[AVR8_REGIDX_TIMSK0])
+#define AVR8_TIMSK0_OCIE0B_MASK 0x04
+#define AVR8_TIMSK0_OCIE0A_MASK 0x02
+#define AVR8_TIMSK0_TOIE0_MASK 0x01
+#define AVR8_TIMSK0_OCIE0B ((AVR8_TIMSK0 & AVR8_TIMSK0_OCIE0B_MASK) >> 2)
+#define AVR8_TIMSK0_OCIE0A ((AVR8_TIMSK0 & AVR8_TIMSK0_OCIE0A_MASK) >> 1)
+#define AVR8_TIMSK0_TOIE0 (AVR8_TIMSK0 & AVR8_TIMSK0_TOIE0_MASK)
+
+#define AVR8_TIFR0 (m_r[AVR8_REGIDX_TIFR0])
+#define AVR8_TIFR0_OCF0B_MASK 0x04
+#define AVR8_TIFR0_OCF0B_SHIFT 2
+#define AVR8_TIFR0_OCF0A_MASK 0x02
+#define AVR8_TIFR0_OCF0A_SHIFT 1
+#define AVR8_TIFR0_TOV0_MASK 0x01
+#define AVR8_TIFR0_TOV0_SHIFT 0
+#define AVR8_TIFR0_MASK (AVR8_TIFR0_TOV0_MASK | AVR8_TIFR0_OCF0B_MASK | AVR8_TIFR0_OCF0A_MASK)
+
+#define AVR8_TCCR1B (m_r[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 0x07
+#define AVR8_TCCR1B_CS_SHIFT 0
+#define AVR8_TIMER1_CLOCK_SELECT (AVR8_TCCR1B & AVR8_TCCR1B_CS_MASK)
+
+#define AVR8_TCCR1A (m_r[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_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT)
+#define AVR8_TCCR1A_WGM1_10 (AVR8_TCCR1A & AVR8_TCCR1A_WGM1_10_MASK)
+
+#define AVR8_TIMSK1 (m_r[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_TIFR1 (m_r[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_TIFR1_MASK (AVR8_TIFR1_ICF1_MASK | AVR8_TIFR1_TOV1_MASK | \
+ AVR8_TIFR1_OCF1B_MASK | AVR8_TIFR1_OCF1A_MASK)
+
+#define AVR8_TCCR2B (m_r[AVR8_REGIDX_TCCR2B])
+#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 0x07
+#define AVR8_TCCR2B_CS_SHIFT 0
+#define AVR8_TIMER2_CLOCK_SELECT (AVR8_TCCR2B & AVR8_TCCR2B_CS_MASK)
+
+#define AVR8_TCCR2A (m_r[AVR8_REGIDX_TCCR2A])
+#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_COM2B_MASK) >> AVR8_TCCR2A_COM2B_SHIFT)
+#define AVR8_TCCR2A_WGM2_10 (AVR8_TCCR2A & AVR8_TCCR2A_WGM2_10_MASK)
+
+#define AVR8_TIMSK2 (m_r[AVR8_REGIDX_TIMSK2])
+#define AVR8_TIMSK2_OCIE2B_MASK 0x04
+#define AVR8_TIMSK2_OCIE2A_MASK 0x02
+#define AVR8_TIMSK2_TOIE2_MASK 0x01
+#define AVR8_TIMSK2_OCIE2B ((AVR8_TIMSK2 & AVR8_TIMSK2_OCIE2B_MASK) >> 2)
+#define AVR8_TIMSK2_OCIE2A ((AVR8_TIMSK2 & AVR8_TIMSK2_OCIE2A_MASK) >> 1)
+#define AVR8_TIMSK2_TOIE2 (AVR8_TIMSK2 & AVR8_TIMSK2_TOIE2_MASK)
+
+#define AVR8_TIFR2 (m_r[AVR8_REGIDX_TIFR2])
+#define AVR8_TIFR2_OCF2B_MASK 0x04
+#define AVR8_TIFR2_OCF2B_SHIFT 2
+#define AVR8_TIFR2_OCF2A_MASK 0x02
+#define AVR8_TIFR2_OCF2A_SHIFT 1
+#define AVR8_TIFR2_TOV2_MASK 0x01
+#define AVR8_TIFR2_TOV2_SHIFT 0
+#define AVR8_TIFR2_MASK (AVR8_TIFR2_TOV2_MASK | AVR8_TIFR2_OCF2B_MASK | AVR8_TIFR2_OCF2A_MASK)
+
+#define AVR8_TIMSK3 (m_r[AVR8_REGIDX_TIMSK3])
+#define AVR8_TIMSK3_OCIE3C_MASK 0x08
+#define AVR8_TIMSK3_OCIE3B_MASK 0x04
+#define AVR8_TIMSK3_OCIE3A_MASK 0x02
+#define AVR8_TIMSK3_TOIE3_MASK 0x01
+#define AVR8_TIMSK3_OCIE3C ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3C_MASK) >> 3)
+#define AVR8_TIMSK3_OCIE3B ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3B_MASK) >> 2)
+#define AVR8_TIMSK3_OCIE3A ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3A_MASK) >> 1)
+#define AVR8_TIMSK3_TOIE3 ((AVR8_TIMSK3 & AVR8_TIMSK3_TOIE3_MASK) >> 0)
+
+#define AVR8_TCCR4C (m_r[AVR8_REGIDX_TCCR4C])
+
+#define AVR8_TCCR4B (m_r[AVR8_REGIDX_TCCR4B])
+#define AVR8_TCCR4B_FOC4A_MASK 0x80
+#define AVR8_TCCR4B_FOC4A_SHIFT 7
+#define AVR8_TCCR4B_FOC4B_MASK 0x40
+#define AVR8_TCCR4B_FOC4B_SHIFT 6
+#define AVR8_TCCR4B_FOC4C_MASK 0x20
+#define AVR8_TCCR4B_FOC4C_SHIFT 5
+#define AVR8_TCCR4B_WGM4_32_MASK 0x18
+#define AVR8_TCCR4B_WGM4_32_SHIFT 3
+#define AVR8_TCCR4B_CS_MASK 0x07
+#define AVR8_TCCR4B_CS_SHIFT 0
+#define AVR8_TIMER4_CLOCK_SELECT ((AVR8_TCCR4B & AVR8_TCCR4B_CS_MASK) >> AVR8_TCCR4B_CS_SHIFT)
+
+#define AVR8_TCCR4A (m_r[AVR8_REGIDX_TCCR4A])
+#define AVR8_TCCR4A_COM4A_MASK 0xc0
+#define AVR8_TCCR4A_COM4A_SHIFT 6
+#define AVR8_TCCR4A_COM4B_MASK 0x30
+#define AVR8_TCCR4A_COM4B_SHIFT 4
+#define AVR8_TCCR4A_COM4C_MASK 0x0c
+#define AVR8_TCCR4A_COM4C_SHIFT 2
+#define AVR8_TCCR4A_WGM4_10_MASK 0x03
+#define AVR8_TCCR4A_WGM4_10_SHIFT 0
+#define AVR8_TCCR4A_COM4A ((AVR8_TCCR4A & AVR8_TCCR4A_COM4A_MASK) >> AVR8_TCCR4A_COM4A_SHIFT)
+#define AVR8_TCCR4A_COM4B ((AVR8_TCCR4A & AVR8_TCCR4A_COM4B_MASK) >> AVR8_TCCR4A_COM4B_SHIFT)
+#define AVR8_TCCR4A_COM4C ((AVR8_TCCR4A & AVR8_TCCR4A_COM4C_MASK) >> AVR8_TCCR4A_COM4C_SHIFT)
+#define AVR8_TCCR4A_WGM2_10 (AVR8_TCCR4A & AVR8_TCCR4A_WGM2_10_MASK)
+
+#define AVR8_WGM4_32 ((AVR8_TCCR4B & AVR8_TCCR4B_WGM4_32_MASK) >> AVR8_TCCR4B_WGM4_32_SHIFT)
+#define AVR8_WGM4_10 ((AVR8_TCCR4A & AVR8_TCCR4A_WGM4_10_MASK) >> AVR8_TCCR4A_WGM4_10_SHIFT)
+#define AVR8_WGM4 ((AVR8_WGM4_32 << 2) | AVR8_WGM4_10)
+
+#define AVR8_TIMSK4 (m_r[AVR8_REGIDX_TIMSK4])
+#define AVR8_TIMSK4_OCIE4B_MASK 0x04
+#define AVR8_TIMSK4_OCIE4A_MASK 0x02
+#define AVR8_TIMSK4_TOIE4_MASK 0x01
+#define AVR8_TIMSK4_OCIE4B ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4B_MASK) >> 2)
+#define AVR8_TIMSK4_OCIE4A ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4A_MASK) >> 1)
+#define AVR8_TIMSK4_TOIE4 (AVR8_TIMSK4 & AVR8_TIMSK4_TOIE4_MASK)
+
+#define AVR8_TIFR4 (m_r[AVR8_REGIDX_TIFR4])
+#define AVR8_TIFR4_OCF4B_MASK 0x04
+#define AVR8_TIFR4_OCF4B_SHIFT 2
+#define AVR8_TIFR4_OCF4A_MASK 0x02
+#define AVR8_TIFR4_OCF4A_SHIFT 1
+#define AVR8_TIFR4_TOV4_MASK 0x01
+#define AVR8_TIFR4_TOV4_SHIFT 0
+#define AVR8_TIFR4_MASK (AVR8_TIFR4_TOV4_MASK | AVR8_TIFR4_OCF4B_MASK | AVR8_TIFR4_OCF4A_MASK)
+
+//---------------------------------------------------------------
+#define AVR8_TCCR5C (m_r[AVR8_REGIDX_TCCR5C])
+#define AVR8_TCCR5C_FOC5A_MASK 0x80
+#define AVR8_TCCR5C_FOC5A_SHIFT 7
+#define AVR8_TCCR5C_FOC5B_MASK 0x40
+#define AVR8_TCCR5C_FOC5B_SHIFT 6
+#define AVR8_TCCR5C_FOC5C_MASK 0x20
+#define AVR8_TCCR5C_FOC5C_SHIFT 5
+
+#define AVR8_TCCR5B (m_r[AVR8_REGIDX_TCCR5B])
+#define AVR8_TCCR5B_ICNC5_MASK 0x80
+#define AVR8_TCCR5B_ICNC5_SHIFT 7
+#define AVR8_TCCR5B_ICES5_MASK 0x40
+#define AVR8_TCCR5B_ICES5_SHIFT 6
+#define AVR8_TCCR5B_WGM5_32_MASK 0x18
+#define AVR8_TCCR5B_WGM5_32_SHIFT 3
+#define AVR8_TCCR5B_CS_MASK 0x07
+#define AVR8_TCCR5B_CS_SHIFT 0
+#define AVR8_TIMER5_CLOCK_SELECT ((AVR8_TCCR5B & AVR8_TCCR5B_CS_MASK) >> AVR8_TCCR5B_CS_SHIFT)
+
+#define AVR8_TCCR5A (m_r[AVR8_REGIDX_TCCR4A])
+#define AVR8_TCCR5A_COM5A_MASK 0xc0
+#define AVR8_TCCR5A_COM5A_SHIFT 6
+#define AVR8_TCCR5A_COM5B_MASK 0x30
+#define AVR8_TCCR5A_COM5B_SHIFT 4
+#define AVR8_TCCR5A_COM5C_MASK 0x0c
+#define AVR8_TCCR5A_COM5C_SHIFT 2
+#define AVR8_TCCR5A_WGM5_10_MASK 0x03
+#define AVR8_TCCR5A_WGM5_10_SHIFT 0
+#define AVR8_TCCR5A_COM5A ((AVR8_TCCR5A & AVR8_TCCR5A_COM5A_MASK) >> AVR8_TCCR5A_COM5A_SHIFT)
+#define AVR8_TCCR5A_COM5B ((AVR8_TCCR5A & AVR8_TCCR5A_COM5B_MASK) >> AVR8_TCCR5A_COM5B_SHIFT)
+#define AVR8_TCCR5A_COM5C ((AVR8_TCCR5A & AVR8_TCCR5A_COM5C_MASK) >> AVR8_TCCR5A_COM5C_SHIFT)
+#define AVR8_TCCR5A_WGM5_10 (AVR8_TCCR5A & AVR8_TCCR5A_WGM5_10_MASK)
+
+#define AVR8_WGM5_32 ((AVR8_TCCR5B & AVR8_TCCR5B_WGM5_32_MASK) >> AVR8_TCCR5B_WGM5_32_SHIFT)
+#define AVR8_WGM5_10 ((AVR8_TCCR5A & AVR8_TCCR5A_WGM5_10_MASK) >> AVR8_TCCR5A_WGM5_10_SHIFT)
+#define AVR8_WGM5 ((AVR8_WGM5_32 << 2) | AVR8_WGM5_10)
+
+#define AVR8_TIMSK5 (m_r[AVR8_REGIDX_TIMSK5])
+#define AVR8_TIMSK5_ICIE5_MASK 0x20
+#define AVR8_TIMSK5_OCIE5C_MASK 0x08
+#define AVR8_TIMSK5_OCIE5B_MASK 0x04
+#define AVR8_TIMSK5_OCIE5A_MASK 0x02
+#define AVR8_TIMSK5_TOIE5_MASK 0x01
+
+#define AVR8_TIMSK5_ICIE5C ((AVR8_TIMSK5 & AVR8_TIMSK5_ICIE5C_MASK) >> 5)
+#define AVR8_TIMSK5_OCIE5C ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5C_MASK) >> 3)
+#define AVR8_TIMSK5_OCIE5B ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5B_MASK) >> 2)
+#define AVR8_TIMSK5_OCIE5A ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5A_MASK) >> 1)
+#define AVR8_TIMSK5_TOIE5 (AVR8_TIMSK5 & AVR8_TIMSK5_TOIE5_MASK)
+
+#define AVR8_TIFR5 (m_r[AVR8_REGIDX_TIFR5])
+#define AVR8_TIFR5_ICF5_MASK 0x20
+#define AVR8_TIFR5_ICF5_SHIFT 5
+#define AVR8_TIFR5_OCF5C_MASK 0x08
+#define AVR8_TIFR5_OCF5C_SHIFT 3
+#define AVR8_TIFR5_OCF5B_MASK 0x04
+#define AVR8_TIFR5_OCF5B_SHIFT 2
+#define AVR8_TIFR5_OCF5A_MASK 0x02
+#define AVR8_TIFR5_OCF5A_SHIFT 1
+#define AVR8_TIFR5_TOV5_MASK 0x01
+#define AVR8_TIFR5_TOV5_SHIFT 0
+#define AVR8_TIFR5_MASK (AVR8_TIFR5_ICF5_MASK | AVR8_TIFR5_OCF5C_MASK | AVR8_TIFR5_OCF5B_MASK | AVR8_TIFR5_OCF5A_MASK | AVR8_TIFR5_TOV5_MASK)
+
+
+#define AVR8_TIFR5_ICF5 ((AVR8_TIFR5 & AVR8_TIFR5_ICF5_MASK) >> AVR8_TIFR5_ICF5_SHIFT)
+#define AVR8_TIFR5_OCF5C ((AVR8_TIFR5 & AVR8_TIFR5_OCF5C_MASK) >> AVR8_TIFR5_OCF5C_SHIFT)
+#define AVR8_TIFR5_OCF5B ((AVR8_TIFR5 & AVR8_TIFR5_OCF5B_MASK) >> AVR8_TIFR5_OCF5B_SHIFT)
+#define AVR8_TIFR5_OCF5A ((AVR8_TIFR5 & AVR8_TIFR5_OCF5A_MASK) >> AVR8_TIFR5_OCF5A_SHIFT)
+#define AVR8_TIFR5_TOV5 ((AVR8_TIFR5 & AVR8_TIFR5_TOV5_MASK) >> AVR8_TIFR5_TOV5_SHIFT)
+
+//---------------------------------------------------------------
+
+#define AVR8_OCR0A m_r[AVR8_REGIDX_OCR0A]
+#define AVR8_OCR0B m_r[AVR8_REGIDX_OCR0B]
+#define AVR8_TCNT0 m_r[AVR8_REGIDX_TCNT0]
+#define AVR8_WGM0 (((AVR8_TCCR0B & 0x08) >> 1) | (AVR8_TCCR0A & 0x03))
+
+#define AVR8_OCR1A ((AVR8_OCR1AH << 8) | AVR8_OCR1AL)
+#define AVR8_OCR1B ((AVR8_OCR1BH << 8) | AVR8_OCR1BL)
+#define AVR8_OCR1C ((AVR8_OCR1CH << 8) | AVR8_OCR1CL)
+#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_OCR2A m_r[AVR8_REGIDX_OCR2A]
+#define AVR8_OCR2B m_r[AVR8_REGIDX_OCR2B]
+#define AVR8_TCNT2 m_r[AVR8_REGIDX_TCNT2]
+#define AVR8_WGM2 (((AVR8_TCCR2B & 0x08) >> 1) | (AVR8_TCCR2A & 0x03))
+
+#define AVR8_ICR3 ((AVR8_ICR3H << 8) | AVR8_ICR3L)
+#define AVR8_OCR3A ((AVR8_OCR3AH << 8) | AVR8_OCR3AL)
+
+#define AVR8_ICR4 ((AVR8_ICR4H << 8) | AVR8_ICR4L)
+#define AVR8_ICR4H (m_r[AVR8_REGIDX_ICR4H])
+#define AVR8_ICR4L (m_r[AVR8_REGIDX_ICR4L])
+#define AVR8_OCR4A ((AVR8_OCR4AH << 8) | AVR8_OCR4AL)
+#define AVR8_OCR4B m_r[AVR8_REGIDX_OCR4B]
+#define AVR8_TCNT4 m_r[AVR8_REGIDX_TCNT4]
+
+#define AVR8_ICR5 ((AVR8_ICR5H << 8) | AVR8_ICR5L)
+#define AVR8_OCR5A ((AVR8_OCR5AH << 8) | AVR8_OCR5AL)
+
+#define AVR8_GTCCR_PSRASY_MASK 0x02
+#define AVR8_GTCCR_PSRASY_SHIFT 1
+
+#define AVR8_SPSR (m_r[AVR8_REGIDX_SPSR])
+#define AVR8_SPSR_SPR2X (AVR8_SPSR & AVR8_SPSR_SPR2X_MASK)
+
+#define AVR8_SPCR (m_r[AVR8_REGIDX_SPCR])
+#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_SPI_RATE ((AVR8_SPSR_SPR2X << 2) | AVR8_SPCR_SPR)
+
+#define AVR8_PORTB_MOSI 0x08
+
+#define AVR8_EECR m_r[AVR8_REGIDX_EECR] & 0x3F; //bits 6 and 7 are reserved and will always read as zero
+#define AVR8_EECR_EEPM_MASK 0x30
+#define AVR8_EECR_EERIE_MASK 0x08
+#define AVR8_EECR_EEMPE_MASK 0x04
+#define AVR8_EECR_EEPE_MASK 0x02
+#define AVR8_EECR_EERE_MASK 0x01
+#define AVR8_EECR_EEPM ((AVR8_EECR & AVR8_EECR_EEPM_MASK) >> 4)
+#define AVR8_EECR_EERIE ((AVR8_EECR & AVR8_EECR_EERIE_MASK) >> 3)
+#define AVR8_EECR_EEMPE ((AVR8_EECR & AVR8_EECR_EEMPE_MASK) >> 2)
+#define AVR8_EECR_EEPE ((AVR8_EECR & AVR8_EECR_EEPE_MASK) >> 1)
+#define AVR8_EECR_EERE ((AVR8_EECR & AVR8_EECR_EERE_MASK) >> 0)
+
+//**************************************************************************
+// DEVICE INTERFACE
+//**************************************************************************
+
+const device_type ATMEGA88 = &device_creator<atmega88_device>;
+const device_type ATMEGA644 = &device_creator<atmega644_device>;
+const device_type ATMEGA1280 = &device_creator<atmega1280_device>;
+const device_type ATMEGA2560 = &device_creator<atmega2560_device>;
+
+//**************************************************************************
+// INTERNAL ADDRESS MAP
+//**************************************************************************
+
+static ADDRESS_MAP_START( atmega88_internal_map, AS_DATA, 8, atmega88_device )
+ AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( atmega644_internal_map, AS_DATA, 8, atmega644_device )
+ AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( atmega1280_internal_map, AS_DATA, 8, atmega1280_device )
+ AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( atmega2560_internal_map, AS_DATA, 8, atmega2560_device )
+ AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w )
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// atmega88_device - constructor
+//-------------------------------------------------
+
+atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : avr8_device(mconfig, "ATMEGA88", tag, owner, clock, ATMEGA88, 0x0fff, ADDRESS_MAP_NAME(atmega88_internal_map), CPU_TYPE_ATMEGA88, "atmega88", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// atmega644_device - constructor
+//-------------------------------------------------
+
+atmega644_device::atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : avr8_device(mconfig, "ATMEGA644", tag, owner, clock, ATMEGA644, 0xffff, ADDRESS_MAP_NAME(atmega644_internal_map), CPU_TYPE_ATMEGA644, "atmega644", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// atmega1280_device - constructor
+//-------------------------------------------------
+
+atmega1280_device::atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : avr8_device(mconfig, "ATMEGA1280", tag, owner, clock, ATMEGA1280, 0x1ffff, ADDRESS_MAP_NAME(atmega1280_internal_map), CPU_TYPE_ATMEGA1280, "atmega1280", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// atmega2560_device - constructor
+//-------------------------------------------------
+
+atmega2560_device::atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : avr8_device(mconfig, "ATMEGA2560", tag, owner, clock, ATMEGA2560, 0x1ffff, ADDRESS_MAP_NAME(atmega2560_internal_map), CPU_TYPE_ATMEGA2560, "atmega2560", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// avr8_device - constructor
+//-------------------------------------------------
+
+avr8_device::avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 addr_mask, address_map_constructor internal_map, UINT8 cpu_type, const char *shortname, const char *source)
+ : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_shifted_pc(0),
+ m_program_config("program", ENDIANNESS_LITTLE, 8, 22),
+ m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0, internal_map),
+ m_io_config("io", ENDIANNESS_LITTLE, 8, 4),
+ m_eeprom_tag(NULL),
+ m_eeprom(NULL),
+ m_cpu_type(cpu_type),
+ m_lfuses(0x62),
+ m_hfuses(0x99),
+ m_efuses(0xFF),
+ m_lock_bits(0xFF),
+ m_pc(0),
+ m_spi_active(false),
+ m_spi_prescale(0),
+ m_spi_prescale_count(0),
+ m_addr_mask(addr_mask),
+ m_interrupt_pending(false),
+ m_elapsed_cycles(0)
+{
+ // Allocate & setup
+
+ for (int t=0; t<=5; t++){
+ m_timer_top[t] = 0;
+ m_timer_increment[t] = 1;
+ m_timer_prescale[t] = 0;
+ m_timer_prescale_count[t] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// static_set_low_fuses
+//-------------------------------------------------
+
+void avr8_device::set_low_fuses(const UINT8 byte)
+{
+ m_lfuses = byte;
+}
+
+//-------------------------------------------------
+// static_set_high_fuses
+//-------------------------------------------------
+
+void avr8_device::set_high_fuses(const UINT8 byte)
+{
+ m_hfuses = byte;
+}
+
+//-------------------------------------------------
+// static_set_extended_fuses
+//-------------------------------------------------
+
+void avr8_device::set_extended_fuses(const UINT8 byte)
+{
+ m_efuses = byte;
+}
+
+//-------------------------------------------------
+// static_set_lock_bits
+//-------------------------------------------------
+
+void avr8_device::set_lock_bits(const UINT8 byte)
+{
+ m_lock_bits = byte;
+}
+
+//-------------------------------------------------
+// unimplemented_opcode - bail on unspuported
+// instruction
+//-------------------------------------------------
+
+void avr8_device::unimplemented_opcode(UINT32 op)
+{
+// debugger_break(machine());
+ fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_shifted_pc);
+}
+
+
+//-------------------------------------------------
+// is_long_opcode - returns true if opcode is 4
+// bytes long
+//-------------------------------------------------
+
+inline bool avr8_device::is_long_opcode(UINT16 op)
+{
+ if((op & 0xf000) == 0x9000)
+ {
+ if((op & 0x0f00) < 0x0400)
+ {
+ if((op & 0x000f) == 0x0000)
+ {
+ return true;
+ }
+ }
+ else if((op & 0x0f00) < 0x0600)
+ {
+ if((op & 0x000f) >= 0x000c)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//-------------------------------------------------
+// device_start - start up the device
+//-------------------------------------------------
+
+void avr8_device::device_start()
+{
+ m_pc = 0;
+
+ m_program = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ m_io = &space(AS_IO);
+
+ // register our state for the debugger
+ std::string tempstr;
+ state_add(STATE_GENPC, "GENPC", m_shifted_pc).noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_r[AVR8_REGIDX_SREG]).callimport().callexport().formatstr("%8s").noshow();
+ state_add(AVR8_SREG, "STATUS", m_r[AVR8_REGIDX_SREG]).mask(0xff);
+ state_add(AVR8_PC, "PC", m_shifted_pc).mask(m_addr_mask);
+ state_add(AVR8_SPH, "SPH", m_r[AVR8_REGIDX_SPH]).mask(0xff);
+ state_add(AVR8_SPL, "SPL", m_r[AVR8_REGIDX_SPL]).mask(0xff);
+ state_add(AVR8_R0, "R0", m_r[ 0]).mask(0xff);
+ state_add(AVR8_R1, "R1", m_r[ 1]).mask(0xff);
+ state_add(AVR8_R2, "R2", m_r[ 2]).mask(0xff);
+ state_add(AVR8_R3, "R3", m_r[ 3]).mask(0xff);
+ state_add(AVR8_R4, "R4", m_r[ 4]).mask(0xff);
+ state_add(AVR8_R5, "R5", m_r[ 5]).mask(0xff);
+ state_add(AVR8_R6, "R6", m_r[ 6]).mask(0xff);
+ state_add(AVR8_R7, "R7", m_r[ 7]).mask(0xff);
+ state_add(AVR8_R8, "R8", m_r[ 8]).mask(0xff);
+ state_add(AVR8_R9, "R9", m_r[ 9]).mask(0xff);
+ state_add(AVR8_R10, "R10", m_r[10]).mask(0xff);
+ state_add(AVR8_R11, "R11", m_r[11]).mask(0xff);
+ state_add(AVR8_R12, "R12", m_r[12]).mask(0xff);
+ state_add(AVR8_R13, "R13", m_r[13]).mask(0xff);
+ state_add(AVR8_R14, "R14", m_r[14]).mask(0xff);
+ state_add(AVR8_R15, "R15", m_r[15]).mask(0xff);
+ state_add(AVR8_R16, "R16", m_r[16]).mask(0xff);
+ state_add(AVR8_R17, "R17", m_r[17]).mask(0xff);
+ state_add(AVR8_R18, "R18", m_r[18]).mask(0xff);
+ state_add(AVR8_R19, "R19", m_r[19]).mask(0xff);
+ state_add(AVR8_R20, "R20", m_r[20]).mask(0xff);
+ state_add(AVR8_R21, "R21", m_r[21]).mask(0xff);
+ state_add(AVR8_R22, "R22", m_r[22]).mask(0xff);
+ state_add(AVR8_R23, "R23", m_r[23]).mask(0xff);
+ state_add(AVR8_R24, "R24", m_r[24]).mask(0xff);
+ state_add(AVR8_R25, "R25", m_r[25]).mask(0xff);
+ state_add(AVR8_R26, "R26", m_r[26]).mask(0xff);
+ state_add(AVR8_R27, "R27", m_r[27]).mask(0xff);
+ state_add(AVR8_R28, "R28", m_r[28]).mask(0xff);
+ state_add(AVR8_R29, "R29", m_r[29]).mask(0xff);
+ state_add(AVR8_R30, "R30", m_r[30]).mask(0xff);
+ state_add(AVR8_R31, "R31", m_r[31]).mask(0xff);
+
+ // register our state for saving
+ save_item(NAME(m_pc));
+ save_item(NAME(m_r));
+ save_item(NAME(m_timer_top[0]));
+ save_item(NAME(m_timer_increment[0]));
+ save_item(NAME(m_timer_prescale[0]));
+ save_item(NAME(m_timer_prescale_count[0]));
+ save_item(NAME(m_timer_top[1]));
+ save_item(NAME(m_timer_increment[1]));
+ save_item(NAME(m_timer_prescale[1]));
+ save_item(NAME(m_timer_prescale_count[1]));
+ save_item(NAME(m_timer_top[2]));
+ save_item(NAME(m_timer_increment[2]));
+ save_item(NAME(m_timer_prescale[2]));
+ save_item(NAME(m_timer_prescale_count[2]));
+ save_item(NAME(m_timer_top[3]));
+ save_item(NAME(m_timer_increment[3]));
+ save_item(NAME(m_timer_prescale[3]));
+ save_item(NAME(m_timer_prescale_count[3]));
+ save_item(NAME(m_timer_top[4]));
+ save_item(NAME(m_timer_increment[4]));
+ save_item(NAME(m_timer_prescale[4]));
+ save_item(NAME(m_timer_prescale_count[4]));
+ save_item(NAME(m_timer_top[5]));
+ save_item(NAME(m_timer_increment[5]));
+ save_item(NAME(m_timer_prescale[5]));
+ save_item(NAME(m_timer_prescale_count[5]));
+ save_item(NAME(m_addr_mask));
+ save_item(NAME(m_interrupt_pending));
+ save_item(NAME(m_elapsed_cycles));
+
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ m_eeprom = machine().root_device().memregion(m_eeprom_tag)->base();
+}
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void avr8_device::device_reset()
+{
+ logerror("AVR low fuse bits: 0x%02X\n", m_lfuses);
+ logerror("AVR high fuse bits: 0x%02X\n", m_hfuses);
+ logerror("AVR extended fuse bits: 0x%02X\n", m_efuses);
+ logerror("AVR lock bits: 0x%02X\n", m_lock_bits);
+
+ switch ((m_hfuses & (BOOTSZ1|BOOTSZ0)) >> 1){
+ case 0: m_boot_size = 4096; break;
+ case 1: m_boot_size = 2048; break;
+ case 2: m_boot_size = 1024; break;
+ case 3: m_boot_size = 512; break;
+ default: break;
+ }
+
+ if (m_hfuses & BOOTRST){
+ m_shifted_pc = 0x0000;
+ logerror("Booting AVR core from address 0x0000\n");
+ } else {
+ m_shifted_pc = (m_addr_mask + 1) - 2*m_boot_size;
+ logerror("AVR Boot loader section size: %d words\n", m_boot_size);
+ }
+
+ for (int i = 0; i < 0x200; i++)
+ {
+ m_r[i] = 0;
+ }
+
+ m_spi_active = false;
+ m_spi_prescale = 0;
+ m_spi_prescale_count = 0;
+
+ for (int t=0; t<=5; t++){
+ m_timer_top[t] = 0;
+ m_timer_increment[t] = 1;
+ m_timer_prescale[t] = 0;
+ m_timer_prescale_count[t] = 0;
+ }
+
+ m_ocr2_not_reached_yet = true;
+ m_interrupt_pending = false;
+ m_elapsed_cycles = 0;
+}
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the specified address space, or NULL if
+// the space doesn't exist
+//-------------------------------------------------
+
+const address_space_config *avr8_device::memory_space_config(address_spacenum spacenum) const
+{
+ if (spacenum == AS_PROGRAM)
+ {
+ return &m_program_config;
+ }
+ else if (spacenum == AS_DATA)
+ {
+ return &m_data_config;
+ }
+ else if (spacenum == AS_IO)
+ {
+ return &m_io_config;
+ }
+ return NULL;
+}
+
+
+//-------------------------------------------------
+// state_string_export - export state as a string
+// for the debugger
+//-------------------------------------------------
+
+void avr8_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "%c%c%c%c%c%c%c%c",
+ (m_r[AVR8_REGIDX_SREG] & 0x80) ? 'I' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x40) ? 'T' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x20) ? 'H' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x10) ? 'S' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x08) ? 'V' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x04) ? 'N' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x02) ? 'Z' : '-',
+ (m_r[AVR8_REGIDX_SREG] & 0x01) ? 'C' : '-');
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// disasm_min_opcode_bytes - return the length
+// of the shortest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 avr8_device::disasm_min_opcode_bytes() const
+{
+ return 2;
+}
+
+
+//-------------------------------------------------
+// disasm_max_opcode_bytes - return the length
+// of the longest instruction, in bytes
+//-------------------------------------------------
+
+UINT32 avr8_device::disasm_max_opcode_bytes() const
+{
+ return 4;
+}
+
+
+//-------------------------------------------------
+// disasm_disassemble - call the disassembly
+// helper function
+//-------------------------------------------------
+
+offs_t avr8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( avr8 );
+ return CPU_DISASSEMBLE_NAME(avr8)(this, buffer, pc, oprom, opram, options);
+}
+
+
+//**************************************************************************
+// MEMORY ACCESSORS
+//**************************************************************************
+
+inline void avr8_device::push(UINT8 val)
+{
+ UINT16 sp = SPREG;
+ m_data->write_byte(sp, val);
+ sp--;
+ m_r[AVR8_REGIDX_SPL] = sp & 0x00ff;
+ m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff;
+}
+
+inline UINT8 avr8_device::pop()
+{
+ UINT16 sp = SPREG;
+ sp++;
+ m_r[AVR8_REGIDX_SPL] = sp & 0x00ff;
+ m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff;
+ return m_data->read_byte(sp);
+}
+
+//**************************************************************************
+// IRQ HANDLING
+//**************************************************************************
+
+void avr8_device::set_irq_line(UINT16 vector, int state)
+{
+ // Horrible hack, not accurate
+ if(state)
+ {
+ if(SREG_R(AVR8_SREG_I))
+ {
+ SREG_W(AVR8_SREG_I, 0);
+ push(m_pc & 0x00ff);
+ push((m_pc >> 8) & 0x00ff);
+ m_pc = vector;
+ m_shifted_pc = vector << 1;
+ }
+ else
+ {
+ m_interrupt_pending = true;
+ }
+ }
+}
+
+class CInterruptCondition
+{
+ public:
+ UINT8 m_intindex;
+ UINT8 m_intreg;
+ UINT8 m_intmask;
+ UINT8 m_regindex;
+ UINT8 m_regmask;
+};
+
+static const CInterruptCondition s_int_conditions[AVR8_INTIDX_COUNT] =
+{
+ { AVR8_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK },
+ { AVR8_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK },
+ { AVR8_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK },
+ { AVR8_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK },
+ { AVR8_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK },
+ { AVR8_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK },
+ { AVR8_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK },
+ { AVR8_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK },
+ { AVR8_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK },
+ { AVR8_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK },
+ { AVR8_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK }
+};
+
+void avr8_device::update_interrupt(int source)
+{
+ const CInterruptCondition &condition = s_int_conditions[source];
+
+ int intstate = 0;
+ if (m_r[condition.m_intreg] & condition.m_intmask)
+ intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
+
+ set_irq_line(condition.m_intindex, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
+
+static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
+{
+ { ATMEGA644_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK },
+ { ATMEGA644_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK },
+ { ATMEGA644_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK },
+ { ATMEGA644_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK },
+ { ATMEGA644_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK },
+ { ATMEGA644_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK },
+ { ATMEGA644_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK },
+ { ATMEGA644_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK },
+ { ATMEGA644_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK },
+ { ATMEGA644_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK },
+ { ATMEGA644_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK }
+};
+
+void atmega644_device::update_interrupt(int source)
+{
+ const CInterruptCondition &condition = s_mega644_int_conditions[source];
+
+ int intstate = 0;
+ if (m_r[condition.m_intreg] & condition.m_intmask)
+ intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
+
+ set_irq_line(condition.m_intindex << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
+//TODO: review this!
+void atmega1280_device::update_interrupt(int source)
+{
+ const CInterruptCondition &condition = s_mega644_int_conditions[source];
+
+ int intstate = 0;
+ if (m_r[condition.m_intreg] & condition.m_intmask)
+ intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
+
+ set_irq_line(condition.m_intindex << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
+//TODO: review this!
+void atmega2560_device::update_interrupt(int source)
+{
+ const CInterruptCondition &condition = s_mega644_int_conditions[source];
+
+ int intstate = 0;
+ if (m_r[condition.m_intreg] & condition.m_intmask)
+ intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
+
+ set_irq_line(condition.m_intindex << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
+
+//**************************************************************************
+// REGISTER HANDLING
+//**************************************************************************
+void avr8_device::timer_tick(int cycles)
+{
+ for(int count = 0; count < cycles; count++)
+ {
+ m_elapsed_cycles++;
+
+ if (m_spi_active && m_spi_prescale > 0 && m_spi_prescale_countdown >= 0)
+ {
+ m_spi_prescale_count++;
+ if (m_spi_prescale_count >= m_spi_prescale)
+ {
+ UINT8 out_bit = (m_r[AVR8_REGIDX_SPDR] & (1 << m_spi_prescale_countdown)) >> m_spi_prescale_countdown;
+ m_spi_prescale_countdown--;
+ m_io->write_byte(AVR8_IO_PORTB, (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0));
+ m_r[AVR8_REGIDX_PORTB] = (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0);
+ m_spi_prescale_count -= m_spi_prescale;
+ }
+ }
+
+ for (int t=0; t<=5; t++){
+ if (m_timer_prescale[t] != 0)
+ {
+ m_timer_prescale_count[t]++;
+ if (m_timer_prescale_count[t] >= m_timer_prescale[t])
+ {
+ switch (t){
+ case 0: timer0_tick(); break;
+ case 1: timer1_tick(); break;
+ case 2: timer2_tick(); break;
+ case 3: timer3_tick(); break;
+ case 4: timer4_tick(); break;
+ case 5: timer5_tick(); break;
+ }
+ m_timer_prescale_count[t] -= m_timer_prescale[t];
+ }
+ }
+ }
+
+ }
+}
+
+// UINT8 ocr0[2] = { m_r[AVR8_REGIDX_OCR0A], m_r[AVR8_REGIDX_OCR0B] };
+//TODO UINT8 ocf0[2] = { (1 << AVR8_TIFR0_OCF0A_SHIFT), (1 << AVR8_TIFR4_OCF0B_SHIFT) };
+//TODO UINT8 int0[2] = { AVR8_INTIDX_OCF0A, AVR8_INTIDX_OCF0B };
+
+#define LOG_TIMER_0 0
+#define LOG_TIMER_5 0
+// Timer 0 Handling
+void avr8_device::timer0_tick()
+{
+#if LOG_TIMER_0
+ printf("AVR8_WGM0: %d\n", AVR8_WGM0);
+ printf("AVR8_TCCR0A_COM0B: %d\n", AVR8_TCCR0A_COM0B);
+#endif
+
+ UINT8 count = m_r[AVR8_REGIDX_TCNT0];
+ INT32 increment = m_timer_increment[0];
+
+ switch(AVR8_WGM0)
+ {
+ case WGM02_NORMAL:
+ //printf("WGM02_NORMAL: Unimplemented timer#0 waveform generation mode\n");
+ break;
+
+ case WGM02_PWM_PC:
+ //printf("WGM02_PWM_PC: Unimplemented timer#0 waveform generation mode\n");
+ break;
+
+ case WGM02_CTC_CMP:
+ switch(AVR8_TCCR0A_COM0B){
+ case 0: /* Normal Operation */
+ if (count == m_timer_top[0]){
+ m_timer_top[0] = 0;
+ }
+ break;
+ case 1: /* Toggle OC0B on compare match */
+ if (count == m_timer_top[0]){
+ m_timer_top[0] = 0;
+#if LOG_TIMER_0
+ printf("[0] Toggle OC0B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) ^ (1 << 5));
+ }
+ break;
+ case 2: /* Clear OC0B on compare match */
+ if (count == m_timer_top[0]){
+ m_timer_top[0] = 0;
+ //Clear OC0B
+#if LOG_TIMER_0
+ printf("[0] Clear OC0B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5));
+ }
+ break;
+ case 3: /* Set OC0B on compare match */
+ if (count == m_timer_top[0]){
+ m_timer_top[0] = 0;
+#if LOG_TIMER_0
+ printf("[0] Set OC0B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5));
+ }
+ break;
+ }
+ break;
+
+ case WGM02_FAST_PWM:
+ printf("WGM02_FAST_PWM: Unimplemented timer#0 waveform generation mode\n");
+ break;
+
+ case WGM02_PWM_PC_CMP:
+ printf("WGM02_PWM_PC_CMP: Unimplemented timer#0 waveform generation mode\n");
+ break;
+
+ case WGM02_FAST_PWM_CMP:
+ printf("WGM02_FAST_PWM_CMP: Unimplemented timer#0 waveform generation mode\n");
+ break;
+
+ default:
+ verboselog(m_pc, 0, "update_timer0_compare_mode: Unknown waveform generation mode: %02x\n", AVR8_WGM0);
+ break;
+ }
+
+ count = count & 0xff;
+
+ count += increment;
+ m_r[AVR8_REGIDX_TCNT0] = count & 0xff;
+}
+
+void avr8_device::changed_tccr0a(UINT8 data)
+{
+ UINT8 oldtccr = AVR8_TCCR0A;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR0A = data;
+
+ if(changed & AVR8_TCCR0A_WGM0_10_MASK)
+ {
+ update_timer_waveform_gen_mode(0, AVR8_WGM0);
+ }
+}
+
+void avr8_device::timer0_force_output_compare(int reg)
+{
+ // TODO
+ verboselog(m_pc, 0, "timer0_force_output_compare: TODO; should be forcing OC0%c\n", avr8_reg_name[reg]);
+}
+
+void avr8_device::changed_tccr0b(UINT8 data)
+{
+ if (VERBOSE_LEVEL) printf("changed_tccr0b: data=0x%02X\n", data);
+
+ UINT8 oldtccr = AVR8_TCCR0B;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR0B = data;
+
+ if(changed & AVR8_TCCR0B_FOC0A_MASK)
+ {
+ // TODO
+ timer0_force_output_compare(AVR8_REG_A);
+ }
+
+ if(changed & AVR8_TCCR0B_FOC0B_MASK)
+ {
+ // TODO
+ timer0_force_output_compare(AVR8_REG_B);
+ }
+
+ if(changed & AVR8_TCCR0B_WGM0_2_MASK)
+ {
+ update_timer_waveform_gen_mode(0, AVR8_WGM0);
+ }
+
+ if(changed & AVR8_TCCR0B_CS_MASK)
+ {
+ update_timer_clock_source(0, AVR8_TIMER0_CLOCK_SELECT);
+ }
+}
+
+void avr8_device::update_ocr0(UINT8 newval, UINT8 reg)
+{
+ m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR0A : AVR8_REGIDX_OCR0B] = newval;
+}
+
+// Timer 1 Handling
+
+void avr8_device::timer1_tick()
+{
+ /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */
+
+ UINT16 count = (m_r[AVR8_REGIDX_TCNT1H] << 8) | m_r[AVR8_REGIDX_TCNT1L];
+ INT32 wgm1 = ((m_r[AVR8_REGIDX_TCCR1B] & AVR8_TCCR1B_WGM1_32_MASK) >> 1) |
+ (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_WGM1_10_MASK);
+
+ // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer
+ //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT,
+ //(m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT };
+ UINT16 ocr1[2] = { (m_r[AVR8_REGIDX_OCR1AH] << 8) | m_r[AVR8_REGIDX_OCR1AL],
+ (m_r[AVR8_REGIDX_OCR1BH] << 8) | m_r[AVR8_REGIDX_OCR1BL] };
+ UINT8 ocf1[2] = { (1 << AVR8_TIFR1_OCF1A_SHIFT), (1 << AVR8_TIFR1_OCF1B_SHIFT) };
+ UINT8 int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B };
+ INT32 increment = m_timer_increment[1];
+
+ for(INT32 reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++)
+ {
+ switch(wgm1)
+ {
+ case WGM1_CTC_OCR:
+ if (count == 0xffff)
+ {
+ m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK;
+ update_interrupt(AVR8_INTIDX_TOV1);
+ count = 0;
+ increment = 0;
+ }
+
+ if (count == ocr1[reg])
+ {
+ if (reg == 0)
+ {
+ count = 0;
+ increment = 0;
+ }
+ m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg];
+ update_interrupt(int1[reg]);
+ }
+ else if (count == 0)
+ {
+ if (reg == 0)
+ {
+ m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK;
+ update_interrupt(AVR8_INTIDX_TOV1);
+ }
+
+ m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg];
+ update_interrupt(int1[reg]);
+ }
+ break;
+
+ case WGM1_FAST_PWM_OCR:
+ if(count == ocr1[reg])
+ {
+ if (reg == 0)
+ {
+ m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK;
+ update_interrupt(AVR8_INTIDX_TOV1);
+ count = 0;
+ increment = 0;
+ }
+
+ m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg];
+ update_interrupt(int1[reg]);
+ }
+ else if(count == 0)
+ {
+ if (reg == 0)
+ {
+ m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK;
+ update_interrupt(AVR8_INTIDX_TOV1);
+ }
+
+ m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg];
+ update_interrupt(int1[reg]);
+ }
+ break;
+
+ default:
+ verboselog(m_pc, 0, "update_timer1_compare_mode: Unknown waveform generation mode: %02x\n", wgm1);
+ break;
+ }
+ /*
+ switch(compare_mode[reg])
+ {
+ case 0:
+ //verboselog(m_pc, 0, "update_timer1_compare_mode: Normal port operation (OC1 disconnected)\n");
+ break;
+
+ case 1:
+ case 2:
+ // TODO
+ break;
+
+ case 3:
+ break;
+ }
+ */
+ }
+
+ count += increment;
+ m_r[AVR8_REGIDX_TCNT1H] = (count >> 8) & 0xff;
+ m_r[AVR8_REGIDX_TCNT1L] = count & 0xff;
+}
+
+void avr8_device::update_timer_waveform_gen_mode(UINT8 t, UINT8 mode)
+{
+ INT32 oc_val = -1, ic_val = -1;
+
+ switch (t){
+ case 0:
+ oc_val = AVR8_OCR0A;
+ ic_val = -1;
+ break;
+ case 1:
+ oc_val = AVR8_OCR1A;
+ ic_val = AVR8_ICR1;
+ break;
+ case 2:
+ oc_val = AVR8_OCR2A;
+ ic_val = -1;
+ break;
+ case 3:
+ oc_val = AVR8_OCR3A;
+ ic_val = AVR8_ICR3;
+ break;
+ case 4:
+ oc_val = AVR8_OCR4A;
+ ic_val = AVR8_ICR4;
+ break;
+ case 5:
+ oc_val = AVR8_OCR5A;
+ ic_val = AVR8_ICR5;
+ break;
+ }
+
+ INT32 top_values_02[8] = {0xFF, 0xFF, oc_val, 0xFF, -1, oc_val, -1, oc_val}; //table 20-8
+
+ INT32 top_values_1345[16] = {0xFFFF, 0x00FF, 0x01FF, 0x03FF,
+ oc_val, 0x00FF, 0x01FF, 0x03FF,
+ ic_val, oc_val, ic_val, oc_val,
+ ic_val, -1, ic_val, oc_val}; //table 17-2
+
+ switch(t){
+ case 0:
+ case 2:
+ m_timer_top[t] = top_values_02[mode];
+ break;
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ m_timer_top[t] = top_values_1345[mode];
+ break;
+ }
+
+ if (m_timer_top[t] == -1){
+ m_timer_top[t] = 0;
+ printf("update_timer_waveform_gen_mode: Timer #%d - Unsupported waveform generation type: %d\n", t, mode);
+ }
+}
+
+void avr8_device::changed_tccr1a(UINT8 data)
+{
+ UINT8 oldtccr = AVR8_TCCR1A;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ m_r[AVR8_REGIDX_TCCR1A] = newtccr;
+
+ if(changed & AVR8_TCCR1A_WGM1_10_MASK)
+ {
+ update_timer_waveform_gen_mode(1, AVR8_WGM1);
+ }
+}
+
+void avr8_device::update_timer1_input_noise_canceler()
+{
+ // TODO
+}
+
+void avr8_device::update_timer1_input_edge_select()
+{
+ // TODO
+ //verboselog(m_pc, 0, "update_timer1_input_edge_select: TODO; Clocking edge is %s\n", "test");
+}
+
+void avr8_device::changed_tccr1b(UINT8 data)
+{
+ if (VERBOSE_LEVEL) printf("changed_tccr1b: data=0x%02X\n", data);
+
+ UINT8 oldtccr = AVR8_TCCR1B;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ m_r[AVR8_REGIDX_TCCR1B] = newtccr;
+
+ if(changed & AVR8_TCCR1B_ICNC1_MASK)
+ {
+ // TODO
+ update_timer1_input_noise_canceler();
+ }
+
+ if(changed & AVR8_TCCR1B_ICES1_MASK)
+ {
+ // TODO
+ update_timer1_input_edge_select();
+ }
+
+ if(changed & AVR8_TCCR1B_WGM1_32_MASK)
+ {
+ update_timer_waveform_gen_mode(1, AVR8_WGM1);
+ }
+
+ if(changed & AVR8_TCCR1B_CS_MASK)
+ {
+ update_timer_clock_source(1, AVR8_TIMER1_CLOCK_SELECT);
+ }
+}
+
+void avr8_device::update_ocr1(UINT16 newval, UINT8 reg)
+{
+ UINT8 *p_reg_h = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AH] : &m_r[AVR8_REGIDX_OCR1BH];
+ UINT8 *p_reg_l = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AL] : &m_r[AVR8_REGIDX_OCR1BL];
+ *p_reg_h = (UINT8)(newval >> 8);
+ *p_reg_l = (UINT8)newval;
+
+ // Nothing needs to be done? All handled in timer callback
+}
+
+// Timer 2 Handling
+
+void avr8_device::timer2_tick()
+{
+ UINT16 count = m_r[AVR8_REGIDX_TCNT2];
+ INT32 wgm2 = ((m_r[AVR8_REGIDX_TCCR2B] & AVR8_TCCR2B_WGM2_2_MASK) >> 1) |
+ (m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_WGM2_10_MASK);
+
+ // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer
+ //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT,
+ //(m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_COM2B_MASK) >> AVR8_TCCR2A_COM2B_SHIFT };
+ UINT8 ocr2[2] = { m_r[AVR8_REGIDX_OCR2A], m_r[AVR8_REGIDX_OCR2B] };
+ UINT8 ocf2[2] = { (1 << AVR8_TIFR2_OCF2A_SHIFT), (1 << AVR8_TIFR2_OCF2B_SHIFT) };
+ INT32 increment = m_timer_increment[2];
+
+ for(INT32 reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++)
+ {
+ switch(wgm2)
+ {
+ case WGM02_FAST_PWM:
+ if (reg==0)
+ {
+ if (count >= m_r[AVR8_REGIDX_OCR2A])
+ {
+ if (count >= 0xFF)
+ {
+ //Turn on
+ m_io->write_byte(AVR8_IO_PORTD, m_io->read_byte(AVR8_IO_PORTD) | (1 << 7));
+ m_r[AVR8_REGIDX_TCNT2] = 0;
+ m_ocr2_not_reached_yet = true;
+ }
+ else
+ {
+ if (m_ocr2_not_reached_yet)
+ {
+ //Turn off
+ m_io->write_byte(AVR8_IO_PORTD, m_io->read_byte(AVR8_IO_PORTD) & ~(1 << 7));
+ m_ocr2_not_reached_yet = false;
+ }
+ }
+ }
+ }
+ break;
+
+ case WGM02_FAST_PWM_CMP:
+ if(count == ocr2[reg])
+ {
+ if (reg == 0)
+ {
+ m_r[AVR8_REGIDX_TIFR2] |= AVR8_TIFR2_TOV2_MASK;
+ count = 0;
+ increment = 0;
+ }
+
+ m_r[AVR8_REGIDX_TIFR2] |= ocf2[reg];
+ }
+ else if (count == 0)
+ {
+ if (reg == 0)
+ {
+ m_r[AVR8_REGIDX_TIFR2] &= ~AVR8_TIFR2_TOV2_MASK;
+ }
+ }
+ break;
+
+ default:
+ // TODO
+ break;
+ }
+ /*
+ switch(compare_mode[reg])
+ {
+ case 0:
+ //verboselog(m_pc, 0, "update_timer2_compare_mode: Normal port operation (OC2 disconnected)\n");
+ break;
+
+ case 1:
+ case 2:
+ // TODO
+ break;
+
+ case 3:
+ break;
+ }
+ */
+ }
+
+ m_r[AVR8_REGIDX_TCNT2] += increment;
+
+ update_interrupt(AVR8_INTIDX_OCF2A);
+ update_interrupt(AVR8_INTIDX_OCF2B);
+ update_interrupt(AVR8_INTIDX_TOV2);
+}
+
+void avr8_device::changed_tccr2a(UINT8 data)
+{
+ UINT8 oldtccr = AVR8_TCCR2A;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR2A = data;
+
+ if(changed & AVR8_TCCR2A_WGM2_10_MASK)
+ {
+ // TODO
+ update_timer_waveform_gen_mode(2, AVR8_WGM2);
+ }
+}
+
+void avr8_device::timer2_force_output_compare(int reg)
+{
+ // TODO
+ verboselog(m_pc, 0, "force_output_compare: TODO; should be forcing OC2%c\n", avr8_reg_name[reg]);
+}
+
+void avr8_device::changed_tccr2b(UINT8 data)
+{
+ if (VERBOSE_LEVEL) printf("changed_tccr2b: data=0x%02X\n", data);
+
+ UINT8 oldtccr = AVR8_TCCR2B;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR2B = data;
+
+ if(changed & AVR8_TCCR2B_FOC2A_MASK)
+ {
+ // TODO
+ timer2_force_output_compare(AVR8_REG_A);
+ }
+
+ if(changed & AVR8_TCCR2B_FOC2B_MASK)
+ {
+ // TODO
+ timer2_force_output_compare(AVR8_REG_B);
+ }
+
+ if(changed & AVR8_TCCR2B_WGM2_2_MASK)
+ {
+ update_timer_waveform_gen_mode(2, AVR8_WGM2);
+ }
+
+ if(changed & AVR8_TCCR2B_CS_MASK)
+ {
+ update_timer_clock_source(2, AVR8_TIMER2_CLOCK_SELECT);
+ }
+}
+
+void avr8_device::update_ocr2(UINT8 newval, UINT8 reg)
+{
+ m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR2A : AVR8_REGIDX_OCR2B] = newval;
+
+ // Nothing needs to be done? All handled in timer callback
+}
+
+/************************************************************************************************/
+
+// Timer 3 Handling
+void avr8_device::timer3_tick()
+{
+}
+
+/************************************************************************************************/
+
+void avr8_device::timer4_tick()
+{
+ /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */
+// printf("AVR8_WGM4: %d\n", AVR8_WGM4);
+// printf("AVR8_TCCR4A_COM4B: %d\n", AVR8_TCCR4A_COM4B);
+
+ UINT16 count = (m_r[AVR8_REGIDX_TCNT4H] << 8) | m_r[AVR8_REGIDX_TCNT4L];
+
+ // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer
+ //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT,
+ //(m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT };
+ UINT16 ocr4[2] = { (m_r[AVR8_REGIDX_OCR4AH] << 8) | m_r[AVR8_REGIDX_OCR4AL],
+ (m_r[AVR8_REGIDX_OCR4BH] << 8) | m_r[AVR8_REGIDX_OCR4BL] };
+//TODO UINT8 ocf4[2] = { (1 << AVR8_TIFR4_OCF4A_SHIFT), (1 << AVR8_TIFR4_OCF4B_SHIFT) };
+//TODO UINT8 int4[2] = { AVR8_INTIDX_OCF4A, AVR8_INTIDX_OCF4B };
+ INT32 increment = m_timer_increment[4];
+
+ switch(AVR8_WGM4)
+ {
+ case WGM4_FAST_PWM_8:
+ case WGM4_FAST_PWM_9:
+ case WGM4_FAST_PWM_10:
+ switch(AVR8_TCCR4A_COM4B){
+ case 0: /* Normal Operation */
+ break;
+ case 1: /* TODO */
+ break;
+ case 2: /* Non-inverting mode */
+ if (count == m_timer_top[4]){
+ //Clear OC0B
+ printf("[2] Clear OC0B\n");
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5));
+ } else if (count == 0){
+ //Set OC0B
+ printf("[2] Set OC0B\n");
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5));
+ }
+ break;
+ case 3: /* Inverting mode */
+ if (count == m_timer_top[4]){
+ //Set OC0B
+ printf("[3] Set OC0B\n");
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5));
+ } else if (count == 0){
+ //Clear OC0B
+ printf("[3] Clear OC0B\n");
+ m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5));
+ }
+ break;
+ }
+ break;
+
+ case WGM4_CTC_OCR:
+ //printf("[T4] tick WGM4_CTC_OCR: %d\n", count);
+ if (count == 0xffff)
+ {
+ m_r[AVR8_REGIDX_TIFR4] |= AVR8_TIFR4_TOV4_MASK;
+ update_interrupt(AVR8_INTIDX_TOV4);
+ count = 0;
+ increment = 0;
+ }
+
+ if (count == ocr4[0]) /*TODO: test for all 3 register*/
+ {}
+ else if (count == 0)
+ {}
+ break;
+
+ case WGM1_FAST_PWM_OCR:
+ if(count == ocr4[0]) /*TODO: test for all 3 register*/
+ {}
+ else if(count == 0)
+ {}
+ break;
+
+ default:
+ verboselog(m_pc, 0, "update_timer4_compare_mode: Unknown waveform generation mode: %02x\n", wgm4);
+ break;
+ }
+
+ count += increment;
+ m_r[AVR8_REGIDX_TCNT4H] = (count >> 8) & 0xff;
+ m_r[AVR8_REGIDX_TCNT4L] = count & 0xff;
+}
+
+void avr8_device::update_timer_clock_source(UINT8 t, UINT8 clock_select)
+{
+ int prescale_values[8] = {0, 1, 8, 64, 256, 1024, -1, -1};
+ m_timer_prescale[t] = prescale_values[clock_select];
+
+ if (VERBOSE_LEVEL) printf("update_timer_clock_source: t=%d cs=%d\n", t, clock_select);
+
+ if (m_timer_prescale[t] == 0xFFFF){
+ printf("[Timer #%d]: update_timer_clock_source: External trigger mode not implemented yet\n", t);
+ m_timer_prescale[t] = 0;
+ }
+
+ if (m_timer_prescale_count[t] > m_timer_prescale[t])
+ m_timer_prescale_count[t] = m_timer_prescale[t] - 1;
+}
+
+void avr8_device::changed_tccr3a(UINT8 data)
+{
+ //TODO: Implement-me
+// AVR8_TCCR3A = data;
+}
+
+void avr8_device::changed_tccr3b(UINT8 data)
+{
+ printf("IMPLEMENT-ME: changed_tccr4b: data=0x%02X\n", data);
+}
+
+void avr8_device::changed_tccr3c(UINT8 data)
+{
+// UINT8 oldtccr = AVR8_TCCR3C;
+// UINT8 newtccr = data;
+// UINT8 changed = newtccr ^ oldtccr;
+ printf("IMPLEMENT-ME: changed_tccr3c: data=0x%02X\n", data);
+
+// AVR8_TCCR3C = data;
+
+ //TODO: Implement-me
+}
+
+void avr8_device::changed_tccr4a(UINT8 data)
+{
+ UINT8 oldtccr = AVR8_TCCR4A;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR4A = data;
+
+ if(changed & AVR8_TCCR4A_WGM4_10_MASK)
+ {
+ update_timer_waveform_gen_mode(4, AVR8_WGM4);
+ }
+}
+
+void avr8_device::changed_tccr4b(UINT8 data)
+{
+ printf("changed_tccr4b: data=0x%02X\n", data);
+
+ UINT8 oldtccr = AVR8_TCCR4B;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR4B = data;
+
+ if(changed & AVR8_TCCR4B_FOC4A_MASK)
+ {
+ // TODO
+// timer4_force_output_compare(AVR8_REG_A);
+ }
+
+ if(changed & AVR8_TCCR4B_FOC4B_MASK)
+ {
+ // TODO
+// timer4_force_output_compare(AVR8_REG_B);
+ }
+
+ if(changed & AVR8_TCCR4B_WGM4_32_MASK)
+ {
+ update_timer_waveform_gen_mode(4, AVR8_WGM4);
+ }
+
+ if(changed & AVR8_TCCR4B_CS_MASK)
+ {
+ update_timer_clock_source(4, AVR8_TIMER4_CLOCK_SELECT);
+ }
+}
+
+void avr8_device::changed_tccr4c(UINT8 data)
+{
+// UINT8 oldtccr = AVR8_TCCR4C;
+// UINT8 newtccr = data;
+// UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR4C = data;
+
+ //TODO: Implement-me
+}
+
+/************************************************************************************************/
+
+// Timer 5 Handling
+void avr8_device::timer5_tick()
+{
+#if LOG_TIMER_5
+ printf("AVR8_WGM5: %d\n", AVR8_WGM5);
+ printf("AVR8_TCCR5A_COM5B: %d\n", AVR8_TCCR5A_COM5B);
+#endif
+
+ UINT16 count = (AVR8_TCNT5H << 8) + AVR8_TCNT5L;
+ INT32 increment = m_timer_increment[5];
+
+ switch(AVR8_WGM5)
+ {
+ case WGM5_NORMAL:
+ case WGM5_PWM_8_PC:
+ case WGM5_PWM_9_PC:
+ case WGM5_PWM_10_PC:
+// case WGM5_CTC_OCR:
+ case WGM5_FAST_PWM_8:
+ case WGM5_FAST_PWM_9:
+ case WGM5_FAST_PWM_10:
+ case WGM5_PWM_PFC_ICR:
+ case WGM5_PWM_PFC_OCR:
+ case WGM5_PWM_PC_ICR:
+ case WGM5_PWM_PC_OCR:
+ case WGM5_CTC_ICR:
+ case WGM5_FAST_PWM_ICR:
+ case WGM5_FAST_PWM_OCR:
+#if LOG_TIMER_5
+ printf("Unimplemented timer#5 waveform generation mode: AVR8_WGM5 = 0x%02X\n", AVR8_WGM5);
+#endif
+ break;
+
+ case WGM5_CTC_OCR:
+ //TODO: verify this! Can be very wrong!!!
+ switch(AVR8_TCCR5A_COM5B){
+ case 0: /* Normal Operation */
+ if (count == m_timer_top[5]){
+ m_timer_top[5] = 0;
+ }
+ break;
+ case 1: /* Toggle OC5B on compare match */
+ if (count == m_timer_top[5]){
+ m_timer_top[5] = 0;
+#if LOG_TIMER_5
+ printf("[5] Toggle OC5B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) ^ (1 << 4));
+ }
+ break;
+ case 2: /* Clear OC5B on compare match */
+ if (count == m_timer_top[5]){
+ m_timer_top[5] = 0;
+ //Clear OC5B
+#if LOG_TIMER_5
+ printf("[5] Clear OC5B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) & ~(1 << 4));
+ }
+ break;
+ case 3: /* Set OC5B on compare match */
+ if (count == m_timer_top[5]){
+ m_timer_top[5] = 0;
+#if LOG_TIMER_5
+ printf("[5] Set OC5B\n");
+#endif
+ m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) | (1 << 4));
+ }
+ break;
+ }
+ break;
+
+ default:
+ printf("Timer #5: Unknown waveform generation mode: %02x\n", AVR8_WGM5);
+ break;
+ }
+
+ count += increment;
+ m_r[AVR8_REGIDX_TCNT5H] = (count >> 8) & 0xff;
+ m_r[AVR8_REGIDX_TCNT5L] = count & 0xff;
+}
+
+void avr8_device::changed_tccr5a(UINT8 data)
+{
+ UINT8 oldtccr = AVR8_TCCR5A;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR5A = data;
+
+ if(changed & AVR8_TCCR5A_WGM5_10_MASK)
+ {
+ update_timer_waveform_gen_mode(5, AVR8_WGM5);
+ }
+}
+
+void avr8_device::changed_tccr5b(UINT8 data)
+{
+ printf("changed_tccr5b: data=0x%02X\n", data);
+
+ UINT8 oldtccr = AVR8_TCCR5B;
+ UINT8 newtccr = data;
+ UINT8 changed = newtccr ^ oldtccr;
+
+ AVR8_TCCR5B = data;
+
+ if(changed & AVR8_TCCR5C_FOC5A_MASK)
+ {
+ // TODO
+// timer5_force_output_compare(AVR8_REG_A);
+ }
+
+ if(changed & AVR8_TCCR5C_FOC5B_MASK)
+ {
+ // TODO
+// timer5_force_output_compare(AVR8_REG_B);
+ }
+
+ if(changed & AVR8_TCCR5C_FOC5C_MASK)
+ {
+ // TODO
+// timer5_force_output_compare(AVR8_REG_C);
+ }
+
+ if(changed & AVR8_TCCR5B_WGM5_32_MASK)
+ {
+ update_timer_waveform_gen_mode(5, AVR8_WGM5);
+ }
+
+ if(changed & AVR8_TCCR5B_CS_MASK)
+ {
+ update_timer_clock_source(5, AVR8_TIMER5_CLOCK_SELECT);
+ }
+}
+
+/************************************************************************************************/
+
+
+/****************/
+/* SPI Handling */
+/****************/
+
+void avr8_device::enable_spi()
+{
+ // TODO
+}
+
+void avr8_device::disable_spi()
+{
+ // TODO
+}
+
+void avr8_device::spi_update_masterslave_select()
+{
+ // TODO
+}
+
+void avr8_device::spi_update_clock_polarity()
+{
+ // TODO
+}
+
+void avr8_device::spi_update_clock_phase()
+{
+ // TODO
+}
+
+const UINT8 avr8_device::spi_clock_divisor[8] = { 4, 16, 64, 128, 2, 8, 32, 64 };
+
+void avr8_device::spi_update_clock_rate()
+{
+ m_spi_prescale = spi_clock_divisor[AVR8_SPI_RATE];
+ m_spi_prescale_count &= m_spi_prescale - 1;
+}
+
+void avr8_device::change_spcr(UINT8 data)
+{
+ UINT8 oldspcr = AVR8_SPCR;
+ UINT8 newspcr = data;
+ UINT8 changed = newspcr ^ oldspcr;
+ UINT8 high_to_low = ~newspcr & oldspcr;
+ UINT8 low_to_high = newspcr & ~oldspcr;
+
+ AVR8_SPCR = data;
+
+ if(changed & AVR8_SPCR_SPIE_MASK)
+ {
+ // Check for SPI interrupt condition
+ update_interrupt(AVR8_INTIDX_SPI);
+ }
+
+ if(low_to_high & AVR8_SPCR_SPE_MASK)
+ {
+ enable_spi();
+ }
+ else if(high_to_low & AVR8_SPCR_SPE_MASK)
+ {
+ disable_spi();
+ }
+
+ if(changed & AVR8_SPCR_MSTR_MASK)
+ {
+ spi_update_masterslave_select();
+ }
+
+ if(changed & AVR8_SPCR_CPOL_MASK)
+ {
+ spi_update_clock_polarity();
+ }
+
+ if(changed & AVR8_SPCR_CPHA_MASK)
+ {
+ spi_update_clock_phase();
+ }
+
+ if(changed & AVR8_SPCR_SPR_MASK)
+ {
+ spi_update_clock_rate();
+ }
+}
+
+void avr8_device::change_spsr(UINT8 data)
+{
+ UINT8 oldspsr = AVR8_SPSR;
+ UINT8 newspsr = data;
+ UINT8 changed = newspsr ^ oldspsr;
+
+ AVR8_SPSR &= ~1;
+ AVR8_SPSR |= data & 1;
+
+ if(changed & AVR8_SPSR_SPR2X_MASK)
+ {
+ spi_update_clock_rate();
+ }
+}
+
+/*****************************************************************************/
+
+WRITE8_MEMBER( avr8_device::regs_w )
+{
+ //printf("<<< WRITE offset [%04x]=%02x >>>\n", offset, data);
+
+ switch( offset )
+ {
+ case AVR8_REGIDX_R0:
+ case AVR8_REGIDX_R1:
+ case AVR8_REGIDX_R2:
+ case AVR8_REGIDX_R3:
+ case AVR8_REGIDX_R4:
+ case AVR8_REGIDX_R5:
+ case AVR8_REGIDX_R6:
+ case AVR8_REGIDX_R7:
+ case AVR8_REGIDX_R8:
+ case AVR8_REGIDX_R9:
+ case AVR8_REGIDX_R10:
+ case AVR8_REGIDX_R11:
+ case AVR8_REGIDX_R12:
+ case AVR8_REGIDX_R13:
+ case AVR8_REGIDX_R14:
+ case AVR8_REGIDX_R15:
+ case AVR8_REGIDX_R16:
+ case AVR8_REGIDX_R17:
+ case AVR8_REGIDX_R18:
+ case AVR8_REGIDX_R19:
+ case AVR8_REGIDX_R20:
+ case AVR8_REGIDX_R21:
+ case AVR8_REGIDX_R22:
+ case AVR8_REGIDX_R23:
+ case AVR8_REGIDX_R24:
+ case AVR8_REGIDX_R25:
+ case AVR8_REGIDX_R26:
+ case AVR8_REGIDX_R27:
+ case AVR8_REGIDX_R28:
+ case AVR8_REGIDX_R29:
+ case AVR8_REGIDX_R30:
+ case AVR8_REGIDX_R31:
+ m_r[offset] = data;
+ break;
+
+ case AVR8_REGIDX_PORTA:
+ m_io->write_byte(AVR8_IO_PORTA, data);
+ m_r[AVR8_REGIDX_PORTA] = data;
+ break;
+
+ case AVR8_REGIDX_PORTB:
+ m_io->write_byte(AVR8_IO_PORTB, data);
+ m_r[AVR8_REGIDX_PORTB] = data;
+ break;
+
+ case AVR8_REGIDX_PORTC:
+ m_io->write_byte(AVR8_IO_PORTC, data);
+ m_r[AVR8_REGIDX_PORTC] = data;
+ break;
+
+ case AVR8_REGIDX_PORTD:
+ m_io->write_byte(AVR8_IO_PORTD, data);
+ m_r[AVR8_REGIDX_PORTD] = data;
+ break;
+
+ case AVR8_REGIDX_PORTE:
+ m_io->write_byte(AVR8_IO_PORTE, data);
+ m_r[AVR8_REGIDX_PORTE] = data;
+ break;
+
+ case AVR8_REGIDX_PORTF:
+ m_io->write_byte(AVR8_IO_PORTF, data);
+ m_r[AVR8_REGIDX_PORTF] = data;
+ break;
+
+ case AVR8_REGIDX_PORTG:
+ m_io->write_byte(AVR8_IO_PORTG, data);
+ m_r[AVR8_REGIDX_PORTG] = data;
+ break;
+
+ case AVR8_REGIDX_PORTH:
+ m_io->write_byte(AVR8_IO_PORTH, data);
+ m_r[AVR8_REGIDX_PORTH] = data;
+ break;
+
+ case AVR8_REGIDX_PORTJ:
+ m_io->write_byte(AVR8_IO_PORTJ, data);
+ m_r[AVR8_REGIDX_PORTJ] = data;
+ break;
+
+ case AVR8_REGIDX_PORTK:
+ m_io->write_byte(AVR8_IO_PORTK, data);
+ m_r[AVR8_REGIDX_PORTK] = data;
+ break;
+
+ case AVR8_REGIDX_PORTL:
+ m_io->write_byte(AVR8_IO_PORTL, data);
+ m_r[AVR8_REGIDX_PORTL] = data;
+ break;
+
+ case AVR8_REGIDX_DDRA:
+ case AVR8_REGIDX_DDRB:
+ case AVR8_REGIDX_DDRC:
+ case AVR8_REGIDX_DDRD:
+ case AVR8_REGIDX_SREG:
+ case AVR8_REGIDX_RAMPZ:
+ case AVR8_REGIDX_SPH:
+ case AVR8_REGIDX_SPL:
+ m_r[offset] = data;
+ break;
+
+ case AVR8_REGIDX_TCCR0B:
+ verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data );
+ changed_tccr0b(data);
+ break;
+
+ case AVR8_REGIDX_TCCR0A:
+ verboselog(m_pc, 0, "AVR8: TCCR0A = %02x\n", data );
+ changed_tccr0a(data);
+ break;
+
+ case AVR8_REGIDX_OCR0A:
+ verboselog(m_pc, 0, "AVR8: OCR0A = %02x\n", data);
+ update_ocr0(AVR8_OCR0A, AVR8_REG_A);
+ break;
+
+ case AVR8_REGIDX_OCR0B:
+ verboselog(m_pc, 0, "AVR8: OCR0B = %02x\n", data );
+ update_ocr0(AVR8_OCR0B, AVR8_REG_B);
+ break;
+
+ case AVR8_REGIDX_TIFR0:
+ verboselog(m_pc, 0, "AVR8: TIFR0 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIFR0] &= ~(data & AVR8_TIFR0_MASK);
+ update_interrupt(AVR8_INTIDX_OCF0A);
+ update_interrupt(AVR8_INTIDX_OCF0B);
+ update_interrupt(AVR8_INTIDX_TOV0);
+ break;
+
+ case AVR8_REGIDX_TCNT0:
+ AVR8_TCNT0 = data;
+ break;
+
+ case AVR8_REGIDX_TIFR1:
+ verboselog(m_pc, 0, "AVR8: TIFR1 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIFR1] &= ~(data & AVR8_TIFR1_MASK);
+ update_interrupt(AVR8_INTIDX_ICF1);
+ update_interrupt(AVR8_INTIDX_OCF1A);
+ update_interrupt(AVR8_INTIDX_OCF1B);
+ update_interrupt(AVR8_INTIDX_TOV1);
+ break;
+
+ case AVR8_REGIDX_TIFR2:
+ verboselog(m_pc, 0, "AVR8: TIFR2 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIFR2] &= ~(data & AVR8_TIFR2_MASK);
+ update_interrupt(AVR8_INTIDX_OCF2A);
+ update_interrupt(AVR8_INTIDX_OCF2B);
+ update_interrupt(AVR8_INTIDX_TOV2);
+ break;
+
+ case AVR8_REGIDX_GTCCR:
+ if (data & AVR8_GTCCR_PSRASY_MASK)
+ {
+ data &= ~AVR8_GTCCR_PSRASY_MASK;
+ m_timer_prescale_count[2] = 0;
+ }
+ break;
+
+// EEPROM registers:
+ case AVR8_REGIDX_EEARL:
+ case AVR8_REGIDX_EEARH:
+ case AVR8_REGIDX_EEDR:
+ m_r[offset] = data;
+ break;
+
+ case AVR8_REGIDX_EECR:
+ m_r[offset] = data;
+
+ if (data & AVR8_EECR_EERE_MASK)
+ {
+ UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8;
+ addr |= m_r[AVR8_REGIDX_EEARL];
+ m_r[AVR8_REGIDX_EEDR] = m_eeprom[addr];
+ if (VERBOSE_LEVEL) printf("EEPROM read @ 0x%04x data = 0x%02x\n", addr, m_eeprom[addr]);
+ }
+ if ((data & AVR8_EECR_EEPE_MASK) && (data & AVR8_EECR_EEMPE_MASK))
+ {
+ UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8;
+ addr |= m_r[AVR8_REGIDX_EEARL];
+ m_eeprom[addr] = m_r[AVR8_REGIDX_EEDR];
+ if (VERBOSE_LEVEL) printf("EEPROM write @ 0x%04x data = 0x%02x ('%c')\n", addr, m_eeprom[addr], m_eeprom[addr]);
+
+ m_r[offset] = data & ~AVR8_EECR_EEPE_MASK; //indicates that we've finished writing a value to the EEPROM.
+ //TODO: shouldn't this happen only after a certain dalay?
+ }
+ break;
+
+ case AVR8_REGIDX_GPIOR0:
+ verboselog(m_pc, 1, "AVR8: GPIOR0 Write: %02x\n", data);
+ m_r[AVR8_REGIDX_GPIOR0] = data;
+ break;
+
+ case AVR8_REGIDX_GPIOR1:
+ case AVR8_REGIDX_GPIOR2:
+ m_r[offset] = data;
+ break;
+
+ case AVR8_REGIDX_SPSR:
+ change_spsr(data);
+ break;
+
+ case AVR8_REGIDX_SPCR:
+ change_spcr(data);
+ break;
+
+ case AVR8_REGIDX_SPDR:
+ {
+ m_r[AVR8_REGIDX_SPDR] = data;
+ m_spi_active = true;
+ m_spi_prescale_countdown = 7;
+ m_spi_prescale_count = 0;
+ break;
+ }
+
+ case AVR8_REGIDX_WDTCSR:
+ verboselog(m_pc, 0, "AVR8: WDTCSR = %02x\n", data );
+ //TODO: changed_wdtcsr(data);
+ break;
+
+ case AVR8_REGIDX_CLKPR:
+ verboselog(m_pc, 0, "AVR8: CLKPR = %02x\n", data );
+ //TODO: changed_clkpr(data);
+ break;
+
+ case AVR8_REGIDX_PRR0:
+ verboselog(m_pc, 0, "AVR8: PRR0 = %02x\n", data );
+ //TODO: changed_prr0(data);
+ break;
+
+ case AVR8_REGIDX_PRR1:
+ verboselog(m_pc, 0, "AVR8: PRR1 = %02x\n", data );
+ //TODO: changed_prr1(data);
+ break;
+
+ case AVR8_REGIDX_OSCCAL:
+ verboselog(m_pc, 0, "AVR8: OSCCAL = %02x\n", data );
+ //TODO: changed_osccal(data);
+ break;
+
+ case AVR8_REGIDX_PCICR:
+ verboselog(m_pc, 0, "AVR8: PCICR = %02x\n", data );
+ //TODO: changed_pcicr(data);
+ break;
+
+ case AVR8_REGIDX_EICRA:
+ verboselog(m_pc, 0, "AVR8: EICRA = %02x\n", data );
+ //TODO: changed_eicra(data);
+ break;
+
+ case AVR8_REGIDX_EICRB:
+ verboselog(m_pc, 0, "AVR8: EICRB = %02x\n", data );
+ //TODO: changed_eicrb(data);
+ break;
+
+ case AVR8_REGIDX_PCMSK0:
+ verboselog(m_pc, 0, "AVR8: PCMSK0 = %02x\n", data );
+ //TODO: changed_pcmsk0(data);
+ break;
+
+ case AVR8_REGIDX_PCMSK1:
+ verboselog(m_pc, 0, "AVR8: PCMSK1 = %02x\n", data );
+ //TODO: changed_pcmsk1(data);
+ break;
+
+ case AVR8_REGIDX_PCMSK2:
+ verboselog(m_pc, 0, "AVR8: PCMSK2 = %02x\n", data );
+ //TODO: changed_pcmsk2(data);
+ break;
+
+ case AVR8_REGIDX_TIMSK0:
+ verboselog(m_pc, 0, "AVR8: TIMSK0 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK0] = data;
+ update_interrupt(AVR8_INTIDX_OCF0A);
+ update_interrupt(AVR8_INTIDX_OCF0B);
+ update_interrupt(AVR8_INTIDX_TOV0);
+ break;
+
+ case AVR8_REGIDX_TIMSK1:
+ verboselog(m_pc, 0, "AVR8: TIMSK1 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK1] = data;
+ update_interrupt(AVR8_INTIDX_ICF1);
+ update_interrupt(AVR8_INTIDX_OCF1A);
+ update_interrupt(AVR8_INTIDX_OCF1B);
+ update_interrupt(AVR8_INTIDX_TOV1);
+ break;
+
+ case AVR8_REGIDX_TIMSK2:
+ verboselog(m_pc, 0, "AVR8: TIMSK2 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK2] = data;
+ update_interrupt(AVR8_INTIDX_OCF2A);
+ update_interrupt(AVR8_INTIDX_OCF2B);
+ update_interrupt(AVR8_INTIDX_TOV2);
+ break;
+
+ case AVR8_REGIDX_TIMSK3:
+ verboselog(m_pc, 0, "AVR8: TIMSK3 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK3] = data;
+ update_interrupt(AVR8_INTIDX_OCF3A);
+ update_interrupt(AVR8_INTIDX_OCF3B);
+ update_interrupt(AVR8_INTIDX_TOV3);
+ break;
+
+ case AVR8_REGIDX_TIMSK4:
+ verboselog(m_pc, 0, "AVR8: TIMSK4 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK4] = data;
+ update_interrupt(AVR8_INTIDX_OCF4A);
+ update_interrupt(AVR8_INTIDX_OCF4B);
+ update_interrupt(AVR8_INTIDX_TOV4);
+ break;
+
+ case AVR8_REGIDX_TIMSK5:
+ verboselog(m_pc, 0, "AVR8: TIMSK5 = %02x\n", data );
+ m_r[AVR8_REGIDX_TIMSK5] = data;
+ update_interrupt(AVR8_INTIDX_OCF5A);
+ update_interrupt(AVR8_INTIDX_OCF5B);
+ update_interrupt(AVR8_INTIDX_TOV5);
+ break;
+
+ case AVR8_REGIDX_XMCRA:
+ verboselog(m_pc, 0, "AVR8: XMCRA = %02x\n", data );
+ //TODO: changed_xmcra(data);
+ break;
+
+ case AVR8_REGIDX_XMCRB:
+ verboselog(m_pc, 0, "AVR8: XMCRB = %02x\n", data );
+ //TODO: changed_xmcrb(data);
+ break;
+
+ case AVR8_REGIDX_ADCL:
+ verboselog(m_pc, 0, "AVR8: ADCL = %02x\n", data );
+ //TODO: changed_adcl(data);
+ break;
+
+ case AVR8_REGIDX_ADCH:
+ verboselog(m_pc, 0, "AVR8: ADCH = %02x\n", data );
+ //TODO: changed_adch(data);
+ break;
+
+ case AVR8_REGIDX_ADCSRA:
+ verboselog(m_pc, 0, "AVR8: ADCSRA = %02x\n", data );
+ //TODO: changed_adcsra(data);
+ break;
+
+ case AVR8_REGIDX_ADCSRB:
+ verboselog(m_pc, 0, "AVR8: ADCSRB = %02x\n", data );
+ //TODO: changed_adcsrb(data);
+ break;
+
+ case AVR8_REGIDX_ADMUX:
+ verboselog(m_pc, 0, "AVR8: ADMUX = %02x\n", data );
+ //TODO: changed_admux(data);
+ break;
+
+ case AVR8_REGIDX_DIDR0:
+ verboselog(m_pc, 0, "AVR8: DIDR0 = %02x\n", data );
+ //TODO: changed_didr0(data);
+ break;
+
+ case AVR8_REGIDX_DIDR1:
+ verboselog(m_pc, 0, "AVR8: DIDR1 = %02x\n", data );
+ //TODO: changed_didr1(data);
+ break;
+
+ case AVR8_REGIDX_DIDR2:
+ verboselog(m_pc, 0, "AVR8: DIDR2 = %02x\n", data );
+ //TODO: changed_didr2(data);
+ break;
+
+ case AVR8_REGIDX_TCCR1A:
+ verboselog(m_pc, 0, "AVR8: TCCR1A = %02x\n", data );
+ changed_tccr1a(data);
+ break;
+
+ case AVR8_REGIDX_TCCR1B:
+ verboselog(m_pc, 0, "AVR8: TCCR1B = %02x\n", data );
+ changed_tccr1b(data);
+ break;
+
+ case AVR8_REGIDX_TCCR1C:
+ verboselog(m_pc, 0, "AVR8: TCCR1C = %02x\n", data );
+ //TODO: changed_tccr1c(data);
+ break;
+
+ case AVR8_REGIDX_TCNT1L:
+ AVR8_TCNT1L = data;
+ break;
+
+ case AVR8_REGIDX_TCNT1H:
+ AVR8_TCNT1H = data;
+ break;
+
+ case AVR8_REGIDX_ICR1L:
+ AVR8_ICR1L = data;
+ break;
+
+ case AVR8_REGIDX_ICR1H:
+ AVR8_ICR1H = data;
+ break;
+
+ case AVR8_REGIDX_OCR1AL:
+ verboselog(m_pc, 0, "AVR8: OCR1AL = %02x\n", data );
+ update_ocr1((AVR8_OCR1A & 0xff00) | data, AVR8_REG_A);
+ break;
+
+ case AVR8_REGIDX_OCR1AH:
+ verboselog(m_pc, 0, "AVR8: OCR1AH = %02x\n", data );
+ update_ocr1((AVR8_OCR1A & 0x00ff) | (data << 8), AVR8_REG_A);
+ break;
+
+ case AVR8_REGIDX_OCR1BL:
+ verboselog(m_pc, 0, "AVR8: OCR1BL = %02x\n", data );
+ update_ocr1((AVR8_OCR1B & 0xff00) | data, AVR8_REG_B);
+ break;
+
+ case AVR8_REGIDX_OCR1BH:
+ verboselog(m_pc, 0, "AVR8: OCR1BH = %02x\n", data );
+ update_ocr1((AVR8_OCR1B & 0x00ff) | (data << 8), AVR8_REG_B);
+ break;
+
+ case AVR8_REGIDX_OCR1CL:
+ verboselog(m_pc, 0, "AVR8: OCR1CL = %02x\n", data );
+ update_ocr1((AVR8_OCR1C & 0xff00) | data, AVR8_REG_C);
+ break;
+
+ case AVR8_REGIDX_OCR1CH:
+ verboselog(m_pc, 0, "AVR8: OCR1CH = %02x\n", data );
+ update_ocr1((AVR8_OCR1C & 0x00ff) | (data << 8), AVR8_REG_C);
+ break;
+
+ case AVR8_REGIDX_TCCR2A:
+ verboselog(m_pc, 0, "AVR8: TCCR2A = %02x\n", data );
+ changed_tccr2a(data);
+ break;
+
+ case AVR8_REGIDX_TCCR2B:
+ verboselog(m_pc, 0, "AVR8: TCCR2B = %02x\n", data );
+ changed_tccr2b(data);
+ break;
+
+ case AVR8_REGIDX_TCNT2:
+ AVR8_TCNT2 = data;
+ break;
+
+ case AVR8_REGIDX_OCR2A:
+ update_ocr2(data, AVR8_REG_A);
+ break;
+
+ case AVR8_REGIDX_OCR2B:
+ update_ocr2(data, AVR8_REG_B);
+ break;
+
+ case AVR8_REGIDX_TCCR3A:
+ verboselog(m_pc, 0, "AVR8: TCCR3A = %02x\n", data );
+ changed_tccr3a(data);
+ break;
+
+ case AVR8_REGIDX_TCCR3B:
+ verboselog(m_pc, 0, "AVR8: TCCR3B = %02x\n", data );
+ changed_tccr3b(data);
+ break;
+
+ case AVR8_REGIDX_TCCR3C:
+ verboselog(m_pc, 0, "AVR8: TCCR3C = %02x\n", data );
+ changed_tccr3c(data);
+ break;
+
+ case AVR8_REGIDX_TCNT3L:
+ AVR8_TCNT3L = data;
+ break;
+
+ case AVR8_REGIDX_TCNT3H:
+ AVR8_TCNT3H = data;
+ break;
+
+ case AVR8_REGIDX_ICR3L:
+ AVR8_ICR3L = data;
+ break;
+
+ case AVR8_REGIDX_ICR3H:
+ AVR8_ICR3H = data;
+ break;
+
+ case AVR8_REGIDX_OCR3AL:
+ AVR8_OCR3AL = data;
+ break;
+
+ case AVR8_REGIDX_OCR3AH:
+ AVR8_OCR3AH = data;
+ break;
+
+ case AVR8_REGIDX_OCR3BL:
+ AVR8_OCR3BL = data;
+ break;
+
+ case AVR8_REGIDX_OCR3BH:
+ AVR8_OCR3BH = data;
+ break;
+
+ case AVR8_REGIDX_OCR3CL:
+ AVR8_OCR3CL = data;
+ break;
+
+ case AVR8_REGIDX_OCR3CH:
+ AVR8_OCR3CH = data;
+ break;
+
+ case AVR8_REGIDX_TCCR4A:
+ verboselog(m_pc, 0, "AVR8: TCCR4A = %02x\n", data );
+ changed_tccr4a(data);
+ break;
+
+ case AVR8_REGIDX_TCCR4B:
+ verboselog(m_pc, 0, "AVR8: TCCR4B = %02x\n", data );
+ changed_tccr4b(data);
+ break;
+
+ case AVR8_REGIDX_TCCR4C:
+ verboselog(m_pc, 0, "AVR8: TCCR4C = %02x\n", data );
+ changed_tccr4c(data);
+ break;
+
+ case AVR8_REGIDX_TCNT4L:
+ AVR8_TCNT4L = data;
+ break;
+
+ case AVR8_REGIDX_TCNT4H:
+ AVR8_TCNT4H = data;
+ break;
+
+ case AVR8_REGIDX_ICR4L:
+ AVR8_ICR4L = data;
+ break;
+
+ case AVR8_REGIDX_ICR4H:
+ AVR8_ICR4H = data;
+ break;
+
+ case AVR8_REGIDX_OCR4AL:
+ AVR8_OCR4AL = data;
+ break;
+
+ case AVR8_REGIDX_OCR4AH:
+ AVR8_OCR4AH = data;
+ break;
+
+ case AVR8_REGIDX_OCR4BL:
+ AVR8_OCR4BL = data;
+ break;
+
+ case AVR8_REGIDX_OCR4BH:
+ AVR8_OCR4BH = data;
+ break;
+
+ case AVR8_REGIDX_OCR4CL:
+ AVR8_OCR4CL = data;
+ break;
+
+ case AVR8_REGIDX_OCR4CH:
+ AVR8_OCR4CH = data;
+ break;
+
+ case AVR8_REGIDX_TCCR5A:
+ verboselog(m_pc, 0, "AVR8: TCCR5A = %02x\n", data );
+ changed_tccr5a(data);
+ break;
+
+ case AVR8_REGIDX_TCCR5B:
+ verboselog(m_pc, 0, "AVR8: TCCR5B = %02x\n", data );
+ changed_tccr5b(data);
+ break;
+
+ case AVR8_REGIDX_ASSR:
+ verboselog(m_pc, 0, "AVR8: ASSR = %02x\n", data );
+ //TODO: changed_assr(data);
+ break;
+
+ case AVR8_REGIDX_TWBR:
+ verboselog(m_pc, 0, "AVR8: TWBR = %02x\n", data );
+ //TODO: changed_twbr(data);
+ break;
+
+ case AVR8_REGIDX_TWSR:
+ verboselog(m_pc, 0, "AVR8: TWSR = %02x\n", data );
+ //TODO: changed_twsr(data);
+ break;
+
+ case AVR8_REGIDX_TWAR:
+ verboselog(m_pc, 0, "AVR8: TWAR = %02x\n", data );
+ //TODO: changed_twar(data);
+ break;
+
+ case AVR8_REGIDX_TWDR:
+ verboselog(m_pc, 0, "AVR8: TWDR = %02x\n", data );
+ //TODO: changed_twdr(data);
+ break;
+
+ case AVR8_REGIDX_TWCR:
+ verboselog(m_pc, 0, "AVR8: TWCR = %02x\n", data );
+ //TODO: changed_twcr(data);
+ m_r[AVR8_REGIDX_TWCR] = data;
+ break;
+
+ case AVR8_REGIDX_TWAMR:
+ verboselog(m_pc, 0, "AVR8: TWAMR = %02x\n", data );
+ //TODO: changed_twamr(data);
+ break;
+
+ case AVR8_REGIDX_UCSR0A:
+ verboselog(m_pc, 0, "AVR8: UCSR0A = %02x\n", data );
+ //TODO: changed_ucsr0a(data);
+ break;
+
+ case AVR8_REGIDX_UCSR0B:
+ verboselog(m_pc, 0, "AVR8: UCSR0B = %02x\n", data );
+ //TODO: changed_ucsr0b(data);
+ break;
+
+ case AVR8_REGIDX_UCSR0C:
+ verboselog(m_pc, 0, "AVR8: UCSR0C = %02x\n", data );
+ //TODO: changed_ucsr0c(data);
+ break;
+/*
+ case AVR8_REGIDX_:
+ verboselog(m_pc, 0, "AVR8: = %02x\n", data );
+ //TODO: changed_(data);
+ break;
+*/
+ default:
+ verboselog(m_pc, 0, "AVR8: Unknown Register Write: %03x = %02x\n", offset, data);
+ break;
+ }
+}
+
+READ8_MEMBER( avr8_device::regs_r )
+{
+// printf("--- READ offset %04x ---\n", offset);
+
+ switch( offset )
+ {
+ case AVR8_REGIDX_R0:
+ case AVR8_REGIDX_R1:
+ case AVR8_REGIDX_R2:
+ case AVR8_REGIDX_R3:
+ case AVR8_REGIDX_R4:
+ case AVR8_REGIDX_R5:
+ case AVR8_REGIDX_R6:
+ case AVR8_REGIDX_R7:
+ case AVR8_REGIDX_R8:
+ case AVR8_REGIDX_R9:
+ case AVR8_REGIDX_R10:
+ case AVR8_REGIDX_R11:
+ case AVR8_REGIDX_R12:
+ case AVR8_REGIDX_R13:
+ case AVR8_REGIDX_R14:
+ case AVR8_REGIDX_R15:
+ case AVR8_REGIDX_R16:
+ case AVR8_REGIDX_R17:
+ case AVR8_REGIDX_R18:
+ case AVR8_REGIDX_R19:
+ case AVR8_REGIDX_R20:
+ case AVR8_REGIDX_R21:
+ case AVR8_REGIDX_R22:
+ case AVR8_REGIDX_R23:
+ case AVR8_REGIDX_R24:
+ case AVR8_REGIDX_R25:
+ case AVR8_REGIDX_R26:
+ case AVR8_REGIDX_R27:
+ case AVR8_REGIDX_R28:
+ case AVR8_REGIDX_R29:
+ case AVR8_REGIDX_R30:
+ case AVR8_REGIDX_R31:
+ return m_r[offset];
+
+ case AVR8_REGIDX_PINA:
+ // TODO: consider the DDRA
+ return m_io->read_byte(AVR8_REG_A);
+
+ case AVR8_REGIDX_PINB:
+ // TODO: consider the DDRB
+ return m_io->read_byte(AVR8_REG_B);
+
+ case AVR8_REGIDX_PINC:
+ // TODO: consider the DDRC
+ return m_io->read_byte(AVR8_REG_C);
+
+ case AVR8_REGIDX_PIND:
+ // TODO: consider the DDRD
+ return m_io->read_byte(AVR8_REG_D);
+
+ case AVR8_REGIDX_PINE:
+ // TODO: consider the DDRE
+ return m_io->read_byte(AVR8_REG_E);
+
+ case AVR8_REGIDX_PINF:
+ // TODO: consider the DDRF
+ return m_io->read_byte(AVR8_REG_F);
+
+ case AVR8_REGIDX_PING:
+ // TODO: consider the DDRG
+ return m_io->read_byte(AVR8_REG_G);
+
+ case AVR8_REGIDX_PINH:
+ // TODO: consider the DDRH
+ return m_io->read_byte(AVR8_REG_H);
+
+ case AVR8_REGIDX_PINJ:
+ // TODO: consider the DDRJ
+ return m_io->read_byte(AVR8_REG_J);
+
+ case AVR8_REGIDX_PINK:
+ // TODO: consider the DDRK
+ return m_io->read_byte(AVR8_REG_K);
+
+ case AVR8_REGIDX_PINL:
+ // TODO: consider the DDRL
+ return m_io->read_byte(AVR8_REG_L);
+
+ case AVR8_REGIDX_PORTA:
+ case AVR8_REGIDX_PORTB:
+ case AVR8_REGIDX_PORTC:
+ case AVR8_REGIDX_PORTD:
+ case AVR8_REGIDX_PORTE:
+ case AVR8_REGIDX_PORTF:
+ case AVR8_REGIDX_PORTG:
+ case AVR8_REGIDX_PORTH:
+ case AVR8_REGIDX_PORTJ:
+ case AVR8_REGIDX_PORTK:
+ case AVR8_REGIDX_PORTL:
+ return m_r[offset];
+
+ case AVR8_REGIDX_DDRA:
+ case AVR8_REGIDX_DDRB:
+ case AVR8_REGIDX_DDRC:
+ case AVR8_REGIDX_DDRD:
+ case AVR8_REGIDX_DDRE:
+ case AVR8_REGIDX_DDRF:
+ case AVR8_REGIDX_DDRG:
+ case AVR8_REGIDX_DDRH:
+ case AVR8_REGIDX_DDRJ:
+ case AVR8_REGIDX_DDRK:
+ case AVR8_REGIDX_DDRL:
+ return m_r[offset];
+
+// EEPROM registers:
+ case AVR8_REGIDX_EECR:
+ case AVR8_REGIDX_EEDR:
+ return m_r[offset];
+
+/* Misc. registers.
+ TODO: implement all registers reads */
+
+ case AVR8_REGIDX_GPIOR0:
+ case AVR8_REGIDX_GPIOR1:
+ case AVR8_REGIDX_GPIOR2:
+// case AVR8_REGIDX_UCSR0B:/*TODO: needed for Replicator 1 */
+ case AVR8_REGIDX_SPDR: /*TODO: needed for Replicator 1 */
+ case AVR8_REGIDX_SPSR: /*TODO: needed for Replicator 1 */
+// case AVR8_REGIDX_ADCSRA: /*TODO: needed for Replicator 1 */
+// case AVR8_REGIDX_ADCSRB: /*TODO: needed for Replicator 1 */
+ case AVR8_REGIDX_SPL:
+ case AVR8_REGIDX_SPH:
+ case AVR8_REGIDX_SREG:
+ case AVR8_REGIDX_TIMSK0:
+ case AVR8_REGIDX_TIMSK1:
+ case AVR8_REGIDX_TIMSK2:
+// case AVR8_REGIDX_TIMSK3: /*TODO: needed for Replicator 1 */
+ case AVR8_REGIDX_TIMSK4:
+ case AVR8_REGIDX_TIMSK5:
+ return m_r[offset];
+
+/* Two-wire registers: */
+ case AVR8_REGIDX_TWCR:
+ /*TODO: needed for Replicator 1
+ BLOQUEIA PROGRESSO DA EXECU??O DO FIRMWARE no endere?o 105EC*/
+ return m_r[offset];
+
+ case AVR8_REGIDX_TWSR:
+ //quick hack: by returning a value != 0x08 we induce an error state that makes the object code jump out of the wait loop and continue execution failing the 2-wire write operation.
+ //TODO: implement-me!
+ return 0x00; /*TODO: needed for Replicator 1 */
+
+
+ case AVR8_REGIDX_TCNT1L:
+ case AVR8_REGIDX_TCNT1H:
+ case AVR8_REGIDX_TCNT2:
+ case AVR8_REGIDX_UCSR0A:
+ return m_r[offset];
+
+ default:
+ printf("[%08X] AVR8: Unknown Register Read: 0x%03X\n", m_shifted_pc, offset);
+// debugger_break(machine());
+ return 0;
+ }
+}
+
+
+//**************************************************************************
+// CORE EXECUTION LOOP
+//**************************************************************************
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+UINT32 avr8_device::execute_min_cycles() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// execute_max_cycles - return maximum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+UINT32 avr8_device::execute_max_cycles() const
+{
+ return 4;
+}
+
+
+//-------------------------------------------------
+// execute_input_lines - return the number of
+// input/interrupt lines
+//-------------------------------------------------
+
+UINT32 avr8_device::execute_input_lines() const
+{
+ return 0;
+}
+
+
+void avr8_device::execute_set_input(int inputnum, int state)
+{
+}
+
+
+//-------------------------------------------------
+// execute_run - execute a timeslice's worth of
+// opcodes
+//-------------------------------------------------
+
+void avr8_device::execute_run()
+{
+ UINT32 op = 0;
+ INT32 offs = 0;
+ UINT8 rd = 0;
+ UINT8 rr = 0;
+ UINT8 res = 0;
+ UINT16 pd = 0;
+ UINT32 pd32 = 0;
+ INT16 sd = 0;
+ INT32 opcycles = 1;
+
+ while (m_icount > 0)
+ {
+ opcycles = 1;
+
+ m_pc &= m_addr_mask;
+ m_shifted_pc &= (m_addr_mask << 1) | 1;
+
+ debugger_instruction_hook(this, m_shifted_pc);
+
+ op = (UINT32)m_program->read_word(m_shifted_pc);
+
+ switch(op & 0xf000)
+ {
+ case 0x0000:
+ switch(op & 0x0f00)
+ {
+ case 0x0000: // NOP
+ break;
+ case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd
+ m_r[(RD4(op) << 1) + 1] = m_r[(RR4(op) << 1) + 1];
+ m_r[RD4(op) << 1] = m_r[RR4(op) << 1];
+ break;
+ case 0x0200: // MULS Rd,Rr
+ sd = (INT8)m_r[16 + RD4(op)] * (INT8)m_r[16 + RR4(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ case 0x0300: // Multiplicatn
+ switch(MULCONST2(op))
+ {
+ case 0x0000: // MULSU Rd,Rr
+ sd = (INT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ case 0x0001: // FMUL Rd,Rr
+ sd = (UINT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)];
+ sd <<= 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ case 0x0002: // FMULS Rd,Rr
+ sd = (INT8)m_r[16 + RD3(op)] * (INT8)m_r[16 + RR3(op)];
+ sd <<= 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ case 0x0003: // FMULSU Rd,Rr
+ sd = (INT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)];
+ sd <<= 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ }
+ break;
+ case 0x0400:
+ case 0x0500:
+ case 0x0600:
+ case 0x0700: // CPC Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd - (rr + SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x0800:
+ case 0x0900:
+ case 0x0a00:
+ case 0x0b00: // SBC Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd - (rr + SREG_R(AVR8_SREG_C));
+ m_r[RD5(op)] = res;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00: // ADD Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd + rr;
+ m_r[RD5(op)] = res;
+ SREG_W(AVR8_SREG_H, (BIT(rd,3) & BIT(rr,3)) | (BIT(rr,3) & NOT(BIT(res,3))) | (NOT(BIT(res,3)) & BIT(rd,3)));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & NOT(BIT(rr,7)) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (BIT(rd,7) & BIT(rr,7)) | (BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(res,7)) & BIT(rd,7)));
+ break;
+ }
+ break;
+ case 0x1000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000: // CPSE Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ if (rd == rr)
+ {
+ op = (UINT32)m_program->read_word(m_shifted_pc + 2);
+ opcycles += is_long_opcode(op) ? 2 : 1;
+ m_pc += is_long_opcode(op) ? 2 : 1;
+ }
+ break;
+ case 0x0400: // CP Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd - rr;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x0800: // SUB Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd - rr;
+ m_r[RD5(op)] = res;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x0c00: // ADC Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ res = rd + rr + SREG_R(AVR8_SREG_C);
+ m_r[RD5(op)] = res;
+ SREG_W(AVR8_SREG_H, (BIT(rd,3) & BIT(rr,3)) | (BIT(rr,3) & NOT(BIT(res,3))) | (NOT(BIT(res,3)) & BIT(rd,3)));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & NOT(BIT(rr,7)) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (BIT(rd,7) & BIT(rr,7)) | (BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(res,7)) & BIT(rd,7)));
+ break;
+ }
+ break;
+ case 0x2000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000: // AND Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ rd &= rr;
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0);
+ m_r[RD5(op)] = rd;
+ break;
+ case 0x0400: // EOR Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ rd ^= rr;
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0);
+ m_r[RD5(op)] = rd;
+ break;
+ case 0x0800: // OR Rd,Rr
+ rd = m_r[RD5(op)];
+ rr = m_r[RR5(op)];
+ rd |= rr;
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0);
+ m_r[RD5(op)] = rd;
+ break;
+ case 0x0c00: // MOV Rd,Rr
+ m_r[RD5(op)] = m_r[RR5(op)];
+ break;
+ }
+ break;
+ case 0x3000: // CPI Rd,K
+ rd = m_r[16 + RD4(op)];
+ rr = KCONST8(op);
+ res = rd - rr;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x4000: // SBCI Rd,K
+ rd = m_r[16 + RD4(op)];
+ rr = KCONST8(op);
+ res = rd - (rr + SREG_R(AVR8_SREG_C));
+ m_r[16 + RD4(op)] = res;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x5000: // SUBI Rd,K
+ rd = m_r[16 + RD4(op)];
+ rr = KCONST8(op);
+ res = rd - rr;
+ m_r[16 + RD4(op)] = res;
+ SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3))));
+ SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
+ break;
+ case 0x6000: // ORI Rd,K
+ rd = m_r[16 + RD4(op)];
+ rr = KCONST8(op);
+ rd |= rr;
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0);
+ m_r[16 + RD4(op)] = rd;
+ break;
+ case 0x7000: // ANDI Rd,K
+ rd = m_r[16 + RD4(op)];
+ rr = KCONST8(op);
+ rd &= rr;
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0);
+ m_r[16 + RD4(op)] = rd;
+ break;
+ case 0x8000:
+ case 0xa000:
+ switch(op & 0x0208)
+ {
+ case 0x0000: // LDD Rd,Z+q
+ m_r[RD5(op)] = m_data->read_byte(ZREG + QCONST6(op));
+ opcycles = 2;
+ break;
+ case 0x0008: // LDD Rd,Y+q
+ m_r[RD5(op)] = m_data->read_byte(YREG + QCONST6(op));
+ opcycles = 2;
+ break;
+ case 0x0200: // STD Z+q,Rr
+ m_data->write_byte(ZREG + QCONST6(op), m_r[RD5(op)]);
+ opcycles = 2;
+ break;
+ case 0x0208: // STD Y+q,Rr
+ m_data->write_byte(YREG + QCONST6(op), m_r[RD5(op)]);
+ opcycles = 2;
+ break;
+ }
+ break;
+ case 0x9000:
+ switch(op & 0x0f00)
+ {
+ case 0x0000:
+ case 0x0100:
+ switch(op & 0x000f)
+ {
+ case 0x0000: // LDS Rd,k
+ op <<= 16;
+ m_pc++;
+ m_shifted_pc += 2;
+ op |= m_program->read_word(m_shifted_pc);
+ m_r[RD5(op >> 16)] = m_data->read_byte(op & 0x0000ffff);
+ opcycles = 2;
+ break;
+ case 0x0001: // LD Rd,Z+
+ pd = ZREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0002: // LD Rd,-Z
+ pd = ZREG;
+ pd--;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0004: // LPM Rd,Z
+ m_r[RD5(op)] = m_program->read_byte(ZREG);
+ opcycles = 3;
+ break;
+ case 0x0005: // LPM Rd,Z+
+ pd = ZREG;
+ m_r[RD5(op)] = m_program->read_byte(pd);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+ opcycles = 3;
+ break;
+ case 0x0006: // ELPM Rd,Z
+ m_r[RD5(op)] = m_program->read_byte((m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG);
+ opcycles = 3;
+ break;
+ case 0x0007: // ELPM Rd,Z+
+ pd32 = (m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG;
+ m_r[RD5(op)] = m_program->read_byte(pd32);
+ pd32++;
+ m_r[AVR8_REGIDX_RAMPZ] = (pd32 >> 16) & 0x00ff;
+ m_r[31] = (pd32 >> 8) & 0x00ff;
+ m_r[30] = pd32 & 0x00ff;
+ opcycles = 3;
+ break;
+ case 0x0009: // LD Rd,Y+
+ pd = YREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000a: // LD Rd,-Y
+ pd = YREG;
+ pd--;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000c: // LD Rd,X
+ m_r[RD5(op)] = m_data->read_byte(XREG);
+ opcycles = 2;
+ break;
+ case 0x000d: // LD Rd,X+
+ pd = XREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000e: // LD Rd,-X
+ pd = XREG;
+ pd--;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000f: // POP Rd
+ m_r[RD5(op)] = pop();
+ opcycles = 2;
+ break;
+ default:
+ unimplemented_opcode(op);
+ //output += sprintf( output, "Undefined (%04x)", op );
+ break;
+ }
+ break;
+ case 0x0200:
+ case 0x0300:
+ switch(op & 0x000f)
+ {
+ case 0x0000: // STS k,Rr
+ op <<= 16;
+ m_pc++;
+ m_shifted_pc += 2;
+ op |= m_program->read_word(m_shifted_pc);
+ m_data->write_byte(op & 0x0000ffff, m_r[RD5(op >> 16)]);
+ opcycles = 2;
+ break;
+ case 0x0001: // ST Z+,Rd
+ pd = ZREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0002: // ST -Z,Rd
+ pd = ZREG;
+ pd--;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0009: // ST Y+,Rd
+ pd = YREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000a: // ST -Y,Rd
+ pd = YREG;
+ pd--;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000c: // ST X,Rd
+ m_data->write_byte(XREG, m_r[RD5(op)]);
+ break;
+ case 0x000d: // ST X+,Rd
+ pd = XREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000e: // ST -X,Rd
+ pd = XREG;
+ pd--;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x000f: // PUSH Rd
+ push(m_r[RD5(op)]);
+ opcycles = 2;
+ break;
+ default:
+ unimplemented_opcode(op);
+ //output += sprintf( output, "Undefined (%04x)", op );
+ break;
+ }
+ break;
+ case 0x0400:
+ switch(op & 0x000f)
+ {
+ case 0x0000: // COM Rd
+ rd = m_r[RD5(op)];
+ res = ~rd;
+ SREG_W(AVR8_SREG_C, 1);
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0001: // NEG Rd
+ rd = m_r[RD5(op)];
+ res = 0 - rd;
+ SREG_W(AVR8_SREG_C, (res == 0) ? 0 : 1);
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, (res == 0x80) ? 1 : 0);
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_H, BIT(res,3) | BIT(rd,3));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0002: // SWAP Rd
+ rd = m_r[RD5(op)];
+ m_r[RD5(op)] = (rd >> 4) | (rd << 4);
+ break;
+ case 0x0003: // INC Rd
+ rd = m_r[RD5(op)];
+ res = rd + 1;
+ SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0005: // ASR Rd
+ rd = m_r[RD5(op)];
+ res = (rd & 0x80) | (rd >> 1);
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0006: // LSR Rd
+ rd = m_r[RD5(op)];
+ res = rd >> 1;
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0);
+ SREG_W(AVR8_SREG_N, 0);
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0007: // ROR Rd
+ rd = m_r[RD5(op)];
+ res = rd >> 1;
+ res |= (SREG_R(AVR8_SREG_C) << 7);
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0008:
+ switch(op & 0x00f0)
+ {
+ case 0x0000: // SEC
+ case 0x0010: // SEZ
+ case 0x0020: // SEN
+ case 0x0030: // SEV
+ case 0x0040: // SES
+ case 0x0050: // SEH
+ case 0x0060: // SET
+ case 0x0070: // SEI
+ SREG_W((op >> 4) & 0x07, 1);
+ break;
+ case 0x0080: // CLC
+ case 0x0090: // CLZ
+ case 0x00a0: // CLN
+ case 0x00b0: // CLV
+ case 0x00c0: // CLS
+ case 0x00d0: // CLH
+ case 0x00e0: // CLT
+ case 0x00f0: // CLI
+ SREG_W((op >> 4) & 0x07, 0);
+ break;
+ }
+ break;
+ case 0x0009:
+ switch(op & 0x00f0)
+ {
+ case 0x0000: // IJMP
+ m_pc = ZREG - 1;
+ opcycles = 2;
+ break;
+ case 0x0010: // EIJMP
+ m_pc = (m_r[AVR8_REGIDX_EIND] << 16 | ZREG) - 1;
+ opcycles = 2;
+ break;
+ default:
+ //output += sprintf( output, "Undefined (%04x)", op );
+ unimplemented_opcode(op);
+ break;
+ }
+ break;
+ case 0x000a: // DEC Rd
+ rd = m_r[RD5(op)];
+ res = rd - 1;
+ SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ m_r[RD5(op)] = res;
+ break;
+ case 0x000c:
+ case 0x000d: // JMP k
+ offs = KCONST22(op) << 16;
+ m_pc++;
+ m_shifted_pc += 2;
+ offs |= m_program->read_word(m_shifted_pc);
+ m_pc = offs;
+ m_pc--;
+ opcycles = 3;
+ break;
+ case 0x000e: // CALL k
+ case 0x000f:
+ push((m_pc + 2) & 0x00ff);
+ push(((m_pc + 2) >> 8) & 0x00ff);
+ offs = KCONST22(op) << 16;
+ m_pc++;
+ m_shifted_pc += 2;
+ offs |= m_program->read_word(m_shifted_pc);
+ m_pc = offs;
+ m_pc--;
+ opcycles = 4;
+ break;
+ default:
+ unimplemented_opcode(op);
+ //output += sprintf( output, "Undefined (%04x)", op );
+ break;
+ }
+ break;
+ case 0x0500:
+ switch(op & 0x000f)
+ {
+ case 0x0000: // COM Rd
+ rd = m_r[RD5(op)];
+ res = ~rd;
+ SREG_W(AVR8_SREG_C, 1);
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, 0);
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0001: // NEG Rd
+ rd = m_r[RD5(op)];
+ res = 0 - rd;
+ SREG_W(AVR8_SREG_C, (res == 0) ? 0 : 1);
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, (res == 0x80) ? 1 : 0);
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_H, BIT(res,3) | BIT(rd,3));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0002: // SWAP Rd
+ rd = m_r[RD5(op)];
+ m_r[RD5(op)] = (rd >> 4) | (rd << 4);
+ break;
+ case 0x0003: // INC Rd
+ rd = m_r[RD5(op)];
+ res = rd + 1;
+ SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0005: // ASR Rd
+ rd = m_r[RD5(op)];
+ res = (rd & 0x80) | (rd >> 1);
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(rd,7));
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0006: // LSR Rd
+ rd = m_r[RD5(op)];
+ res = rd >> 1;
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0);
+ SREG_W(AVR8_SREG_N, 0);
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0007: // ROR Rd
+ rd = m_r[RD5(op)];
+ res = rd >> 1;
+ res |= (SREG_R(AVR8_SREG_C) << 7);
+ SREG_W(AVR8_SREG_C, BIT(rd,0));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ m_r[RD5(op)] = res;
+ break;
+ case 0x0008:
+ switch(op & 0x00f0)
+ {
+ case 0x0000: // RET
+ m_pc = pop() << 8;
+ m_pc |= pop();
+ m_pc--;
+ opcycles = 4;
+ break;
+ case 0x0010: // RETI
+ m_pc = pop() << 8;
+ m_pc |= pop();
+ m_pc--;
+ SREG_W(AVR8_SREG_I, 1);
+ opcycles = 4;
+ break;
+ case 0x0080: // SLEEP
+ //output += sprintf( output, "SLEEP" );
+ m_pc--;
+ opcycles = 1;
+ //unimplemented_opcode(op);
+ break;
+ case 0x0090: // BREAK
+ //output += sprintf( output, "BREAK" );
+ unimplemented_opcode(op);
+ break;
+ case 0x00a0: // WDR
+ //output += sprintf( output, "WDR" );
+ //unimplemented_opcode(op); //TODO: necessary for emulating the Replicator 1
+ //printf("Watchdot Reset!\n");
+ opcycles = 1;
+ break;
+ case 0x00c0: // LPM
+ m_r[0] = m_program->read_byte(ZREG);
+ opcycles = 3;
+ break;
+ case 0x00d0: // ELPM
+ //output += sprintf( output, "ELPM" );
+ unimplemented_opcode(op);
+ break;
+ case 0x00e0: // SPM
+ //output += sprintf( output, "SPM" );
+ unimplemented_opcode(op);
+ break;
+ case 0x00f0: // SPM Z+
+ //output += sprintf( output, "SPM Z+" );
+ unimplemented_opcode(op);
+ break;
+ default:
+ unimplemented_opcode(op);
+ //output += sprintf( output, "Undefined (%04x)", op );
+ break;
+ }
+ break;
+ case 0x0009:
+ switch(op & 0x00f0)
+ {
+ case 0x0000: // ICALL
+ push((m_pc + 1) & 0x00ff);
+ push(((m_pc + 1) >> 8) & 0x00ff);
+ m_pc = ZREG;
+ m_pc--;
+ opcycles = 3;
+ break;
+ case 0x0010: // EICALL
+ //output += sprintf( output, "EICALL" );
+ unimplemented_opcode(op);
+ break;
+ default:
+ unimplemented_opcode(op);
+ //output += sprintf( output, "Undefined (%04x)", op );
+ break;
+ }
+ break;
+ case 0x000a: // DEC Rd
+ rd = m_r[RD5(op)];
+ res = rd - 1;
+ SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0);
+ SREG_W(AVR8_SREG_N, BIT(res,7));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
+ m_r[RD5(op)] = res;
+ break;
+ case 0x000c:
+ case 0x000d: // JMP k
+ //op <<= 8;
+ //op |= oprom[pos++];
+ //op <<= 8;
+ //op |= oprom[pos++];
+ //output += sprintf( output, "JMP 0x%06x", KCONST22(op) );
+ unimplemented_opcode(op);
+ break;
+ case 0x000e:
+ case 0x000f: // CALL k
+ //op <<= 8;
+ //op |= oprom[pos++];
+ //op <<= 8;
+ //op |= oprom[pos++];
+ //output += sprintf( output, "CALL 0x%06x", KCONST22(op) );
+ unimplemented_opcode(op);
+ break;
+ }
+ break;
+ case 0x0600: // ADIW Rd+1:Rd,K
+ rd = m_r[24 + (DCONST(op) << 1)];
+ rr = m_r[25 + (DCONST(op) << 1)];
+ pd = rd;
+ pd |= rr << 8;
+ pd += KCONST6(op);
+ SREG_W(AVR8_SREG_V, BIT(pd,15) & NOT(BIT(rr,7)));
+ SREG_W(AVR8_SREG_N, BIT(pd,15));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, NOT(BIT(pd,15)) & BIT(rr,7));
+ m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff;
+ m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0700: // SBIW Rd+1:Rd,K
+ rd = m_r[24 + (DCONST(op) << 1)];
+ rr = m_r[25 + (DCONST(op) << 1)];
+ pd = rd;
+ pd |= rr << 8;
+ pd -= KCONST6(op);
+ SREG_W(AVR8_SREG_V, NOT(BIT(pd,15)) & BIT(rr,7));
+ SREG_W(AVR8_SREG_N, BIT(pd,15));
+ SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
+ SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0);
+ SREG_W(AVR8_SREG_C, BIT(pd,15) & NOT(BIT(rr,7)));
+ m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff;
+ m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff;
+ opcycles = 2;
+ break;
+ case 0x0800: // CBI A,b
+ //output += sprintf( output, "CBI 0x%02x, %d", ACONST5(op), RR3(op) );
+ m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) &~ (1 << RR3(op)));
+ opcycles = 2;
+ break;
+ case 0x0900: // SBIC A,b
+ if(NOT(BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op))))
+ {
+ op = (UINT32)m_program->read_word(m_shifted_pc + 2);
+ opcycles = is_long_opcode(op) ? 3 : 2;
+ m_pc += is_long_opcode(op) ? 2 : 1;
+ }
+ break;
+ case 0x0a00: // SBI A,b
+ m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) | (1 << RR3(op)));
+ opcycles = 2;
+ break;
+ case 0x0b00: // SBIS A,b
+ if(BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op)))
+ {
+ op = (UINT32)m_program->read_word(m_shifted_pc + 2);
+ opcycles = is_long_opcode(op) ? 3 : 2;
+ m_pc += is_long_opcode(op) ? 2 : 1;
+ }
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00: // MUL Rd,Rr
+ sd = (UINT8)m_r[RD5(op)] * (UINT8)m_r[RR5(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0);
+ SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0);
+ opcycles = 2;
+ break;
+ }
+ break;
+ case 0xb000:
+ if(op & 0x0800) // OUT A,Rr
+ {
+ m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]);
+ }
+ else // IN Rd,A
+ {
+ m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op));
+ }
+ break;
+ case 0xc000: // RJMP k
+ offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff));
+ m_pc += offs;
+ opcycles = 2;
+ break;
+ case 0xd000: // RCALL k
+ offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff));
+ push((m_pc + 1) & 0x00ff);
+ push(((m_pc + 1) >> 8) & 0x00ff);
+ m_pc += offs;
+ opcycles = 3;
+ break;
+ case 0xe000: // LDI Rd,K
+ m_r[16 + RD4(op)] = KCONST8(op);
+ break;
+ case 0xf000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000: // BRLO through BRIE
+ if(SREG_R(op & 0x0007))
+ {
+ offs = (INT32)(KCONST7(op));
+ if(offs & 0x40)
+ {
+ offs |= 0xffffff80;
+ }
+ m_pc += offs;
+ opcycles = 2;
+ }
+ break;
+ case 0x0400: // BRSH through BRID
+ if(SREG_R(op & 0x0007) == 0)
+ {
+ offs = (INT32)(KCONST7(op));
+ if(offs & 0x40)
+ {
+ offs |= 0xffffff80;
+ }
+ m_pc += offs;
+ opcycles = 2;
+ }
+ break;
+ case 0x0800:
+ if(op & 0x0200) // BST Rd, b
+ {
+ SREG_W(AVR8_SREG_T, (BIT(m_r[RD5(op)], RR3(op))) ? 1 : 0);
+ }
+ else // BLD Rd, b
+ {
+ if(SREG_R(AVR8_SREG_T))
+ {
+ m_r[RD5(op)] |= (1 << RR3(op));
+ }
+ else
+ {
+ m_r[RD5(op)] &= ~(1 << RR3(op));
+ }
+ }
+ break;
+ case 0x0c00:
+ if(op & 0x0200) // SBRS Rd, b
+ {
+ if(BIT(m_r[RD5(op)], RR3(op)))
+ {
+ op = (UINT32)m_program->read_word(m_shifted_pc + 2);
+ m_pc += is_long_opcode(op) ? 2 : 1;
+ opcycles = is_long_opcode(op) ? 3 : 2;
+ }
+ }
+ else // SBRC Rd, b
+ {
+ if(NOT(BIT(m_r[RD5(op)], RR3(op))))
+ {
+ op = (UINT32)m_program->read_word(m_shifted_pc + 2);
+ m_pc += is_long_opcode(op) ? 2 : 1;
+ opcycles = is_long_opcode(op) ? 3 : 2;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ m_pc++;
+
+ m_shifted_pc = m_pc << 1;
+
+ m_icount -= opcycles;
+
+ timer_tick(opcycles);
+ }
+}