summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/avr8
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/avr8')
-rw-r--r--src/devices/cpu/avr8/avr8.cpp5448
-rw-r--r--src/devices/cpu/avr8/avr8.h1645
-rw-r--r--src/devices/cpu/avr8/avr8dasm.cpp1043
-rw-r--r--src/devices/cpu/avr8/avr8ops.hxx1403
4 files changed, 5475 insertions, 4064 deletions
diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp
index 5bc83e55511..4f319b2131a 100644
--- a/src/devices/cpu/avr8/avr8.cpp
+++ b/src/devices/cpu/avr8/avr8.cpp
@@ -6,13 +6,13 @@
- 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
+ interrupts although no software has been encountered 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
+ Unimplemented opcodes: SPM, SPM Z+, SLEEP, BREAK, WDR, EICALL
- Changelist -
05 Jul. 2015 [Felipe Sanches]
@@ -60,23 +60,42 @@
#include "emu.h"
#include "avr8.h"
#include "avr8dasm.h"
-#include "debugger.h"
-#define VERBOSE_LEVEL (0)
-
-#define ENABLE_VERBOSE_LOG (0)
-
-static inline void ATTR_PRINTF(3, 4) verboselogout(device_t &dev, uint16_t pc, const char *s_fmt, ...)
-{
- va_list v;
- char buf[ 32768 ];
- va_start( v, s_fmt );
- vsprintf( buf, s_fmt, v );
- va_end( v );
- dev.logerror( "%05x: %s", pc << 1, buf );
-}
-
-#define verboselog(x,y,...) do { if (ENABLE_VERBOSE_LOG && (VERBOSE_LEVEL >= y)) verboselogout(*this, x, __VA_ARGS__); } while (false)
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_BOOT (1U << 2)
+#define LOG_TIMER0 (1U << 3)
+#define LOG_TIMER1 (1U << 4)
+#define LOG_TIMER2 (1U << 5)
+#define LOG_TIMER3 (1U << 6)
+#define LOG_TIMER4 (1U << 7)
+#define LOG_TIMER5 (1U << 8)
+#define LOG_TIMER0_TICK (1U << 9)
+#define LOG_TIMER1_TICK (1U << 10)
+#define LOG_TIMER2_TICK (1U << 11)
+#define LOG_TIMER3_TICK (1U << 12)
+#define LOG_TIMER4_TICK (1U << 13)
+#define LOG_TIMER5_TICK (1U << 14)
+#define LOG_EEPROM (1U << 15)
+#define LOG_GPIO (1U << 16)
+#define LOG_WDOG (1U << 17)
+#define LOG_CLOCK (1U << 18)
+#define LOG_POWER (1U << 19)
+#define LOG_OSC (1U << 20)
+#define LOG_PINCHG (1U << 21)
+#define LOG_EXTMEM (1U << 22)
+#define LOG_ADC (1U << 23)
+#define LOG_DIGINPUT (1U << 24)
+#define LOG_ASYNC (1U << 25)
+#define LOG_TWI (1U << 26)
+#define LOG_UART (1U << 27)
+#define LOG_TIMERS (LOG_TIMER0 | LOG_TIMER1 | LOG_TIMER2 | LOG_TIMER3 | LOG_TIMER4 | LOG_TIMER5)
+#define LOG_TIMER_TICKS (LOG_TIMER0_TICK | LOG_TIMER1_TICK | LOG_TIMER2_TICK | LOG_TIMER3_TICK | LOG_TIMER4_TICK | LOG_TIMER5_TICK)
+#define LOG_ALL (LOG_UNKNOWN | LOG_BOOT | LOG_TIMERS | LOG_EEPROM | LOG_GPIO | LOG_WDOG | LOG_CLOCK | LOG_POWER \
+ | LOG_OSC | LOG_PINCHG | LOG_EXTMEM | LOG_ADC | LOG_DIGINPUT | LOG_ASYNC | LOG_TWI | LOG_UART)
+
+#define VERBOSE (0)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
//**************************************************************************
@@ -85,39 +104,28 @@ static inline void ATTR_PRINTF(3, 4) verboselogout(device_t &dev, uint16_t pc, c
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
+ SREG_C = 0,
+ SREG_Z,
+ SREG_N,
+ SREG_V,
+ SREG_S,
+ SREG_H,
+ SREG_T,
+ SREG_I,
+
+ SREG_MASK_C = 0x01,
+ SREG_MASK_Z = 0x02,
+ SREG_MASK_N = 0x04,
+ SREG_MASK_V = 0x08,
+ SREG_MASK_S = 0x10,
+ SREG_MASK_H = 0x20,
+ SREG_MASK_T = 0x40,
+ SREG_MASK_I = 0x80
};
// 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,
@@ -168,12 +176,6 @@ enum
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)
@@ -196,401 +198,514 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' };
#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])
+#define SPREG ((m_r[SPH] << 8) | m_r[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 TCCR0B_CS_SHIFT 0
+#define TCCR0B_CS_MASK 0x07
+#define TCCR0B_WGM0_2_SHIFT 3
+#define TCCR0B_WGM0_2_MASK 0x08
+#define TCCR0B_FOC0B_SHIFT 6
+#define TCCR0B_FOC0B_MASK 0x40
+#define TCCR0B_FOC0A_SHIFT 7
+#define TCCR0B_FOC0A_MASK 0x80
+#define TIMER0_CLOCK_SELECT (m_r[TCCR0B] & TCCR0B_CS_MASK)
+
+#define TCCR0A_WGM0_10_SHIFT 0
+#define TCCR0A_WGM0_10_MASK 0x03
+#define TCCR0A_COM0B_SHIFT 4
+#define TCCR0A_COM0B_MASK 0x30
+#define TCCR0A_COM0A_SHIFT 6
+#define TCCR0A_COM0A_MASK 0xc0
+#define TCCR0A_COM0A ((m_r[TCCR0A] & TCCR0A_COM0A_MASK) >> TCCR0A_COM0A_SHIFT)
+#define TCCR0A_COM0B ((m_r[TCCR0A] & TCCR0A_COM0B_MASK) >> TCCR0A_COM0B_SHIFT)
+#define TCCR0A_WGM0_10 (m_r[TCCR0A] & TCCR0A_WGM0_10_MASK)
+
+#define TIMSK0_TOIE0_BIT 0
+#define TIMSK0_OCIE0A_BIT 1
+#define TIMSK0_OCIE0B_BIT 2
+#define TIMSK0_TOIE0_MASK (1 << TIMSK0_TOIE0_BIT)
+#define TIMSK0_OCIE0A_MASK (1 << TIMSK0_OCIE0A_BIT)
+#define TIMSK0_OCIE0B_MASK (1 << TIMSK0_OCIE0B_BIT)
+#define TIMSK0_TOIE0 (BIT(m_r[TIMSK0], TIMSK0_TOIE0_BIT))
+#define TIMSK0_OCIE0A (BIT(m_r[TIMSK0], TIMSK0_OCIE0A_BIT))
+#define TIMSK0_OCIE0B (BIT(m_r[TIMSK0], TIMSK0_OCIE0B_BIT))
+
+#define TIFR0_TOV0_SHIFT 0
+#define TIFR0_TOV0_MASK 0x01
+#define TIFR0_OCF0A_SHIFT 1
+#define TIFR0_OCF0A_MASK 0x02
+#define TIFR0_OCF0B_SHIFT 2
+#define TIFR0_OCF0B_MASK 0x04
+#define TIFR0_MASK (TIFR0_TOV0_MASK | TIFR0_OCF0B_MASK | TIFR0_OCF0A_MASK)
+
+#define TCCR1B_CS_SHIFT 0
+#define TCCR1B_CS_MASK 0x07
+#define TCCR1B_WGM1_32_SHIFT 3
+#define TCCR1B_WGM1_32_MASK 0x18
+#define TCCR1B_ICES1_SHIFT 6
+#define TCCR1B_ICES1_MASK 0x40
+#define TCCR1B_ICNC1_SHIFT 7
+#define TCCR1B_ICNC1_MASK 0x80
+#define TIMER1_CLOCK_SELECT (m_r[TCCR1B] & TCCR1B_CS_MASK)
+
+#define TCCR1A_WGM1_10_SHIFT 0
+#define TCCR1A_WGM1_10_MASK 0x03
+#define TCCR1A_COM1AB_SHIFT 4
+#define TCCR1A_COM1AB_MASK 0xf0
+#define TCCR1A_COM1B_SHIFT 4
+#define TCCR1A_COM1B_MASK 0x30
+#define TCCR1A_COM1A_SHIFT 6
+#define TCCR1A_COM1A_MASK 0xc0
+#define TCCR1A_COM1A ((m_r[TCCR1A] & TCCR1A_COM1A_MASK) >> TCCR1A_COM1A_SHIFT)
+#define TCCR1A_COM1B ((m_r[TCCR1A] & TCCR1A_COM1B_MASK) >> TCCR1A_COM1B_SHIFT)
+#define TCCR1A_WGM1_10 (m_r[TCCR1A] & TCCR1A_WGM1_10_MASK)
+
+#define TIMSK1_TOIE1_BIT 0
+#define TIMSK1_OCIE1A_BIT 1
+#define TIMSK1_OCIE1B_BIT 2
+#define TIMSK1_ICIE1_BIT 5
+#define TIMSK1_TOIE1_MASK (1 << TIMSK1_TOIE1_BIT)
+#define TIMSK1_OCIE1A_MASK (1 << TIMSK1_OCIE1A_BIT)
+#define TIMSK1_OCIE1B_MASK (1 << TIMSK1_OCIE1B_BIT)
+#define TIMSK1_ICIE1_MASK (1 << TIMSK1_ICIE1_BIT)
+#define TIMSK1_TOIE1 (BIT(m_r[TIMSK1], TIMSK1_TOIE1_BIT))
+#define TIMSK1_OCIE1A (BIT(m_r[TIMSK1], TIMSK1_OCIE1A_BIT))
+#define TIMSK1_OCIE1B (BIT(m_r[TIMSK1], TIMSK1_OCIE1B_BIT))
+#define TIMSK1_ICIE1 (BIT(m_r[TIMSK1], TIMSK1_ICIE1_BIT))
+
+#define TIFR1_TOV1_SHIFT 0
+#define TIFR1_TOV1_MASK 0x01
+#define TIFR1_OCF1A_SHIFT 1
+#define TIFR1_OCF1A_MASK 0x02
+#define TIFR1_OCF1B_SHIFT 2
+#define TIFR1_OCF1B_MASK 0x04
+#define TIFR1_ICF1_SHIFT 5
+#define TIFR1_ICF1_MASK 0x20
+#define TIFR1_MASK (TIFR1_ICF1_MASK | TIFR1_TOV1_MASK | TIFR1_OCF1B_MASK | TIFR1_OCF1A_MASK)
+
+#define TCCR2B_CS_SHIFT 0
+#define TCCR2B_CS_MASK 0x07
+#define TCCR2B_WGM2_2_SHIFT 3
+#define TCCR2B_WGM2_2_MASK 0x08
+#define TCCR2B_FOC2B_SHIFT 6
+#define TCCR2B_FOC2B_MASK 0x40
+#define TCCR2B_FOC2A_SHIFT 7
+#define TCCR2B_FOC2A_MASK 0x80
+#define TIMER2_CLOCK_SELECT (m_r[TCCR2B] & TCCR2B_CS_MASK)
+
+#define TCCR2A_WGM2_10_SHIFT 0
+#define TCCR2A_WGM2_10_MASK 0x03
+#define TCCR2A_COM2B_SHIFT 4
+#define TCCR2A_COM2B_MASK 0x30
+#define TCCR2A_COM2A_SHIFT 6
+#define TCCR2A_COM2A_MASK 0xc0
+#define TCCR2A_COM2A ((m_r[TCCR2A] & TCCR2A_COM2A_MASK) >> TCCR2A_COM2A_SHIFT)
+#define TCCR2A_COM2B ((m_r[TCCR2A] & TCCR2A_COM2B_MASK) >> TCCR2A_COM2B_SHIFT)
+#define TCCR2A_WGM2_10 (m_r[TCCR2A] & TCCR2A_WGM2_10_MASK)
+
+#define TIMSK2_TOIE2_BIT 0
+#define TIMSK2_OCIE2A_BIT 1
+#define TIMSK2_OCIE2B_BIT 2
+#define TIMSK2_TOIE2_MASK (1 << TIMSK2_TOIE2_BIT)
+#define TIMSK2_OCIE2A_MASK (1 << TIMSK2_OCIE2A_BIT)
+#define TIMSK2_OCIE2B_MASK (1 << TIMSK2_OCIE2B_BIT)
+#define TIMSK2_TOIE2 (BIT(m_r[TIMSK2], TIMSK2_TOIE2_BIT))
+#define TIMSK2_OCIE2A (BIT(m_r[TIMSK2], TIMSK2_OCIE2A_BIT))
+#define TIMSK2_OCIE2B (BIT(m_r[TIMSK2], TIMSK2_OCIE2B_BIT))
+
+#define TIFR2_TOV2_SHIFT 0
+#define TIFR2_TOV2_MASK 0x01
+#define TIFR2_OCF2A_SHIFT 1
+#define TIFR2_OCF2A_MASK 0x02
+#define TIFR2_OCF2B_SHIFT 2
+#define TIFR2_OCF2B_MASK 0x04
+#define TIFR2_MASK (TIFR2_TOV2_MASK | TIFR2_OCF2B_MASK | TIFR2_OCF2A_MASK)
+
+#define TIMSK3_TOIE3_BIT 0
+#define TIMSK3_OCIE3A_BIT 1
+#define TIMSK3_OCIE3B_BIT 2
+#define TIMSK3_OCIE3C_BIT 3
+#define TIMSK3_TOIE3 (BIT(m_r[TIMSK3], TIMSK3_TOIE3_BIT))
+#define TIMSK3_OCIE3A (BIT(m_r[TIMSK3], TIMSK3_OCIE3A_BIT))
+#define TIMSK3_OCIE3B (BIT(m_r[TIMSK3], TIMSK3_OCIE3B_BIT))
+#define TIMSK3_OCIE3C (BIT(m_r[TIMSK3], TIMSK3_OCIE3C_BIT))
+
+#define TCCR4B_CS_SHIFT 0
+#define TCCR4B_CS_MASK 0x07
+#define TCCR4B_WGM4_32_SHIFT 3
+#define TCCR4B_WGM4_32_MASK 0x18
+#define TCCR4B_FOC4C_SHIFT 5
+#define TCCR4B_FOC4C_MASK 0x20
+#define TCCR4B_FOC4B_SHIFT 6
+#define TCCR4B_FOC4B_MASK 0x40
+#define TCCR4B_FOC4A_SHIFT 7
+#define TCCR4B_FOC4A_MASK 0x80
+#define TIMER4_CLOCK_SELECT ((m_r[TCCR4B] & TCCR4B_CS_MASK) >> TCCR4B_CS_SHIFT)
+
+#define TCCR4A_WGM4_10_SHIFT 0
+#define TCCR4A_WGM4_10_MASK 0x03
+#define TCCR4A_COM4C_SHIFT 2
+#define TCCR4A_COM4C_MASK 0x0c
+#define TCCR4A_COM4B_SHIFT 4
+#define TCCR4A_COM4B_MASK 0x30
+#define TCCR4A_COM4A_SHIFT 6
+#define TCCR4A_COM4A_MASK 0xc0
+#define TCCR4A_COM4A ((m_r[TCCR4A] & TCCR4A_COM4A_MASK) >> TCCR4A_COM4A_SHIFT)
+#define TCCR4A_COM4B ((m_r[TCCR4A] & TCCR4A_COM4B_MASK) >> TCCR4A_COM4B_SHIFT)
+#define TCCR4A_COM4C ((m_r[TCCR4A] & TCCR4A_COM4C_MASK) >> TCCR4A_COM4C_SHIFT)
+#define TCCR4A_WGM2_10 (m_r[TCCR4A] & TCCR4A_WGM2_10_MASK)
+
+#define WGM4_32 ((m_r[TCCR4B] & TCCR4B_WGM4_32_MASK) >> TCCR4B_WGM4_32_SHIFT)
+#define WGM4_10 ((m_r[TCCR4A] & TCCR4A_WGM4_10_MASK) >> TCCR4A_WGM4_10_SHIFT)
+#define WGM4 ((WGM4_32 << 2) | WGM4_10)
+
+#define TIMSK4_TOIE4_BIT 0
+#define TIMSK4_OCIE4A_BIT 1
+#define TIMSK4_OCIE4B_BIT 2
+#define TIMSK4_TOIE4 (BIT(m_r[TIMSK4], TIMSK4_TOIE4_BIT))
+#define TIMSK4_OCIE4A (BIT(m_r[TIMSK4], TIMSK4_OCIE4A_BIT))
+#define TIMSK4_OCIE4B (BIT(m_r[TIMSK4], TIMSK4_OCIE4B_BIT))
+
+#define TIFR4_TOV4_SHIFT 0
+#define TIFR4_TOV4_MASK 0x01
+#define TIFR4_OCF4A_SHIFT 1
+#define TIFR4_OCF4A_MASK 0x02
+#define TIFR4_OCF4B_SHIFT 2
+#define TIFR4_OCF4B_MASK 0x04
+#define TIFR4_MASK (TIFR4_TOV4_MASK | TIFR4_OCF4B_MASK | TIFR4_OCF4A_MASK)
+
+#define TCCR5C_FOC5C_SHIFT 5
+#define TCCR5C_FOC5C_MASK 0x20
+#define TCCR5C_FOC5B_SHIFT 6
+#define TCCR5C_FOC5B_MASK 0x40
+#define TCCR5C_FOC5A_SHIFT 7
+#define TCCR5C_FOC5A_MASK 0x80
+
+#define TCCR5B_CS_SHIFT 0
+#define TCCR5B_CS_MASK 0x07
+#define TCCR5B_WGM5_32_SHIFT 3
+#define TCCR5B_WGM5_32_MASK 0x18
+#define TCCR5B_ICES5_SHIFT 6
+#define TCCR5B_ICES5_MASK 0x40
+#define TCCR5B_ICNC5_SHIFT 7
+#define TCCR5B_ICNC5_MASK 0x80
+#define TIMER5_CLOCK_SELECT ((m_r[TCCR5B] & TCCR5B_CS_MASK) >> TCCR5B_CS_SHIFT)
+
+#define TCCR5A_WGM5_10_SHIFT 0
+#define TCCR5A_WGM5_10_MASK 0x03
+#define TCCR5A_COM5C_SHIFT 2
+#define TCCR5A_COM5C_MASK 0x0c
+#define TCCR5A_COM5B_SHIFT 4
+#define TCCR5A_COM5B_MASK 0x30
+#define TCCR5A_COM5A_SHIFT 6
+#define TCCR5A_COM5A_MASK 0xc0
+#define TCCR5A_COM5A ((m_r[TCCR5A] & TCCR5A_COM5A_MASK) >> TCCR5A_COM5A_SHIFT)
+#define TCCR5A_COM5B ((m_r[TCCR5A] & TCCR5A_COM5B_MASK) >> TCCR5A_COM5B_SHIFT)
+#define TCCR5A_COM5C ((m_r[TCCR5A] & TCCR5A_COM5C_MASK) >> TCCR5A_COM5C_SHIFT)
+#define TCCR5A_WGM5_10 (m_r[TCCR5A] & TCCR5A_WGM5_10_MASK)
+
+#define WGM5_32 ((m_r[TCCR5B] & TCCR5B_WGM5_32_MASK) >> TCCR5B_WGM5_32_SHIFT)
+#define WGM5_10 ((m_r[TCCR5A] & TCCR5A_WGM5_10_MASK) >> TCCR5A_WGM5_10_SHIFT)
+#define WGM5 ((WGM5_32 << 2) | WGM5_10)
+
+#define TIMSK5_TOIE5_BIT 0
+#define TIMSK5_OCIE5A_BIT 1
+#define TIMSK5_OCIE5B_BIT 2
+#define TIMSK5_OCIE5C_BIT 3
+#define TIMSK5_ICIE5_BIT 5
+#define TIMSK5_TOIE5_MASK (1 << TIMSK5_TOIE5_BIT)
+#define TIMSK5_OCIE5A_MASK (1 << TIMSK5_OCIE5A_BIT)
+#define TIMSK5_OCIE5B_MASK (1 << TIMSK5_OCIE5B_BIT)
+#define TIMSK5_OCIE5C_MASK (1 << TIMSK5_OCIE5C_BIT)
+#define TIMSK5_ICIE5_MASK (1 << TIMSK5_ICIE5_BIT)
+#define TIMSK5_TOIE5 (BIT(m_r[TIMSK5], TIMSK5_TOIE5_BIT))
+#define TIMSK5_OCIE5A (BIT(m_r[TIMSK5], TIMSK5_OCIE5A_BIT))
+#define TIMSK5_OCIE5B (BIT(m_r[TIMSK5], TIMSK5_OCIE5B_BIT))
+#define TIMSK5_OCIE5C (BIT(m_r[TIMSK5], TIMSK5_OCIE5C_BIT))
+#define TIMSK5_ICIE5C (BIT(m_r[TIMSK5], TIMSK5_ICIE5C_BIT))
+
+#define TIFR5_ICF5_MASK 0x20
+#define TIFR5_ICF5_SHIFT 5
+#define TIFR5_OCF5C_MASK 0x08
+#define TIFR5_OCF5C_SHIFT 3
+#define TIFR5_OCF5B_MASK 0x04
+#define TIFR5_OCF5B_SHIFT 2
+#define TIFR5_OCF5A_MASK 0x02
+#define TIFR5_OCF5A_SHIFT 1
+#define TIFR5_TOV5_MASK 0x01
+#define TIFR5_TOV5_SHIFT 0
+#define TIFR5_MASK (TIFR5_ICF5_MASK | TIFR5_OCF5C_MASK | TIFR5_OCF5B_MASK | TIFR5_OCF5A_MASK | TIFR5_TOV5_MASK)
+#define TIFR5_ICF5 ((m_r[TIFR5] & TIFR5_ICF5_MASK) >> TIFR5_ICF5_SHIFT)
+#define TIFR5_OCF5C ((m_r[TIFR5] & TIFR5_OCF5C_MASK) >> TIFR5_OCF5C_SHIFT)
+#define TIFR5_OCF5B ((m_r[TIFR5] & TIFR5_OCF5B_MASK) >> TIFR5_OCF5B_SHIFT)
+#define TIFR5_OCF5A ((m_r[TIFR5] & TIFR5_OCF5A_MASK) >> TIFR5_OCF5A_SHIFT)
+#define TIFR5_TOV5 ((m_r[TIFR5] & TIFR5_TOV5_MASK) >> TIFR5_TOV5_SHIFT)
//---------------------------------------------------------------
-#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 WGM0 (((m_r[TCCR0B] & 0x08) >> 1) | (m_r[TCCR0A] & 0x03))
+
+#define OCR1A ((m_r[OCR1AH] << 8) | m_r[OCR1AL])
+#define OCR1B ((m_r[OCR1BH] << 8) | m_r[OCR1BL])
+#define OCR1C ((m_r[OCR1CH] << 8) | m_r[OCR1CL])
+#define ICR1 ((m_r[ICR1H] << 8) | m_r[ICR1L])
+#define WGM1 (((m_r[TCCR1B] & 0x18) >> 1) | (m_r[TCCR1A] & 0x03))
+
+#define WGM2 (((m_r[TCCR2B] & 0x08) >> 1) | (m_r[TCCR2A] & 0x03))
+
+#define ICR3 ((m_r[ICR3H] << 8) | m_r[ICR3L])
+#define OCR3A ((m_r[OCR3AH] << 8) | m_r[OCR3AL])
+
+#define ICR4 ((m_r[ICR4H] << 8) | m_r[ICR4L])
+#define OCR4A ((m_r[OCR4AH] << 8) | m_r[OCR4AL])
+
+#define ICR5 ((m_r[ICR5H] << 8) | m_r[ICR5L])
+#define OCR5A ((m_r[OCR5AH] << 8) | m_r[OCR5AL])
+
+#define GTCCR_PSRASY_MASK 0x02
+#define GTCCR_PSRASY_SHIFT 1
+
+#define SPSR_SPR2X (m_r[SPSR] & SPSR_SPR2X_MASK)
+
+#define SPCR_SPIE ((m_r[SPCR] & SPCR_SPIE_MASK) >> 7)
+#define SPCR_SPE ((m_r[SPCR] & SPCR_SPE_MASK) >> 6)
+#define SPCR_DORD ((m_r[SPCR] & SPCR_DORD_MASK) >> 5)
+#define SPCR_MSTR ((m_r[SPCR] & SPCR_MSTR_MASK) >> 4)
+#define SPCR_CPOL ((m_r[SPCR] & SPCR_CPOL_MASK) >> 3)
+#define SPCR_CPHA ((m_r[SPCR] & SPCR_CPHA_MASK) >> 2)
+#define SPCR_SPR (m_r[SPCR] & SPCR_SPR_MASK)
+
+#define SPI_RATE ((SPSR_SPR2X << 2) | SPCR_SPR)
+
+#define PORTB_MOSI 0x08
+
+#define EECR_MASK 0x3f
+#define EECR_EERE_BIT 0
+#define EECR_EEPE_BIT 1
+#define EECR_EEMPE_BIT 2
+#define EECR_EERIE_BIT 3
+#define EECR_EEPM_BIT 4
+#define EECR_EERE_MASK (1 << EECR_EERE_BIT)
+#define EECR_EEPE_MASK (1 << EECR_EEPE_BIT)
+#define EECR_EEMPE_MASK (1 << EECR_EEMPE_BIT)
+#define EECR_EERIE_MASK (1 << EECR_EERIE_BIT)
+#define EECR_EEPM_MASK (3 << EECR_EEPM_BIT)
+#define EECR_EERE (BIT(m_r[EECR], EECR_EERE_BIT))
+#define EECR_EEPE (BIT(m_r[EECR], EECR_EEPE_BIT))
+#define EECR_EEMPE (BIT(m_r[EECR], EECR_EEMPE_BIT))
+#define EECR_EERIE (BIT(m_r[EECR], EECR_EERIE_BIT))
+#define EECR_EEPM ((m_r[EECR] & EECR_EEPM_MASK) >> EECR_EEPM_BIT)
//---------------------------------------------------------------
-#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)
+#define ADMUX_MUX_MASK 0x0f
+#define ADMUX_ADLAR_MASK 0x20
+#define ADMUX_REFS_MASK 0xc0
+#define ADMUX_MUX ((m_r[ADMUX] & ADMUX_MUX_MASK) >> 0)
+#define ADMUX_ADLAR ((m_r[ADMUX] & ADMUX_ADLAR_MASK) >> 5)
+#define ADMUX_REFS ((m_r[ADMUX] & ADMUX_REFS_MASK) >> 6)
+
+#define ADCSRB_ACME_MASK 0x40
+#define ADCSRB_ADTS_MASK 0x07
+#define ADCSRB_ACME ((m_r[ADCSRB] & ADCSRB_ACME_MASK) >> 6)
+#define ADCSRB_ADTS ((m_r[ADCSRB] & ADCSRB_ADTS_MASK) >> 0)
+
+#define ADCSRA_ADPS_MASK 0x07
+#define ADCSRA_ADIE_MASK 0x08
+#define ADCSRA_ADIF_MASK 0x10
+#define ADCSRA_ADATE_MASK 0x20
+#define ADCSRA_ADSC_MASK 0x40
+#define ADCSRA_ADEN_MASK 0x80
+#define ADCSRA_ADPS (m_r[ADCSRA] & ADCSRA_ADPS_MASK)
+#define ADCSRA_ADIE ((m_r[ADCSRA] & ADCSRA_ADIE_MASK) >> 3)
+#define ADCSRA_ADIF ((m_r[ADCSRA] & ADCSRA_ADIF_MASK) >> 4)
+#define ADCSRA_ADATE ((m_r[ADCSRA] & ADCSRA_ADATE_MASK) >> 5)
+#define ADCSRA_ADSC ((m_r[ADCSRA] & ADCSRA_ADSC_MASK) >> 6)
+#define ADCSRA_ADEN ((m_r[ADCSRA] & ADCSRA_ADEN_MASK) >> 7)
+
//**************************************************************************
// DEVICE INTERFACE
//**************************************************************************
DEFINE_DEVICE_TYPE(ATMEGA88, atmega88_device, "atmega88", "Atmel ATmega88")
+DEFINE_DEVICE_TYPE(ATMEGA168, atmega168_device, "atmega168", "Atmel ATmega168")
+DEFINE_DEVICE_TYPE(ATMEGA328, atmega328_device, "atmega328", "Atmel ATmega328")
DEFINE_DEVICE_TYPE(ATMEGA644, atmega644_device, "atmega644", "Atmel ATmega644")
DEFINE_DEVICE_TYPE(ATMEGA1280, atmega1280_device, "atmega1280", "Atmel ATmega1280")
DEFINE_DEVICE_TYPE(ATMEGA2560, atmega2560_device, "atmega2560", "Atmel ATmega2560")
+DEFINE_DEVICE_TYPE(ATTINY15, attiny15_device, "attiny15", "Atmel ATtiny15")
//**************************************************************************
// INTERNAL ADDRESS MAP
//**************************************************************************
+template <int NumTimers>
+void avr8_device<NumTimers>::base_internal_map(address_map &map)
+{
+ map(0x0000, 0x01ff).ram().share(m_r);
+ map(0x0020, 0x0020).r(FUNC(avr8_device::pin_r<0>));
+ map(0x0022, 0x0022).rw(FUNC(avr8_device::gpio_r<GPIOA>), FUNC(avr8_device::port_w<GPIOA>));
+ map(0x0023, 0x0023).r(FUNC(avr8_device::pin_r<1>));
+ map(0x0025, 0x0025).rw(FUNC(avr8_device::gpio_r<GPIOB>), FUNC(avr8_device::port_w<GPIOB>));
+ map(0x0026, 0x0026).r(FUNC(avr8_device::pin_r<2>));
+ map(0x0028, 0x0028).rw(FUNC(avr8_device::gpio_r<GPIOC>), FUNC(avr8_device::port_w<GPIOC>));
+ map(0x0029, 0x0029).r(FUNC(avr8_device::pin_r<3>));
+ map(0x002b, 0x002b).rw(FUNC(avr8_device::gpio_r<GPIOD>), FUNC(avr8_device::port_w<GPIOD>));
+ map(0x002c, 0x002c).r(FUNC(avr8_device::pin_r<4>));
+ map(0x002e, 0x002e).rw(FUNC(avr8_device::gpio_r<GPIOE>), FUNC(avr8_device::port_w<GPIOE>));
+ map(0x002f, 0x002f).r(FUNC(avr8_device::pin_r<5>));
+ map(0x0031, 0x0031).rw(FUNC(avr8_device::gpio_r<GPIOF>), FUNC(avr8_device::port_w<GPIOF>));
+ map(0x0032, 0x0032).r(FUNC(avr8_device::pin_r<6>));
+ map(0x0034, 0x0034).rw(FUNC(avr8_device::gpio_r<GPIOG>), FUNC(avr8_device::port_w<GPIOG>));
+ map(0x0035, 0x0035).w(FUNC(avr8_device::tifr0_w));
+ map(0x0036, 0x0036).w(FUNC(avr8_device::tifr1_w));
+ map(0x0037, 0x0037).w(FUNC(avr8_device::tifr2_w));
+ map(0x003e, 0x003e).w(FUNC(avr8_device::gpior0_w));
+ map(0x003f, 0x003f).w(FUNC(avr8_device::eecr_w));
+ map(0x0043, 0x0043).w(FUNC(avr8_device::gtccr_w));
+ map(0x0044, 0x0044).w(FUNC(avr8_device::tccr0a_w));
+ map(0x0045, 0x0045).w(FUNC(avr8_device::tccr0b_w));
+ map(0x0047, 0x0047).w(FUNC(avr8_device::ocr0a_w));
+ map(0x0048, 0x0048).w(FUNC(avr8_device::ocr0b_w));
+ map(0x004a, 0x004a).w(FUNC(avr8_device::gpior1_w));
+ map(0x004b, 0x004b).w(FUNC(avr8_device::gpior2_w));
+ map(0x004c, 0x004c).w(FUNC(avr8_device::spcr_w));
+ map(0x004d, 0x004d).w(FUNC(avr8_device::spsr_w));
+ map(0x004e, 0x004e).w(FUNC(avr8_device::spdr_w));
+ map(0x0060, 0x0060).w(FUNC(avr8_device::wdtcsr_w));
+ map(0x0061, 0x0061).w(FUNC(avr8_device::clkpr_w));
+ map(0x0064, 0x0064).w(FUNC(avr8_device::prr0_w));
+ map(0x0065, 0x0065).w(FUNC(avr8_device::prr1_w));
+ map(0x0066, 0x0066).w(FUNC(avr8_device::osccal_w));
+ map(0x0068, 0x0068).w(FUNC(avr8_device::pcicr_w));
+ map(0x0069, 0x0069).w(FUNC(avr8_device::eicra_w));
+ map(0x006a, 0x006a).w(FUNC(avr8_device::eicrb_w));
+ map(0x006b, 0x006b).w(FUNC(avr8_device::pcmsk0_w));
+ map(0x006c, 0x006c).w(FUNC(avr8_device::pcmsk1_w));
+ map(0x006d, 0x006d).w(FUNC(avr8_device::pcmsk2_w));
+ map(0x006e, 0x006e).w(FUNC(avr8_device::timsk0_w));
+ map(0x006f, 0x006f).w(FUNC(avr8_device::timsk1_w));
+ map(0x0070, 0x0070).w(FUNC(avr8_device::timsk2_w));
+ map(0x0071, 0x0071).w(FUNC(avr8_device::timsk3_w));
+ map(0x0072, 0x0072).w(FUNC(avr8_device::timsk4_w));
+ map(0x0073, 0x0073).w(FUNC(avr8_device::timsk5_w));
+ map(0x0074, 0x0074).w(FUNC(avr8_device::xmcra_w));
+ map(0x0075, 0x0075).w(FUNC(avr8_device::xmcrb_w));
+ map(0x0078, 0x0078).rw(FUNC(avr8_device::adcl_r), FUNC(avr8_device::adcl_w));
+ map(0x0079, 0x0079).rw(FUNC(avr8_device::adch_r), FUNC(avr8_device::adch_w));
+ map(0x007a, 0x007a).w(FUNC(avr8_device::adcsra_w));
+ map(0x007b, 0x007b).w(FUNC(avr8_device::adcsrb_w));
+ map(0x007c, 0x007c).w(FUNC(avr8_device::admux_w));
+ map(0x007d, 0x007d).w(FUNC(avr8_device::didr2_w));
+ map(0x007e, 0x007e).w(FUNC(avr8_device::didr0_w));
+ map(0x007f, 0x007f).w(FUNC(avr8_device::didr1_w));
+ map(0x0080, 0x0080).w(FUNC(avr8_device::tccr1a_w));
+ map(0x0081, 0x0081).w(FUNC(avr8_device::tccr1b_w));
+ map(0x0082, 0x0082).w(FUNC(avr8_device::tccr1c_w));
+ map(0x0086, 0x0086).w(FUNC(avr8_device::icr1l_w));
+ map(0x0087, 0x0087).w(FUNC(avr8_device::icr1h_w));
+ map(0x0088, 0x0088).w(FUNC(avr8_device::ocr1al_w));
+ map(0x0089, 0x0089).w(FUNC(avr8_device::ocr1ah_w));
+ map(0x008a, 0x008a).w(FUNC(avr8_device::ocr1bl_w));
+ map(0x008b, 0x008b).w(FUNC(avr8_device::ocr1bh_w));
+ map(0x008c, 0x008c).w(FUNC(avr8_device::ocr1cl_w));
+ map(0x008d, 0x008d).w(FUNC(avr8_device::ocr1ch_w));
+ map(0x0090, 0x0090).w(FUNC(avr8_device::tccr3a_w));
+ map(0x0091, 0x0091).w(FUNC(avr8_device::tccr3b_w));
+ map(0x0092, 0x0092).w(FUNC(avr8_device::tccr3c_w));
+ map(0x0096, 0x0096).w(FUNC(avr8_device::icr3l_w));
+ map(0x0097, 0x0097).w(FUNC(avr8_device::icr3h_w));
+ map(0x0098, 0x0098).w(FUNC(avr8_device::ocr3al_w));
+ map(0x0099, 0x0099).w(FUNC(avr8_device::ocr3ah_w));
+ map(0x009a, 0x009a).w(FUNC(avr8_device::ocr3bl_w));
+ map(0x009b, 0x009b).w(FUNC(avr8_device::ocr3bh_w));
+ map(0x009c, 0x009c).w(FUNC(avr8_device::ocr3cl_w));
+ map(0x009d, 0x009d).w(FUNC(avr8_device::ocr3ch_w));
+ map(0x00a0, 0x00a0).w(FUNC(avr8_device::tccr4a_w));
+ map(0x00a1, 0x00a1).w(FUNC(avr8_device::tccr4b_w));
+ map(0x00a2, 0x00a2).w(FUNC(avr8_device::tccr4c_w));
+ map(0x00a4, 0x00a4).w(FUNC(avr8_device::tcnt4l_w));
+ map(0x00a5, 0x00a5).w(FUNC(avr8_device::tcnt4h_w));
+ map(0x00a6, 0x00a6).w(FUNC(avr8_device::icr4l_w));
+ map(0x00a7, 0x00a7).w(FUNC(avr8_device::icr4h_w));
+ map(0x00a8, 0x00a8).w(FUNC(avr8_device::ocr4al_w));
+ map(0x00a9, 0x00a9).w(FUNC(avr8_device::ocr4ah_w));
+ map(0x00aa, 0x00aa).w(FUNC(avr8_device::ocr4bl_w));
+ map(0x00ab, 0x00ab).w(FUNC(avr8_device::ocr4bh_w));
+ map(0x00ac, 0x00ac).w(FUNC(avr8_device::ocr4cl_w));
+ map(0x00ad, 0x00ad).w(FUNC(avr8_device::ocr4ch_w));
+ map(0x00b0, 0x00b0).w(FUNC(avr8_device::tccr2a_w));
+ map(0x00b1, 0x00b1).w(FUNC(avr8_device::tccr2b_w));
+ map(0x00b2, 0x00b2).w(FUNC(avr8_device::tcnt2_w));
+ map(0x00b3, 0x00b3).w(FUNC(avr8_device::ocr2a_w));
+ map(0x00b4, 0x00b4).w(FUNC(avr8_device::ocr2b_w));
+ map(0x00b6, 0x00b6).w(FUNC(avr8_device::assr_w));
+ map(0x00b8, 0x00b8).w(FUNC(avr8_device::twbr_w));
+ map(0x00b9, 0x00b9).rw(FUNC(avr8_device::twsr_r), FUNC(avr8_device::twsr_w));
+ map(0x00ba, 0x00ba).w(FUNC(avr8_device::twar_w));
+ map(0x00bb, 0x00bb).w(FUNC(avr8_device::twdr_w));
+ map(0x00bc, 0x00bc).w(FUNC(avr8_device::twcr_w));
+ map(0x00bd, 0x00bd).w(FUNC(avr8_device::twamr_w));
+ map(0x00c0, 0x00c0).w(FUNC(avr8_device::ucsr0a_w));
+ map(0x00c1, 0x00c1).w(FUNC(avr8_device::ucsr0b_w));
+ map(0x00c2, 0x00c2).w(FUNC(avr8_device::ucsr0c_w));
+}
+
void atmega88_device::atmega88_internal_map(address_map &map)
{
- map(0x0000, 0x00ff).rw(FUNC(atmega88_device::regs_r), FUNC(atmega88_device::regs_w));
+ avr8_device::base_internal_map(map);
+}
+
+void atmega168_device::atmega168_internal_map(address_map &map)
+{
+ avr8_device::base_internal_map(map);
+}
+
+void atmega328_device::atmega328_internal_map(address_map &map)
+{
+ avr8_device::base_internal_map(map);
}
void atmega644_device::atmega644_internal_map(address_map &map)
{
- map(0x0000, 0x00ff).rw(FUNC(atmega644_device::regs_r), FUNC(atmega644_device::regs_w));
+ avr8_device::base_internal_map(map);
}
void atmega1280_device::atmega1280_internal_map(address_map &map)
{
- map(0x0000, 0x01ff).rw(FUNC(atmega1280_device::regs_r), FUNC(atmega1280_device::regs_w));
+ avr8_device::base_internal_map(map);
+ map(0x0100, 0x0100).r(FUNC(atmega1280_device::pin_r<7>));
+ map(0x0102, 0x0102).rw(FUNC(atmega1280_device::gpio_r<GPIOH>), FUNC(atmega1280_device::port_w<GPIOH>));
+ map(0x0103, 0x0103).r(FUNC(atmega1280_device::pin_r<8>));
+ map(0x0105, 0x0105).rw(FUNC(atmega1280_device::gpio_r<GPIOJ>),FUNC(atmega1280_device::port_w<GPIOJ>));
+ map(0x0106, 0x0106).r(FUNC(atmega1280_device::pin_r<9>));
+ map(0x0108, 0x0108).rw(FUNC(atmega1280_device::gpio_r<GPIOK>),FUNC(atmega1280_device::port_w<GPIOK>));
+ map(0x0109, 0x0109).r(FUNC(atmega1280_device::pin_r<10>));
+ map(0x010b, 0x010b).rw(FUNC(atmega1280_device::gpio_r<GPIOL>),FUNC(atmega1280_device::port_w<GPIOL>));
+ map(0x0120, 0x0120).w(FUNC(atmega1280_device::tccr5a_w));
+ map(0x0121, 0x0121).w(FUNC(atmega1280_device::tccr5b_w));
}
void atmega2560_device::atmega2560_internal_map(address_map &map)
{
- map(0x0000, 0x01ff).rw(FUNC(atmega2560_device::regs_r), FUNC(atmega2560_device::regs_w));
+ avr8_device::base_internal_map(map);
+ map(0x0100, 0x0100).r(FUNC(atmega2560_device::pin_r<7>));
+ map(0x0102, 0x0102).rw(FUNC(atmega2560_device::gpio_r<GPIOH>), FUNC(atmega2560_device::port_w<GPIOH>));
+ map(0x0103, 0x0103).r(FUNC(atmega2560_device::pin_r<8>));
+ map(0x0105, 0x0105).rw(FUNC(atmega2560_device::gpio_r<GPIOJ>),FUNC(atmega2560_device::port_w<GPIOJ>));
+ map(0x0106, 0x0106).r(FUNC(atmega2560_device::pin_r<9>));
+ map(0x0108, 0x0108).rw(FUNC(atmega2560_device::gpio_r<GPIOK>),FUNC(atmega2560_device::port_w<GPIOK>));
+ map(0x0109, 0x0109).r(FUNC(atmega2560_device::pin_r<10>));
+ map(0x010b, 0x010b).rw(FUNC(atmega2560_device::gpio_r<GPIOL>),FUNC(atmega2560_device::port_w<GPIOL>));
+ map(0x0120, 0x0120).w(FUNC(atmega2560_device::tccr5a_w));
+ map(0x0121, 0x0121).w(FUNC(atmega2560_device::tccr5b_w));
+}
+
+void attiny15_device::attiny15_internal_map(address_map &map)
+{
+ avr8_device::base_internal_map(map);
}
//-------------------------------------------------
@@ -598,7 +713,25 @@ void atmega2560_device::atmega2560_internal_map(address_map &map)
//-------------------------------------------------
atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : avr8_device(mconfig, tag, owner, clock, ATMEGA88, 0x0fff, address_map_constructor(FUNC(atmega88_device::atmega88_internal_map), this), CPU_TYPE_ATMEGA88)
+ : avr8_device<3>(mconfig, tag, owner, clock, ATMEGA88, 0x0fff, address_map_constructor(FUNC(atmega88_device::atmega88_internal_map), this))
+{
+}
+
+//-------------------------------------------------
+// atmega168_device - constructor
+//-------------------------------------------------
+
+atmega168_device::atmega168_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : avr8_device<3>(mconfig, tag, owner, clock, ATMEGA168, 0x1fff, address_map_constructor(FUNC(atmega168_device::atmega168_internal_map), this))
+{
+}
+
+//-------------------------------------------------
+// atmega328_device - constructor
+//-------------------------------------------------
+
+atmega328_device::atmega328_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : avr8_device<3>(mconfig, tag, owner, clock, ATMEGA328, 0x3fff, address_map_constructor(FUNC(atmega328_device::atmega328_internal_map), this))
{
}
@@ -607,7 +740,7 @@ atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag,
//-------------------------------------------------
atmega644_device::atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : avr8_device(mconfig, tag, owner, clock, ATMEGA644, 0xffff, address_map_constructor(FUNC(atmega644_device::atmega644_internal_map), this), CPU_TYPE_ATMEGA644)
+ : avr8_device<3>(mconfig, tag, owner, clock, ATMEGA644, 0x7fff, address_map_constructor(FUNC(atmega644_device::atmega644_internal_map), this))
{
}
@@ -616,7 +749,7 @@ atmega644_device::atmega644_device(const machine_config &mconfig, const char *ta
//-------------------------------------------------
atmega1280_device::atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : avr8_device(mconfig, tag, owner, clock, ATMEGA1280, 0x1ffff, address_map_constructor(FUNC(atmega1280_device::atmega1280_internal_map), this), CPU_TYPE_ATMEGA1280)
+ : avr8_device<6>(mconfig, tag, owner, clock, ATMEGA1280, 0xffff, address_map_constructor(FUNC(atmega1280_device::atmega1280_internal_map), this))
{
}
@@ -625,77 +758,205 @@ atmega1280_device::atmega1280_device(const machine_config &mconfig, const char *
//-------------------------------------------------
atmega2560_device::atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : avr8_device(mconfig, tag, owner, clock, ATMEGA2560, 0x1ffff, address_map_constructor(FUNC(atmega2560_device::atmega2560_internal_map), this), CPU_TYPE_ATMEGA2560)
+ : avr8_device<6>(mconfig, tag, owner, clock, ATMEGA2560, 0x1ffff, address_map_constructor(FUNC(atmega2560_device::atmega2560_internal_map), this))
{
}
//-------------------------------------------------
-// avr8_device - constructor
+// attiny15_device - constructor
//-------------------------------------------------
-avr8_device::avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t addr_mask, address_map_constructor internal_map, uint8_t cpu_type)
+attiny15_device::attiny15_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : avr8_device<2>(mconfig, tag, owner, clock, ATTINY15, 0x01ff, address_map_constructor(FUNC(attiny15_device::attiny15_internal_map), this))
+{
+}
+
+//-------------------------------------------------
+// avr8_base_device - constructor
+//-------------------------------------------------
+
+avr8_base_device::avr8_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t addr_mask, address_map_constructor internal_map)
: cpu_device(mconfig, type, tag, owner, clock)
- , 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(*this, finder_base::DUMMY_TAG)
- , m_cpu_type(cpu_type)
, m_lfuses(0x62)
, m_hfuses(0x99)
- , m_efuses(0xFF)
- , m_lock_bits(0xFF)
+ , m_efuses(0xff)
+ , m_lock_bits(0xff)
+ , m_r(*this, "regs")
, m_pc(0)
+ , m_addr_mask((addr_mask << 1) | 1)
+ , m_interrupt_pending(false)
+{
+}
+
+template <int NumTimers>
+avr8_device<NumTimers>::avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t addr_mask, address_map_constructor internal_map)
+ : avr8_base_device(mconfig, tag, owner, clock, type, addr_mask, internal_map)
+ , m_gpio_out_cb(*this)
+ , m_gpio_in_cb(*this, 0)
+ , m_adc_in_cb(*this, 0)
+ , m_adc_timer(nullptr)
, 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
+ // Fill in default callbacks
+ for (int i = 0; i < 8*4; i++)
+ {
+ m_timer0_ticks[i] = timer_func(&avr8_device<NumTimers>::timer0_tick_default, this);
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ m_timer2_ticks[i] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ }
- 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;
+ // Fill in the mode-specific callbacks
+ for (int i = 0; i < 8; i++)
+ {
+ for (int j = 1; j < 4; j++)
+ {
+ switch (i)
+ {
+ case 0:
+ m_timer0_ticks[(i << 2) + j] = timer_func(&avr8_device<NumTimers>::timer0_tick_norm, this);
+ break;
+ case 1:
+ m_timer0_ticks[(i << 2) + j] = timer_func(&avr8_device<NumTimers>::timer0_tick_pwm_pc, this);
+ break;
+ case 3:
+ m_timer0_ticks[(i << 2) + j] = timer_func(&avr8_device<NumTimers>::timer0_tick_fast_pwm, this);
+ break;
+ case 5:
+ m_timer0_ticks[(i << 2) + j] = timer_func(&avr8_device<NumTimers>::timer0_tick_pwm_pc_cmp, this);
+ break;
+ case 7:
+ m_timer0_ticks[(i << 2) + j] = timer_func(&avr8_device<NumTimers>::timer0_tick_fast_pwm_cmp, this);
+ break;
+ }
+ }
}
-}
+ m_timer0_ticks[(WGM02_CTC_CMP << 2) | 0] = timer_func(&avr8_device<NumTimers>::timer0_tick_ctc_norm, this);
+ m_timer0_ticks[(WGM02_CTC_CMP << 2) | 1] = timer_func(&avr8_device<NumTimers>::timer0_tick_ctc_toggle, this);
+ m_timer0_ticks[(WGM02_CTC_CMP << 2) | 2] = timer_func(&avr8_device<NumTimers>::timer0_tick_ctc_clear, this);
+ m_timer0_ticks[(WGM02_CTC_CMP << 2) | 3] = timer_func(&avr8_device<NumTimers>::timer0_tick_ctc_set, this);
+
+ for (int i = 0; i < 16; i++)
+ {
+ m_timer1_ticks[(WGM1_NORMAL << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_normal, this);
+ m_timer1_ticks[(WGM1_PWM_8_PC << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm8_pc, this);
+ m_timer1_ticks[(WGM1_PWM_9_PC << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm9_pc, this);
+ m_timer1_ticks[(WGM1_PWM_10_PC << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm10_pc, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_8 << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm8, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_9 << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm9, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_10 << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm10, this);
+ m_timer1_ticks[(WGM1_PWM_PFC_ICR << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm_pfc_icr, this);
+ m_timer1_ticks[(WGM1_PWM_PFC_OCR << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm_pfc_ocr, this);
+ m_timer1_ticks[(WGM1_PWM_PC_ICR << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm_pc_icr, this);
+ m_timer1_ticks[(WGM1_PWM_PC_OCR << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_pwm_pc_ocr, this);
+ m_timer1_ticks[(WGM1_CTC_ICR << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_icr, this);
+ m_timer1_ticks[(WGM1_RESERVED << 4) | i] = timer_func(&avr8_device<NumTimers>::timer1_tick_resv, this);
+ }
+
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 0] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_norm_norm, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 1] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_norm_toggle, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 2] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_norm_clear, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 3] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_norm_set, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 4] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_toggle_norm, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 5] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_toggle_toggle, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 6] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_toggle_clear, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 7] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_toggle_set, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 8] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_clear_norm, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 9] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_clear_toggle, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 10] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_clear_clear, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 11] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_clear_set, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 12] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_set_norm, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 13] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_set_toggle, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 14] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_set_clear, this);
+ m_timer1_ticks[(WGM1_CTC_OCR << 4) | 15] = timer_func(&avr8_device<NumTimers>::timer1_tick_ctc_ocr_set_set, this);
+
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 0] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_norm_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 1] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_norm_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 2] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_norm_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 3] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_norm_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 4] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_toggle_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 5] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_toggle_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 6] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_toggle_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 7] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_toggle_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 8] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_clear_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 9] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_clear_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 10] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_clear_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 11] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_clear_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 12] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_set_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 13] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_set_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 14] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_set_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_ICR << 4) | 15] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_icr_set_set, this);
+
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 0] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_norm_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 1] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_norm_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 2] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_norm_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 3] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_norm_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 4] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_toggle_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 5] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_toggle_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 6] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_toggle_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 7] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_toggle_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 8] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_clear_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 9] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_clear_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 10] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_clear_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 11] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_clear_set, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 12] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_set_norm, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 13] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_set_toggle, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 14] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_set_clear, this);
+ m_timer1_ticks[(WGM1_FAST_PWM_OCR << 4) | 15] = timer_func(&avr8_device<NumTimers>::timer1_tick_fast_pwm_ocr_set_set, this);
+
+ m_timer2_ticks[WGM02_NORMAL] = timer_func(&avr8_device<NumTimers>::timer2_tick_norm, this);
+ m_timer2_ticks[WGM02_PWM_PC] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ m_timer2_ticks[WGM02_CTC_CMP] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ m_timer2_ticks[WGM02_FAST_PWM] = timer_func(&avr8_device<NumTimers>::timer2_tick_fast_pwm, this);
+ m_timer2_ticks[WGM02_RESERVED0] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ m_timer2_ticks[WGM02_PWM_PC_CMP] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ m_timer2_ticks[WGM02_RESERVED1] = timer_func(&avr8_device<NumTimers>::timer2_tick_default, this);
+ m_timer2_ticks[WGM02_FAST_PWM_CMP] = timer_func(&avr8_device<NumTimers>::timer2_tick_fast_pwm_cmp, this);
+
+ m_timer0_tick = m_timer0_ticks[0];
+ m_timer1_tick = m_timer1_ticks[0];
+ m_timer2_tick = m_timer2_ticks[0];
+}
//-------------------------------------------------
-// static_set_low_fuses
+// set_low_fuses
//-------------------------------------------------
-void avr8_device::set_low_fuses(const uint8_t byte)
+void avr8_base_device::set_low_fuses(const uint8_t byte)
{
m_lfuses = byte;
}
//-------------------------------------------------
-// static_set_high_fuses
+// set_high_fuses
//-------------------------------------------------
-void avr8_device::set_high_fuses(const uint8_t byte)
+void avr8_base_device::set_high_fuses(const uint8_t byte)
{
m_hfuses = byte;
}
//-------------------------------------------------
-// static_set_extended_fuses
+// set_extended_fuses
//-------------------------------------------------
-void avr8_device::set_extended_fuses(const uint8_t byte)
+void avr8_base_device::set_extended_fuses(const uint8_t byte)
{
m_efuses = byte;
}
//-------------------------------------------------
-// static_set_lock_bits
+// set_lock_bits
//-------------------------------------------------
-void avr8_device::set_lock_bits(const uint8_t byte)
+void avr8_base_device::set_lock_bits(const uint8_t byte)
{
m_lock_bits = byte;
}
@@ -705,10 +966,10 @@ void avr8_device::set_lock_bits(const uint8_t byte)
// instruction
//-------------------------------------------------
-void avr8_device::unimplemented_opcode(uint32_t op)
+void avr8_base_device::unimplemented_opcode(uint32_t op)
{
// machine().debug_break();
- fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_shifted_pc);
+ fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_pc);
}
@@ -717,20 +978,20 @@ void avr8_device::unimplemented_opcode(uint32_t op)
// bytes long
//-------------------------------------------------
-inline bool avr8_device::is_long_opcode(uint16_t op)
+inline bool avr8_base_device::is_long_opcode(uint16_t op)
{
- if((op & 0xf000) == 0x9000)
+ if ((op & 0xf000) == 0x9000)
{
- if((op & 0x0f00) < 0x0400)
+ if ((op & 0x0f00) < 0x0400)
{
- if((op & 0x000f) == 0x0000)
+ if ((op & 0x000f) == 0x0000)
{
return true;
}
}
- else if((op & 0x0f00) < 0x0600)
+ else if ((op & 0x0f00) < 0x0600)
{
- if((op & 0x000f) >= 0x000c)
+ if ((op & 0x000f) >= 0x000c)
{
return true;
}
@@ -743,22 +1004,21 @@ inline bool avr8_device::is_long_opcode(uint16_t op)
// device_start - start up the device
//-------------------------------------------------
-void avr8_device::device_start()
+void avr8_base_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
- state_add(STATE_GENPC, "GENPC", m_shifted_pc).noshow();
- state_add(STATE_GENPCBASE, "CURPC", 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(STATE_GENPC, "GENPC", m_pc).callexport().noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_pc).callexport().noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_r[SREG]).callimport().callexport().formatstr("%8s").noshow();
+ state_add(AVR8_SREG, "STATUS", m_r[SREG]).mask(0xff);
+ state_add(AVR8_PC, "PC", m_pc).mask(m_addr_mask).callexport();
+ state_add(AVR8_SPH, "SPH", m_r[SPH]).mask(0xff);
+ state_add(AVR8_SPL, "SPL", m_r[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);
@@ -793,86 +1053,145 @@ void avr8_device::device_start()
state_add(AVR8_R31, "R31", m_r[31]).mask(0xff);
// register our state for saving
+ save_item(NAME(m_boot_size));
+ save_item(NAME(m_lfuses));
+ save_item(NAME(m_hfuses));
+ save_item(NAME(m_efuses));
+ save_item(NAME(m_lock_bits));
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]));
+
+ // Misc.
save_item(NAME(m_addr_mask));
save_item(NAME(m_interrupt_pending));
- save_item(NAME(m_elapsed_cycles));
+ save_item(NAME(m_opcycles));
// set our instruction counter
set_icountptr(m_icount);
+
+ populate_ops();
+
+ m_add_flag_cache = std::make_unique<uint8_t[]>(0x10000);
+ m_adc_flag_cache = std::make_unique<uint8_t[]>(0x20000);
+ m_sub_flag_cache = std::make_unique<uint8_t[]>(0x10000);
+ m_sbc_flag_cache = std::make_unique<uint8_t[]>(0x40000);
+ m_bool_flag_cache = std::make_unique<uint8_t[]>(0x100);
+ m_shift_flag_cache = std::make_unique<uint8_t[]>(0x10000);
+ populate_add_flag_cache();
+ populate_adc_flag_cache();
+ populate_sub_flag_cache();
+ populate_sbc_flag_cache();
+ populate_bool_flag_cache();
+ populate_shift_flag_cache();
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::device_start()
+{
+ avr8_base_device::device_start();
+
+ m_adc_timer = timer_alloc(FUNC(avr8_device<NumTimers>::adc_conversion_complete), this);
+
+ // Timers
+ save_item(NAME(m_timer_top));
+ save_item(NAME(m_timer_prescale));
+ save_item(NAME(m_timer_prescale_count));
+ save_item(NAME(m_ocr2_not_reached_yet));
+ save_item(NAME(m_ocr1));
+
+ // ADC
+ save_item(NAME(m_adc_sample));
+ save_item(NAME(m_adc_result));
+ save_item(NAME(m_adc_data));
+ save_item(NAME(m_adc_first));
+ save_item(NAME(m_adc_hold));
+
+ // SPI
+ save_item(NAME(m_spi_active));
+ save_item(NAME(m_spi_prescale));
+ save_item(NAME(m_spi_prescale_count));
+ save_item(NAME(m_spi_prescale_countdown));
}
//-------------------------------------------------
// device_reset - reset the device
//-------------------------------------------------
-void avr8_device::device_reset()
+void avr8_base_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;
+ switch ((m_hfuses & (BOOTSZ1 | BOOTSZ0)) >> 1)
+ {
+ case 0:
+ if (m_addr_mask <= 0x3fff) { m_boot_size = 1024; }
+ else if (m_addr_mask <= 0x7fff) { m_boot_size = 2048; }
+ else { m_boot_size = 4096; }
+ break;
+ case 1:
+ if (m_addr_mask <= 0x3fff) { m_boot_size = 512; }
+ else if (m_addr_mask <= 0x7fff) { m_boot_size = 1024; }
+ else { m_boot_size = 2048; }
+ break;
+ case 2:
+ if (m_addr_mask <= 0x3fff) { m_boot_size = 256; }
+ else if (m_addr_mask <= 0x7fff) { m_boot_size = 512; }
+ else { m_boot_size = 1024; }
+ break;
+ case 3:
+ if (m_addr_mask <= 0x3fff) { m_boot_size = 128; }
+ else if (m_addr_mask <= 0x7fff) { m_boot_size = 256; }
+ else { m_boot_size = 512; }
+ break;
+ default:
+ break;
}
- if (m_hfuses & BOOTRST){
- m_shifted_pc = 0x0000;
- logerror("Booting AVR core from address 0x0000\n");
+ if (m_hfuses & BOOTRST)
+ {
+ m_pc = 0x0000;
+ LOGMASKED(LOG_BOOT, "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);
+ m_pc = (m_addr_mask + 1) - 2 * m_boot_size;
+ LOGMASKED(LOG_BOOT, "AVR Boot loader section size: %d words\n", m_boot_size);
}
- for (auto & elem : m_r)
+ for (int i = 0; i < 0x200; i++)
{
- elem = 0;
+ m_r[i] = 0;
}
+ m_interrupt_pending = false;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::device_reset()
+{
+ m_adc_sample = 0;
+ m_adc_result = 0;
+ m_adc_data = 0;
+ m_adc_first = true;
+ m_adc_hold = false;
+
m_spi_active = false;
m_spi_prescale = 0;
m_spi_prescale_count = 0;
- for (int t=0; t<=5; t++){
+ for (int t = 0; t < NumTimers; t++)
+ {
m_timer_top[t] = 0;
- m_timer_increment[t] = 1;
- m_timer_prescale[t] = 0;
+ m_timer_prescale[t] = 0xffff;
m_timer_prescale_count[t] = 0;
}
+ for (int reg = AVR8_REG_A; reg <= AVR8_REG_C; reg++)
+ {
+ m_ocr1[reg] = 0;
+ }
+
m_ocr2_not_reached_yet = true;
- m_interrupt_pending = false;
- m_elapsed_cycles = 0;
}
//-------------------------------------------------
@@ -880,12 +1199,11 @@ void avr8_device::device_reset()
// of the CPU's address spaces
//-------------------------------------------------
-device_memory_interface::space_config_vector avr8_device::memory_space_config() const
+device_memory_interface::space_config_vector avr8_base_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_program_config),
- std::make_pair(AS_DATA, &m_data_config),
- std::make_pair(AS_IO, &m_io_config)
+ std::make_pair(AS_DATA, &m_data_config)
};
}
@@ -895,26 +1213,30 @@ device_memory_interface::space_config_vector avr8_device::memory_space_config()
// for the debugger
//-------------------------------------------------
-void avr8_device::state_string_export(const device_state_entry &entry, std::string &str) const
+void avr8_base_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
switch (entry.index())
{
- case STATE_GENFLAGS:
- str = string_format("%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;
+ case STATE_GENPC:
+ case STATE_GENPCBASE:
+ case AVR8_PC:
+ str = string_format("%05x", m_pc >> 1);
+ break;
+ case STATE_GENFLAGS:
+ str = string_format("%c%c%c%c%c%c%c%c",
+ (m_r[SREG] & 0x80) ? 'I' : '-',
+ (m_r[SREG] & 0x40) ? 'T' : '-',
+ (m_r[SREG] & 0x20) ? 'H' : '-',
+ (m_r[SREG] & 0x10) ? 'S' : '-',
+ (m_r[SREG] & 0x08) ? 'V' : '-',
+ (m_r[SREG] & 0x04) ? 'N' : '-',
+ (m_r[SREG] & 0x02) ? 'Z' : '-',
+ (m_r[SREG] & 0x01) ? 'C' : '-');
+ break;
}
}
-
-std::unique_ptr<util::disasm_interface> avr8_device::create_disassembler()
+std::unique_ptr<util::disasm_interface> avr8_base_device::create_disassembler()
{
return std::make_unique<avr8_disassembler>();
}
@@ -924,21 +1246,21 @@ std::unique_ptr<util::disasm_interface> avr8_device::create_disassembler()
// MEMORY ACCESSORS
//**************************************************************************
-inline void avr8_device::push(uint8_t val)
+inline void avr8_base_device::push(uint8_t val)
{
uint16_t sp = SPREG;
m_data->write_byte(sp, val);
sp--;
- m_r[AVR8_REGIDX_SPL] = sp & 0x00ff;
- m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff;
+ m_r[SPL] = sp & 0x00ff;
+ m_r[SPH] = (sp >> 8) & 0x00ff;
}
-inline uint8_t avr8_device::pop()
+inline uint8_t avr8_base_device::pop()
{
uint16_t sp = SPREG;
sp++;
- m_r[AVR8_REGIDX_SPL] = sp & 0x00ff;
- m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff;
+ m_r[SPL] = sp & 0x00ff;
+ m_r[SPH] = (sp >> 8) & 0x00ff;
return m_data->read_byte(sp);
}
@@ -946,18 +1268,16 @@ inline uint8_t avr8_device::pop()
// IRQ HANDLING
//**************************************************************************
-void avr8_device::set_irq_line(uint16_t vector, int state)
+void avr8_base_device::set_irq_line(uint16_t vector, int state)
{
- // Horrible hack, not accurate
- if(state)
+ if (state)
{
- if(SREG_R(AVR8_SREG_I))
+ if (BIT(m_r[SREG], 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;
+ m_r[SREG] &= ~SREG_MASK_I;
+ push((m_pc >> 1) & 0x00ff);
+ push((m_pc >> 9) & 0x00ff);
+ m_pc = vector << 1;
}
else
{
@@ -966,34 +1286,24 @@ void avr8_device::set_irq_line(uint16_t vector, int state)
}
}
-class CInterruptCondition
+const avr8_base_device::interrupt_condition avr8_base_device::s_int_conditions[avr8_base_device::INTIDX_COUNT] =
{
- public:
- uint8_t m_intindex;
- uint8_t m_intreg;
- uint8_t m_intmask;
- uint8_t m_regindex;
- uint8_t m_regmask;
+ { AVR8_INT_SPI_STC, SPCR, SPCR_SPIE_MASK, SPSR, SPSR_SPIF_MASK },
+ { AVR8_INT_T0COMPB, TIMSK0, TIMSK0_OCIE0B_MASK, TIFR0, TIFR0_OCF0B_MASK },
+ { AVR8_INT_T0COMPA, TIMSK0, TIMSK0_OCIE0A_MASK, TIFR0, TIFR0_OCF0A_MASK },
+ { AVR8_INT_T0OVF, TIMSK0, TIMSK0_TOIE0_MASK, TIFR0, TIFR0_TOV0_MASK },
+ { AVR8_INT_T1CAPT, TIMSK1, TIMSK1_ICIE1_MASK, TIFR1, TIFR1_ICF1_MASK },
+ { AVR8_INT_T1COMPB, TIMSK1, TIMSK1_OCIE1B_MASK, TIFR1, TIFR1_OCF1B_MASK },
+ { AVR8_INT_T1COMPA, TIMSK1, TIMSK1_OCIE1A_MASK, TIFR1, TIFR1_OCF1A_MASK },
+ { AVR8_INT_T1OVF, TIMSK1, TIMSK1_TOIE1_MASK, TIFR1, TIFR1_TOV1_MASK },
+ { AVR8_INT_T2COMPB, TIMSK2, TIMSK2_OCIE2B_MASK, TIFR2, TIFR2_OCF2B_MASK },
+ { AVR8_INT_T2COMPA, TIMSK2, TIMSK2_OCIE2A_MASK, TIFR2, TIFR2_OCF2A_MASK },
+ { AVR8_INT_T2OVF, TIMSK2, TIMSK2_TOIE2_MASK, TIFR2, TIFR2_TOV2_MASK }
};
-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)
+void avr8_base_device::update_interrupt(int source)
{
- const CInterruptCondition &condition = s_int_conditions[source];
+ const interrupt_condition &condition = s_int_conditions[source];
int intstate = 0;
if (m_r[condition.m_intreg] & condition.m_intmask)
@@ -1007,25 +1317,57 @@ void avr8_device::update_interrupt(int source)
}
}
+//TODO: review this!
+void atmega168_device::update_interrupt(int source)
+{
+ const interrupt_condition &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 << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
-static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
+void atmega328_device::update_interrupt(int source)
{
- { 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 }
+ const interrupt_condition &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 << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
+const avr8_base_device::interrupt_condition avr8_base_device::s_mega644_int_conditions[avr8_base_device::INTIDX_COUNT] =
+{
+ { ATMEGA644_INT_SPI_STC, SPCR, SPCR_SPIE_MASK, SPSR, SPSR_SPIF_MASK },
+ { ATMEGA644_INT_T0COMPB, TIMSK0, TIMSK0_OCIE0B_MASK, TIFR0, TIFR0_OCF0B_MASK },
+ { ATMEGA644_INT_T0COMPA, TIMSK0, TIMSK0_OCIE0A_MASK, TIFR0, TIFR0_OCF0A_MASK },
+ { ATMEGA644_INT_T0OVF, TIMSK0, TIMSK0_TOIE0_MASK, TIFR0, TIFR0_TOV0_MASK },
+ { ATMEGA644_INT_T1CAPT, TIMSK1, TIMSK1_ICIE1_MASK, TIFR1, TIFR1_ICF1_MASK },
+ { ATMEGA644_INT_T1COMPB, TIMSK1, TIMSK1_OCIE1B_MASK, TIFR1, TIFR1_OCF1B_MASK },
+ { ATMEGA644_INT_T1COMPA, TIMSK1, TIMSK1_OCIE1A_MASK, TIFR1, TIFR1_OCF1A_MASK },
+ { ATMEGA644_INT_T1OVF, TIMSK1, TIMSK1_TOIE1_MASK, TIFR1, TIFR1_TOV1_MASK },
+ { ATMEGA644_INT_T2COMPB, TIMSK2, TIMSK2_OCIE2B_MASK, TIFR2, TIFR2_OCF2B_MASK },
+ { ATMEGA644_INT_T2COMPA, TIMSK2, TIMSK2_OCIE2A_MASK, TIFR2, TIFR2_OCF2A_MASK },
+ { ATMEGA644_INT_T2OVF, TIMSK2, TIMSK2_TOIE2_MASK, TIFR2, TIFR2_TOV2_MASK }
};
void atmega644_device::update_interrupt(int source)
{
- const CInterruptCondition &condition = s_mega644_int_conditions[source];
+ const interrupt_condition &condition = s_mega644_int_conditions[source];
int intstate = 0;
if (m_r[condition.m_intreg] & condition.m_intmask)
@@ -1042,12 +1384,13 @@ void atmega644_device::update_interrupt(int source)
//TODO: review this!
void atmega1280_device::update_interrupt(int source)
{
- const CInterruptCondition &condition = s_mega644_int_conditions[source];
+ const interrupt_condition &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;
+ if (intstate) logerror("interrupt %d is 1\n", source);
set_irq_line(condition.m_intindex << 1, intstate);
if (intstate)
@@ -1059,12 +1402,13 @@ void atmega1280_device::update_interrupt(int source)
//TODO: review this!
void atmega2560_device::update_interrupt(int source)
{
- const CInterruptCondition &condition = s_mega644_int_conditions[source];
+ const interrupt_condition &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;
+ if (intstate) logerror("interrupt %d is 1\n", source);
set_irq_line(condition.m_intindex << 1, intstate);
if (intstate)
@@ -1075,580 +1419,668 @@ void atmega2560_device::update_interrupt(int source)
//**************************************************************************
-// REGISTER HANDLING
+// PERIPHERAL HANDLING
//**************************************************************************
-void avr8_device::timer_tick(int cycles)
+
+template <int NumTimers>
+void avr8_device<NumTimers>::spi_tick()
+{
+ const uint8_t out_bit = (m_r[SPDR] & (1 << m_spi_prescale_countdown)) >> m_spi_prescale_countdown;
+ m_spi_prescale_countdown--;
+ const uint8_t data = (m_r[PORTB] &~ PORTB_MOSI) | (out_bit ? PORTB_MOSI : 0);
+ m_r[PORTB] = data;
+ m_gpio_out_cb[GPIOB](data);
+ m_r[PORTB] = (m_r[PORTB] &~ PORTB_MOSI) | (out_bit ? PORTB_MOSI : 0);
+}
+
+// Timer 0 Handling
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_norm()
+{
+ LOGMASKED(LOG_TIMER0, "%s: WGM02_NORMAL: Unimplemented timer#0 waveform generation mode\n", machine().describe_context());
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_pwm_pc()
+{
+ LOGMASKED(LOG_TIMER0, "%s: WGM02_PWM_PC: Unimplemented timer#0 waveform generation mode\n", machine().describe_context());
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_ctc_norm()
{
- for(int count = 0; count < cycles; count++)
+ static const uint8_t s_ocf0[2] = { (1 << TIFR0_OCF0A_SHIFT), (1 << TIFR0_OCF0B_SHIFT) };
+ static const uint8_t s_int0[2] = { INTIDX_OCF0A, INTIDX_OCF0B };
+
+ if (m_r[TCNT0] == m_r[OCR0A] - 1)
+ {
+ m_r[TIFR0] |= s_ocf0[AVR8_REG_A];
+ update_interrupt(s_int0[AVR8_REG_A]);
+ m_r[TCNT0] = 0;
+ }
+ else if (m_r[TCNT0] == m_r[OCR0B] - 1)
+ {
+ m_r[TIFR0] |= s_ocf0[AVR8_REG_B];
+ update_interrupt(s_int0[AVR8_REG_B]);
+ m_r[TCNT0]++;
+ }
+ else
{
- m_elapsed_cycles++;
+ m_r[TCNT0]++;
+ }
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
- 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_t 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;
- }
- }
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_ctc_toggle()
+{
+ if (m_r[TCNT0] == m_timer_top[0] - 1)
+ {
+ m_timer_top[0] = 0;
+ LOGMASKED(LOG_TIMER0, "%s: timer0: Toggle OC0B on match\n", machine().describe_context());
+ m_r[PORTG] ^= (1 << 5);
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
+ }
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
- 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];
- }
- }
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_ctc_clear()
+{
+ if (m_r[TCNT0] == m_timer_top[0])
+ {
+ m_timer_top[0] = 0;
+ LOGMASKED(LOG_TIMER0, "[0] timer0: Clear OC0B on match\n", machine().describe_context());
+ m_r[PORTG] &= ~(1 << 5);
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
}
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_ctc_set()
+{
+ if (m_r[TCNT0] == m_timer_top[0])
+ {
+ m_timer_top[0] = 0;
+ LOGMASKED(LOG_TIMER0, "%s: timer0: Set OC0B on match\n", machine().describe_context());
+ m_r[PORTG] |= (1 << 5);
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
}
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
}
-// uint8_t ocr0[2] = { m_r[AVR8_REGIDX_OCR0A], m_r[AVR8_REGIDX_OCR0B] };
-//TODO uint8_t ocf0[2] = { (1 << AVR8_TIFR0_OCF0A_SHIFT), (1 << AVR8_TIFR4_OCF0B_SHIFT) };
-//TODO uint8_t int0[2] = { AVR8_INTIDX_OCF0A, AVR8_INTIDX_OCF0B };
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_fast_pwm()
+{
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
-#define LOG_TIMER_0 0
-#define LOG_TIMER_5 0
-// Timer 0 Handling
-void avr8_device::timer0_tick()
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_pwm_pc_cmp()
{
-#if LOG_TIMER_0
- printf("AVR8_WGM0: %d\n", AVR8_WGM0);
- printf("AVR8_TCCR0A_COM0B: %d\n", AVR8_TCCR0A_COM0B);
-#endif
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_PWM_PC_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
- uint8_t count = m_r[AVR8_REGIDX_TCNT0];
- int32_t increment = m_timer_increment[0];
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_fast_pwm_cmp()
+{
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_tick_default()
+{
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: timer0_tick_default: Unknown waveform generation mode: %02x\n", machine().describe_context(), WGM0);
+ m_r[TCNT0]++;
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer0_force_output_compare(int reg)
+{
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: timer0_force_output_compare: TODO; should be forcing OC0%c\n", machine().describe_context(), 'A' + reg);
+ m_timer_prescale_count[0] -= m_timer_prescale[0];
+}
- switch(AVR8_WGM0)
+template <int NumTimers>
+void avr8_device<NumTimers>::update_ocr0(uint8_t newval, uint8_t reg)
+{
+ m_r[(reg == AVR8_REG_A) ? OCR0A : OCR0B] = newval;
+}
+
+// Timer 1 Handling
+
+template <int NumTimers>
+template <int TimerMode, int ChannelModeA, int ChannelModeB>
+inline void avr8_device<NumTimers>::timer1_tick()
+{
+ static const uint8_t s_ocf1[2] = { (1 << TIFR1_OCF1A_SHIFT), (1 << TIFR1_OCF1B_SHIFT) };
+ static const uint8_t s_int1[2] = { INTIDX_OCF1A, INTIDX_OCF1B };
+ const uint16_t icr1 = ICR1;
+ uint16_t timer1_count = (m_r[TCNT1H] << 8) | m_r[TCNT1L];
+ int32_t increment = 1;
+
+ switch (TimerMode)
{
- case WGM02_NORMAL:
- //printf("WGM02_NORMAL: Unimplemented timer#0 waveform generation mode\n");
- break;
+ case WGM1_CTC_OCR:
+ if (timer1_count == 0xffff)
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 CTC_OCR, TOP, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ m_r[TIFR1] |= TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
+ timer1_count = 0;
+ increment = 0;
+ }
- case WGM02_PWM_PC:
- //printf("WGM02_PWM_PC: Unimplemented timer#0 waveform generation mode\n");
- break;
+ if (timer1_count == m_ocr1[AVR8_REG_A])
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 CTC_OCR, OCR1A, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ timer1_count = 0;
+ increment = 0;
- 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));
+ switch (ChannelModeA)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ break;
+
+ case 1: /* Toggle OC1A on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A on match\n", machine().describe_context());
+ m_r[PORTB] ^= 2;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1A on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_A);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1A on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_A;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
}
- break;
+
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_A];
+ update_interrupt(s_int1[AVR8_REG_A]);
+ }
+ else if (timer1_count == 0)
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 CTC_OCR, BOTTOM, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ m_r[TIFR1] &= ~TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
}
- break;
- case WGM02_FAST_PWM:
- printf("WGM02_FAST_PWM: Unimplemented timer#0 waveform generation mode\n");
- break;
+ if (timer1_count == m_ocr1[AVR8_REG_B])
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 CTC_OCR, OCR1B, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ switch (ChannelModeB)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ case 1: /* Toggle OC1A on compare match */
+ break;
- case WGM02_PWM_PC_CMP:
- printf("WGM02_PWM_PC_CMP: Unimplemented timer#0 waveform generation mode\n");
- break;
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1B on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_B);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1B on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_B;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
- case WGM02_FAST_PWM_CMP:
- printf("WGM02_FAST_PWM_CMP: Unimplemented timer#0 waveform generation mode\n");
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_B];
+ update_interrupt(s_int1[AVR8_REG_B]);
+ }
break;
- default:
- verboselog(m_pc, 0, "update_timer0_compare_mode: Unknown waveform generation mode: %02x\n", AVR8_WGM0);
- break;
- }
+ case WGM1_FAST_PWM_OCR:
+ if (timer1_count == m_ocr1[AVR8_REG_A])
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_OCR, OCR1A, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ m_r[TIFR1] |= TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
+ timer1_count = 0;
+ increment = 0;
- count = count & 0xff;
+ switch (ChannelModeA)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ break;
- count += increment;
- m_r[AVR8_REGIDX_TCNT0] = count & 0xff;
-}
+ case 1: /* Toggle OC1A on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A on match\n", machine().describe_context());
+ m_r[PORTB] ^= 2;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
-void avr8_device::changed_tccr0a(uint8_t data)
-{
- uint8_t oldtccr = AVR8_TCCR0A;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1A on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_A);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- AVR8_TCCR0A = data;
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1A on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_A;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
- if(changed & AVR8_TCCR0A_WGM0_10_MASK)
- {
- update_timer_waveform_gen_mode(0, AVR8_WGM0);
- }
-}
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_A];
+ update_interrupt(s_int1[AVR8_REG_A]);
+ }
+ else if (timer1_count == 0)
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_OCR, BOTTOM A, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ m_r[TIFR1] &= ~TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
-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]);
-}
+ switch (ChannelModeA)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ break;
-void avr8_device::changed_tccr0b(uint8_t data)
-{
- if (VERBOSE_LEVEL) printf("changed_tccr0b: data=0x%02X\n", data);
+ case 1: /* Toggle OC1A at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] ^= 2;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- uint8_t oldtccr = AVR8_TCCR0B;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
+ case 2: /* Set OC1A/B at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_A;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- AVR8_TCCR0B = data;
+ case 3: /* Clear OC1A/B at BOTTOM */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_A);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
+ }
- if(changed & AVR8_TCCR0B_FOC0A_MASK)
- {
- // TODO
- timer0_force_output_compare(AVR8_REG_A);
- }
+ if (timer1_count == m_ocr1[AVR8_REG_B])
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_OCR, OCR1B, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ switch (ChannelModeB)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ case 1: /* Toggle OC1A on compare match */
+ break;
- if(changed & AVR8_TCCR0B_FOC0B_MASK)
- {
- // TODO
- timer0_force_output_compare(AVR8_REG_B);
- }
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1B on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_B);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- if(changed & AVR8_TCCR0B_WGM0_2_MASK)
- {
- update_timer_waveform_gen_mode(0, AVR8_WGM0);
- }
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1B on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_B;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
- if(changed & AVR8_TCCR0B_CS_MASK)
- {
- update_timer_clock_source(0, AVR8_TIMER0_CLOCK_SELECT);
- }
-}
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_B];
+ update_interrupt(s_int1[AVR8_REG_B]);
+ }
+ else if (timer1_count == 0)
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_OCR, BOTTOM B, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ switch (ChannelModeB)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ case 1: /* Toggle OC1A at BOTTOM*/
+ break;
-void avr8_device::update_ocr0(uint8_t newval, uint8_t reg)
-{
- m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR0A : AVR8_REGIDX_OCR0B] = newval;
-}
+ case 2: /* Set OC1A/B at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1B at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_B;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
-// Timer 1 Handling
+ case 3: /* Clear OC1A/B at BOTTOM */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1B at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_B);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
+ }
+ break;
-void avr8_device::timer1_tick()
-{
- /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */
+ case WGM1_FAST_PWM_ICR:
+ if (timer1_count == m_ocr1[AVR8_REG_A])
+ {
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_ICR, OCR1A, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ switch (ChannelModeA)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ break;
- uint16_t count = (m_r[AVR8_REGIDX_TCNT1H] << 8) | m_r[AVR8_REGIDX_TCNT1L];
- int32_t wgm1 = ((m_r[AVR8_REGIDX_TCCR1B] & AVR8_TCCR1B_WGM1_32_MASK) >> 1) |
- (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_WGM1_10_MASK);
+ case 1: /* Toggle OC1A on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A on match\n", machine().describe_context());
+ m_r[PORTB] ^= 2;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer
- //uint8_t 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_t ocr1[2] = { static_cast<uint16_t>((m_r[AVR8_REGIDX_OCR1AH] << 8) | m_r[AVR8_REGIDX_OCR1AL]),
- static_cast<uint16_t>((m_r[AVR8_REGIDX_OCR1BH] << 8) | m_r[AVR8_REGIDX_OCR1BL]) };
- uint8_t ocf1[2] = { (1 << AVR8_TIFR1_OCF1A_SHIFT), (1 << AVR8_TIFR1_OCF1B_SHIFT) };
- uint8_t int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B };
- int32_t increment = m_timer_increment[1];
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1A on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_A);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- for(int32_t reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++)
- {
- switch(wgm1)
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1A on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_A;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
+
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_A];
+ update_interrupt(s_int1[AVR8_REG_A]);
+ }
+ else if (timer1_count == 0)
{
- 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;
- }
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1 WGM1 FAST_PWM_ICR, BOTTOM A, new count %04x, OCR1A/B %04x/%04x, ICR1 %04x\n", machine().describe_context(), timer1_count, m_ocr1[AVR8_REG_A], m_ocr1[AVR8_REG_B], icr1);
+ m_r[TIFR1] &= ~TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
- 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);
- }
+ switch (ChannelModeA)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ break;
- m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg];
- update_interrupt(int1[reg]);
- }
+ case 1: /* Toggle OC1A at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] ^= 2;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
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;
- }
+ case 2: /* Set OC1A/B at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_A;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
- 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);
- }
+ case 3: /* Clear OC1A/B at BOTTOM */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1A at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_A);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
+ }
- m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg];
- update_interrupt(int1[reg]);
- }
+ if (timer1_count == m_ocr1[AVR8_REG_B])
+ {
+ switch (ChannelModeB)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ case 1: /* Toggle OC1A on compare match */
+ break;
+
+ case 2: /* Clear OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1B on match\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_B);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
break;
- default:
- verboselog(m_pc, 0, "update_timer1_compare_mode: Unknown waveform generation mode: %02x\n", wgm1);
+ case 3: /* Set OC1A/B on compare match */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1B on match\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_B;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
break;
+ }
+
+ m_r[TIFR1] |= s_ocf1[AVR8_REG_B];
+ update_interrupt(s_int1[AVR8_REG_B]);
}
- /*
- switch(compare_mode[reg])
+ else if (timer1_count == 0)
{
- case 0:
- //verboselog(m_pc, 0, "update_timer1_compare_mode: Normal port operation (OC1 disconnected)\n");
- break;
+ switch (ChannelModeB)
+ {
+ case 0: /* Normal Operation; OC1A/B disconnected */
+ case 1: /* Toggle OC1A at BOTTOM*/
+ break;
- case 1:
- case 2:
- // TODO
- break;
+ case 2: /* Set OC1A/B at BOTTOM*/
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1B at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] |= 2 << AVR8_REG_B;
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+
+ case 3: /* Clear OC1A/B at BOTTOM */
+ LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1B at BOTTOM\n", machine().describe_context());
+ m_r[PORTB] &= ~(2 << AVR8_REG_B);
+ m_gpio_out_cb[GPIOB](m_r[PORTB]);
+ break;
+ }
+ }
- case 3:
- break;
+ if (timer1_count == icr1)
+ {
+ m_r[TIFR1] |= TIFR1_TOV1_MASK;
+ update_interrupt(INTIDX_TOV1);
+ timer1_count = 0;
+ increment = 0;
}
- */
+ break;
+
+ default:
+ LOGMASKED(LOG_TIMER1 | LOG_UNKNOWN, "%s: timer1_tick: Unknown waveform generation mode: %02x\n", machine().describe_context(), WGM1);
+ break;
}
- count += increment;
- m_r[AVR8_REGIDX_TCNT1H] = (count >> 8) & 0xff;
- m_r[AVR8_REGIDX_TCNT1L] = count & 0xff;
+ timer1_count += increment;
+ m_timer_prescale_count[1] -= m_timer_prescale[1];
+
+ m_r[TCNT1H] = timer1_count >> 8;
+ m_r[TCNT1L] = (uint8_t)timer1_count;
}
-void avr8_device::update_timer_waveform_gen_mode(uint8_t t, uint8_t mode)
+template <int NumTimers>
+void avr8_device<NumTimers>::update_timer_waveform_gen_mode(uint8_t t, uint8_t mode)
{
int32_t oc_val = -1, ic_val = -1;
-
- switch (t){
+ switch (t)
+ {
case 0:
- oc_val = AVR8_OCR0A;
+ oc_val = m_r[OCR0A];
ic_val = -1;
break;
case 1:
- oc_val = AVR8_OCR1A;
- ic_val = AVR8_ICR1;
+ oc_val = OCR1A;
+ ic_val = ICR1;
break;
case 2:
- oc_val = AVR8_OCR2A;
+ oc_val = OCR2A;
ic_val = -1;
break;
case 3:
- oc_val = AVR8_OCR3A;
- ic_val = AVR8_ICR3;
+ oc_val = OCR3A;
+ ic_val = ICR3;
break;
case 4:
- oc_val = AVR8_OCR4A;
- ic_val = AVR8_ICR4;
+ oc_val = OCR4A;
+ ic_val = ICR4;
break;
case 5:
- oc_val = AVR8_OCR5A;
- ic_val = AVR8_ICR5;
+ oc_val = OCR5A;
+ ic_val = ICR5;
break;
}
- int32_t top_values_02[8] = {0xFF, 0xFF, oc_val, 0xFF, -1, oc_val, -1, oc_val}; //table 20-8
+ static const int32_t s_top_values_02[8] =
+ {
+ 0xff, 0xff, oc_val, 0xff, -1, oc_val, -1, oc_val
+ }; //table 20-8
- int32_t 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
+ static const int32_t s_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){
+ switch (t)
+ {
case 0:
case 2:
- m_timer_top[t] = top_values_02[mode];
+ m_timer_top[t] = s_top_values_02[mode];
break;
case 1:
case 3:
case 4:
case 5:
- m_timer_top[t] = top_values_1345[mode];
+ m_timer_top[t] = s_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_t data)
-{
- uint8_t oldtccr = AVR8_TCCR1A;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
-
- m_r[AVR8_REGIDX_TCCR1A] = newtccr;
-
- if(changed & AVR8_TCCR1A_WGM1_10_MASK)
+ if (m_timer_top[t] == -1)
{
- update_timer_waveform_gen_mode(1, AVR8_WGM1);
+ m_timer_top[t] = 0;
+ LOGMASKED((LOG_TIMER0 << t), "%s: update_timer_waveform_gen_mode: Timer %d - Unsupported waveform generation type: %d\n", machine().describe_context(), t, mode);
}
}
-void avr8_device::update_timer1_input_noise_canceler()
+template <int NumTimers>
+void avr8_device<NumTimers>::update_timer1_input_noise_canceler()
{
- // TODO
+ LOGMASKED(LOG_TIMER1 | LOG_UNKNOWN, "%s: update_timer1_input_noise_canceler: TODO\n", machine().describe_context());
}
-void avr8_device::update_timer1_input_edge_select()
+template <int NumTimers>
+void avr8_device<NumTimers>::update_timer1_input_edge_select()
{
- // TODO
- //verboselog(m_pc, 0, "update_timer1_input_edge_select: TODO; Clocking edge is %s\n", "test");
+ LOGMASKED(LOG_TIMER1 | LOG_UNKNOWN, "%s: update_timer1_input_edge_select: TODO\n", machine().describe_context());
}
-void avr8_device::changed_tccr1b(uint8_t data)
+template <int NumTimers>
+void avr8_device<NumTimers>::update_ocr1(uint16_t newval, uint8_t reg)
{
- if (VERBOSE_LEVEL) printf("changed_tccr1b: data=0x%02X\n", data);
-
- uint8_t oldtccr = AVR8_TCCR1B;
- uint8_t newtccr = data;
- uint8_t 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();
- }
+ static const int32_t s_high_indices[3] = { OCR1AH, OCR1BH, OCR1CH };
+ static const int32_t s_low_indices[3] = { OCR1AL, OCR1BL, OCR1CL };
+ m_r[s_high_indices[reg]] = (uint8_t)(newval >> 8);
+ m_r[s_low_indices[reg]] = (uint8_t)newval;
+ m_ocr1[reg] = newval;
+}
- if(changed & AVR8_TCCR1B_WGM1_32_MASK)
- {
- update_timer_waveform_gen_mode(1, AVR8_WGM1);
- }
+// Timer 2 Handling
- if(changed & AVR8_TCCR1B_CS_MASK)
- {
- update_timer_clock_source(1, AVR8_TIMER1_CLOCK_SELECT);
- }
+template <int NumTimers>
+void avr8_device<NumTimers>::timer2_tick_default()
+{
+ LOGMASKED(LOG_TIMER2, "%s: WGM02_PWM_PC: Unimplemented timer#2 waveform generation mode %d\n", machine().describe_context(), WGM2);
+ m_r[TCNT2]++;
+ m_timer_prescale_count[2] -= m_timer_prescale[2];
}
-void avr8_device::update_ocr1(uint16_t newval, uint8_t reg)
+template <int NumTimers>
+void avr8_device<NumTimers>::timer2_tick_norm()
{
- uint8_t *p_reg_h = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AH] : &m_r[AVR8_REGIDX_OCR1BH];
- uint8_t *p_reg_l = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AL] : &m_r[AVR8_REGIDX_OCR1BL];
- *p_reg_h = (uint8_t)(newval >> 8);
- *p_reg_l = (uint8_t)newval;
-
- // Nothing needs to be done? All handled in timer callback
+ LOGMASKED(LOG_TIMER2, "%s: timer2_tick_norm; WGM02_NORMAL\n", machine().describe_context());
+ if (m_r[TCNT2] == 0xff)
+ {
+ m_r[TIFR2] |= TIFR2_TOV2_MASK;
+ }
+ m_r[TCNT2]++;
+ update_interrupt(INTIDX_TOV2);
+ m_timer_prescale_count[2] -= m_timer_prescale[2];
}
-// Timer 2 Handling
-
-void avr8_device::timer2_tick()
+template <int NumTimers>
+void avr8_device<NumTimers>::timer2_tick_fast_pwm()
{
- uint16_t count = m_r[AVR8_REGIDX_TCNT2];
- int32_t 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_t 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_t ocr2[2] = { m_r[AVR8_REGIDX_OCR2A], m_r[AVR8_REGIDX_OCR2B] };
- uint8_t ocf2[2] = { (1 << AVR8_TIFR2_OCF2A_SHIFT), (1 << AVR8_TIFR2_OCF2B_SHIFT) };
- int32_t increment = m_timer_increment[2];
-
- for(int32_t reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++)
+ if (m_r[TCNT2] >= m_r[OCR2A])
{
- switch(wgm2)
+ if (m_r[TCNT2] >= 0xff)
{
- 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;
+ // Turn on
+ m_r[PORTD] |= 1 << 7;
+ m_gpio_out_cb[GPIOD](m_r[PORTD]);
+ m_r[TCNT2] = 0;
+ m_ocr2_not_reached_yet = true;
}
- /*
- switch(compare_mode[reg])
+ else
{
- 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;
+ if (m_ocr2_not_reached_yet)
+ {
+ // Turn off
+ m_r[PORTD] &= ~(1 << 7);
+ m_gpio_out_cb[GPIOD](m_r[PORTD]);
+ m_ocr2_not_reached_yet = false;
+ }
}
- */
}
- m_r[AVR8_REGIDX_TCNT2] += increment;
-
- update_interrupt(AVR8_INTIDX_OCF2A);
- update_interrupt(AVR8_INTIDX_OCF2B);
- update_interrupt(AVR8_INTIDX_TOV2);
+ m_r[TCNT2]++;
+ m_timer_prescale_count[2] -= m_timer_prescale[2];
}
-void avr8_device::changed_tccr2a(uint8_t data)
+template <int NumTimers>
+void avr8_device<NumTimers>::timer2_tick_fast_pwm_cmp()
{
- uint8_t oldtccr = AVR8_TCCR2A;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t ocf2[2] = { (1 << TIFR2_OCF2A_SHIFT), (1 << TIFR2_OCF2B_SHIFT) };
+ uint16_t count = m_r[TCNT2];
- AVR8_TCCR2A = data;
+ int32_t increment = 1;
- if(changed & AVR8_TCCR2A_WGM2_10_MASK)
+ if (count == m_r[OCR2A])
{
- // TODO
- update_timer_waveform_gen_mode(2, AVR8_WGM2);
+ m_r[TIFR2] |= TIFR2_TOV2_MASK;
+ count = 0;
+ increment = 0;
+ m_r[TIFR2] |= ocf2[AVR8_REG_A];
}
-}
-
-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_t data)
-{
- if (VERBOSE_LEVEL) printf("changed_tccr2b: data=0x%02X\n", data);
-
- uint8_t oldtccr = AVR8_TCCR2B;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
-
- AVR8_TCCR2B = data;
-
- if(changed & AVR8_TCCR2B_FOC2A_MASK)
+ else if (count == 0)
{
- // TODO
- timer2_force_output_compare(AVR8_REG_A);
+ m_r[TIFR2] &= ~TIFR2_TOV2_MASK;
}
- if(changed & AVR8_TCCR2B_FOC2B_MASK)
+ if (count == m_r[OCR2B])
{
- // TODO
- timer2_force_output_compare(AVR8_REG_B);
+ m_r[TIFR2] |= ocf2[AVR8_REG_B];
}
- if(changed & AVR8_TCCR2B_WGM2_2_MASK)
- {
- update_timer_waveform_gen_mode(2, AVR8_WGM2);
- }
+ count += increment;
- if(changed & AVR8_TCCR2B_CS_MASK)
- {
- update_timer_clock_source(2, AVR8_TIMER2_CLOCK_SELECT);
- }
+ update_interrupt(INTIDX_TOV2);
+ m_r[TCNT2] = count;
+ m_timer_prescale_count[2] -= m_timer_prescale[2];
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer2_force_output_compare(int reg)
+{
+ LOGMASKED(LOG_TIMER2 | LOG_UNKNOWN, "%s: force_output_compare: TODO; should be forcing OC2%c\n", machine().describe_context(), 'A' + reg);
}
-void avr8_device::update_ocr2(uint8_t newval, uint8_t reg)
+template <int NumTimers>
+void avr8_device<NumTimers>::update_ocr2(uint8_t newval, uint8_t reg)
{
- m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR2A : AVR8_REGIDX_OCR2B] = newval;
+ m_r[(reg == AVR8_REG_A) ? OCR2A : OCR2B] = newval;
// Nothing needs to be done? All handled in timer callback
}
@@ -1656,210 +2088,139 @@ void avr8_device::update_ocr2(uint8_t newval, uint8_t reg)
/************************************************************************************************/
// Timer 3 Handling
-void avr8_device::timer3_tick()
+template <int NumTimers>
+void avr8_device<NumTimers>::timer3_tick()
{
}
/************************************************************************************************/
-void avr8_device::timer4_tick()
+template <int NumTimers>
+void avr8_device<NumTimers>::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_t 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_t 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_t ocr4[2] = { static_cast<uint16_t>((m_r[AVR8_REGIDX_OCR4AH] << 8) | m_r[AVR8_REGIDX_OCR4AL]),
- static_cast<uint16_t>((m_r[AVR8_REGIDX_OCR4BH] << 8) | m_r[AVR8_REGIDX_OCR4BL]) };
-//TODO uint8_t ocf4[2] = { (1 << AVR8_TIFR4_OCF4A_SHIFT), (1 << AVR8_TIFR4_OCF4B_SHIFT) };
-//TODO uint8_t int4[2] = { AVR8_INTIDX_OCF4A, AVR8_INTIDX_OCF4B };
- int32_t 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){
+ LOGMASKED(LOG_TIMER4_TICK, "%s: WGM4: %d\n", machine().describe_context(), WGM4);
+ LOGMASKED(LOG_TIMER4_TICK, "%s: TCCR4A_COM4B: %d\n", machine().describe_context(), TCCR4A_COM4B);
+
+ uint16_t count = (m_r[TCNT4H] << 8) | m_r[TCNT4L];
+ int32_t increment = 1;
+
+ switch (WGM4)
+ {
+ case WGM4_FAST_PWM_8:
+ case WGM4_FAST_PWM_9:
+ case WGM4_FAST_PWM_10:
+ switch (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));
+ if (count == m_timer_top[4])
+ {
+ // Clear OC0B
+ LOGMASKED(LOG_TIMER4, "%s: timer4: non-inverting mode, Clear OC0B\n", machine().describe_context());
+ m_r[PORTG] &= ~(1 << 5);
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
+ }
+ else if (count == 0)
+ {
+ // Set OC0B
+ LOGMASKED(LOG_TIMER4, "%s: timer4: non-inverting mode, Set OC0B\n", machine().describe_context());
+ m_r[PORTG] |= 1 << 5;
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
}
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));
+ if (count == m_timer_top[4])
+ {
+ // Set OC0B
+ LOGMASKED(LOG_TIMER4, "%s: timer4: inverting mode, Clear OC0B\n", machine().describe_context());
+ m_r[PORTG] |= 1 << 5;
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
+ }
+ else if (count == 0)
+ {
+ // Clear OC0B
+ LOGMASKED(LOG_TIMER4, "%s: timer4: inverting mode, Set OC0B\n", machine().describe_context());
+ m_r[PORTG] &= ~(1 << 5);
+ m_gpio_out_cb[GPIOG](m_r[PORTG]);
}
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;
- }
+ case WGM4_CTC_OCR:
+ LOGMASKED(LOG_TIMER4, "%s: timer4: tick WGM4_CTC_OCR: %d\n", machine().describe_context(), count);
+ if (count == 0xffff)
+ {
+ m_r[TIFR4] |= TIFR4_TOV4_MASK;
+ update_interrupt(INTIDX_TOV4);
+ count = 0;
+ increment = 0;
+ }
- if (count == ocr4[0]) /*TODO: test for all 3 register*/
- {}
- else if (count == 0)
- {}
- break;
+ /* TODO: test for match against all 3 registers */
+ break;
- case WGM1_FAST_PWM_OCR:
- if(count == ocr4[0]) /*TODO: test for all 3 register*/
- {}
- else if(count == 0)
- {}
- break;
+ case WGM1_FAST_PWM_OCR:
+ /* TODO: test for match against all 3 registers */
+ break;
- default:
- verboselog(m_pc, 0, "update_timer4_compare_mode: Unknown waveform generation mode: %02x\n", AVR8_WGM4);
- break;
+ default:
+ LOGMASKED(LOG_TIMER4 | LOG_UNKNOWN, "%s: timer4_tick: Unknown waveform generation mode: %02x\n", machine().describe_context(), 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 t, uint8_t 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_t data)
-{
- //TODO: Implement-me
-// AVR8_TCCR3A = data;
-}
-
-void avr8_device::changed_tccr3b(uint8_t data)
-{
- printf("IMPLEMENT-ME: changed_tccr4b: data=0x%02X\n", data);
-}
-
-void avr8_device::changed_tccr3c(uint8_t data)
-{
-// uint8_t oldtccr = AVR8_TCCR3C;
-// uint8_t newtccr = data;
-// uint8_t changed = newtccr ^ oldtccr;
- printf("IMPLEMENT-ME: changed_tccr3c: data=0x%02X\n", data);
-
-// AVR8_TCCR3C = data;
-
- //TODO: Implement-me
+ m_r[TCNT4H] = (count >> 8) & 0xff;
+ m_r[TCNT4L] = count & 0xff;
}
-void avr8_device::changed_tccr4a(uint8_t data)
+template <int NumTimers>
+template <int Timer>
+void avr8_device<NumTimers>::update_timer_clock_source(uint8_t clock_select, const uint8_t old_clock_select)
{
- uint8_t oldtccr = AVR8_TCCR4A;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
-
- AVR8_TCCR4A = data;
-
- if(changed & AVR8_TCCR4A_WGM4_10_MASK)
+ static const int32_t s_prescale_values[2][8] =
{
- update_timer_waveform_gen_mode(4, AVR8_WGM4);
- }
-}
-
-void avr8_device::changed_tccr4b(uint8_t data)
-{
- printf("changed_tccr4b: data=0x%02X\n", data);
-
- uint8_t oldtccr = AVR8_TCCR4B;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
-
- AVR8_TCCR4B = data;
+ { 0x0000ffff, 1, 8, 64, 256, 1024, -1, -1 }, // T0/T1/T3/T4/T5
+ { 0x0000ffff, 1, 8, 32, 64, 128, 256, 1024 } // T2
+ };
+ const int32_t prescale_divisor = s_prescale_values[(Timer == 2) ? 1 : 0][clock_select];
+ const uint16_t old_prescale = s_prescale_values[(Timer == 2) ? 1 : 0][old_clock_select];
+ m_timer_prescale[Timer] = (uint16_t)prescale_divisor;
- if(changed & AVR8_TCCR4B_FOC4A_MASK)
- {
- // TODO
-// timer4_force_output_compare(AVR8_REG_A);
- }
+ LOGMASKED(LOG_TIMER0 << Timer, "%s: update_timer_clock_source: t = %d, cs = %d\n", machine().describe_context(), Timer, clock_select);
- if(changed & AVR8_TCCR4B_FOC4B_MASK)
+ if (prescale_divisor == -1)
{
- // TODO
-// timer4_force_output_compare(AVR8_REG_B);
+ LOGMASKED(LOG_TIMER0 << Timer, "%s: timer%d: update_timer_clock_source: External trigger mode not implemented yet\n", machine().describe_context(), Timer);
+ m_timer_prescale[Timer] = 0xffff;
}
- if(changed & AVR8_TCCR4B_WGM4_32_MASK)
+ if (old_prescale == 0xffff || m_timer_prescale_count[Timer] > m_timer_prescale[Timer])
{
- update_timer_waveform_gen_mode(4, AVR8_WGM4);
+ m_timer_prescale_count[Timer] = m_timer_prescale[Timer];
}
-
- if(changed & AVR8_TCCR4B_CS_MASK)
- {
- update_timer_clock_source(4, AVR8_TIMER4_CLOCK_SELECT);
- }
-}
-
-void avr8_device::changed_tccr4c(uint8_t data)
-{
-// uint8_t oldtccr = AVR8_TCCR4C;
-// uint8_t newtccr = data;
-// uint8_t changed = newtccr ^ oldtccr;
-
- AVR8_TCCR4C = data;
-
- //TODO: Implement-me
}
/************************************************************************************************/
// Timer 5 Handling
-void avr8_device::timer5_tick()
+
+template <int NumTimers>
+void avr8_device<NumTimers>::timer5_tick()
{
-#if LOG_TIMER_5
- printf("AVR8_WGM5: %d\n", AVR8_WGM5);
- printf("AVR8_TCCR5A_COM5B: %d\n", AVR8_TCCR5A_COM5B);
-#endif
+ LOGMASKED(LOG_TIMER5_TICK, "%s: WGM5: %d\n", machine().describe_context(), WGM5);
+ LOGMASKED(LOG_TIMER5_TICK, "%s: TCCR5A_COM5B: %d\n", machine().describe_context(), TCCR5A_COM5B);
- uint16_t count = (AVR8_TCNT5H << 8) + AVR8_TCNT5L;
- int32_t increment = m_timer_increment[5];
+ uint16_t count = (m_r[TCNT5H] << 8) + m_r[TCNT5L];
+ int32_t increment = 1;
- switch(AVR8_WGM5)
+ switch (WGM5)
{
- case WGM5_NORMAL:
+ case WGM5_NORMAL:
case WGM5_PWM_8_PC:
case WGM5_PWM_9_PC:
case WGM5_PWM_10_PC:
@@ -1874,209 +2235,223 @@ void avr8_device::timer5_tick()
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;
+ LOGMASKED(LOG_TIMER5 | LOG_UNKNOWN, "%s: Unimplemented timer5 waveform generation mode: WGM5 = 0x%02X\n", machine().describe_context(), WGM5);
+ break;
- case WGM5_CTC_OCR:
- //TODO: verify this! Can be very wrong!!!
- switch(AVR8_TCCR5A_COM5B){
+ case WGM5_CTC_OCR:
+ // TODO: Please verify, might be wrong
+ switch (TCCR5A_COM5B)
+ {
case 0: /* Normal Operation */
- if (count == m_timer_top[5]){
- m_timer_top[5] = 0;
+ 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));
+ if (count == m_timer_top[5])
+ {
+ m_timer_top[5] = 0;
+ LOGMASKED(LOG_TIMER5, "%s: timer5: Toggle OC5B on compare match\n", machine().describe_context());
+ m_r[PORTL] ^= 1 << 4;
+ m_gpio_out_cb[GPIOL](m_r[PORTL]);
}
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));
+ if (count == m_timer_top[5])
+ {
+ m_timer_top[5] = 0;
+ // Clear OC5B
+ LOGMASKED(LOG_TIMER5, "%s: timer5: Clear OC5B on compare match\n", machine().describe_context());
+ m_r[PORTL] &= ~(1 << 4);
+ m_gpio_out_cb[GPIOL](m_r[PORTL]);
}
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));
+ if (count == m_timer_top[5])
+ {
+ m_timer_top[5] = 0;
+ LOGMASKED(LOG_TIMER5, "%s: timer5: Set OC5B on compare match\n", machine().describe_context());
+ m_r[PORTL] |= 1 << 4;
+ m_gpio_out_cb[GPIOL](m_r[PORTL]);
}
break;
}
break;
- default:
- printf("Timer #5: Unknown waveform generation mode: %02x\n", AVR8_WGM5);
- break;
+ default:
+ LOGMASKED(LOG_TIMER5 | LOG_UNKNOWN, "%s: timer5: Unknown waveform generation mode: %02x\n", machine().describe_context(), WGM5);
+ break;
}
count += increment;
- m_r[AVR8_REGIDX_TCNT5H] = (count >> 8) & 0xff;
- m_r[AVR8_REGIDX_TCNT5L] = count & 0xff;
+ m_r[TCNT5H] = (count >> 8) & 0xff;
+ m_r[TCNT5L] = count & 0xff;
}
-void avr8_device::changed_tccr5a(uint8_t data)
-{
- uint8_t oldtccr = AVR8_TCCR5A;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
+/************************************************************************************************/
- AVR8_TCCR5A = data;
- if(changed & AVR8_TCCR5A_WGM5_10_MASK)
- {
- update_timer_waveform_gen_mode(5, AVR8_WGM5);
- }
-}
+/****************/
+/* ADC Handling */
+/****************/
-void avr8_device::changed_tccr5b(uint8_t data)
+template <int NumTimers>
+void avr8_device<NumTimers>::adc_start_conversion()
{
- printf("changed_tccr5b: data=0x%02X\n", data);
-
- uint8_t oldtccr = AVR8_TCCR5B;
- uint8_t newtccr = data;
- uint8_t changed = newtccr ^ oldtccr;
-
- AVR8_TCCR5B = data;
+ // set capture in progress flag
+ m_r[ADCSRA] |= ADCSRA_ADSC_MASK;
- if(changed & AVR8_TCCR5C_FOC5A_MASK)
+ // get a sample - the sample-and-hold circuit will hold this for the duration of the conversion
+ if (ADMUX_MUX < 0x8)
{
- // TODO
-// timer5_force_output_compare(AVR8_REG_A);
+ m_adc_sample = m_adc_in_cb[ADMUX_MUX]() & 0x3ff;
}
-
- if(changed & AVR8_TCCR5C_FOC5B_MASK)
+ else if (ADMUX_MUX == 0xe)
{
- // TODO
-// timer5_force_output_compare(AVR8_REG_B);
+ // 1.1V (Vbg)
+ // FIXME: the value this acquires depends on what the reference source is set to
+ logerror("%s: Using unimplemented 1.1V reference voltage as ADC input\n", machine().describe_context());
+ m_adc_sample = 0x3ff;
}
-
- if(changed & AVR8_TCCR5C_FOC5C_MASK)
+ else if (ADMUX_MUX == 0x0f)
{
- // TODO
-// timer5_force_output_compare(AVR8_REG_C);
+ // 0V (GND)
+ m_adc_sample = 0;
}
-
- if(changed & AVR8_TCCR5B_WGM5_32_MASK)
+ else
{
- update_timer_waveform_gen_mode(5, AVR8_WGM5);
+ logerror("%s: Using reserved ADC input 0x%X\n", machine().describe_context(), ADMUX_MUX);
+ m_adc_sample = 0;
}
- if(changed & AVR8_TCCR5B_CS_MASK)
- {
- update_timer_clock_source(5, AVR8_TIMER5_CLOCK_SELECT);
- }
+ // wait for conversion to complete
+ int const scale = 1 << std::max(ADCSRA_ADPS, 1);
+ m_adc_timer->adjust(attotime::from_ticks((m_adc_first ? 25 : 13) * scale, clock()));
}
-/************************************************************************************************/
+template <int NumTimers>
+TIMER_CALLBACK_MEMBER(avr8_device<NumTimers>::adc_conversion_complete)
+{
+ // set conversion result
+ m_adc_result = m_adc_sample;
+ if (!m_adc_hold)
+ m_adc_data = m_adc_result;
+
+ // clear conversion in progress flag, set conversion interrupt flag
+ m_r[ADCSRA] &= ~ADCSRA_ADSC_MASK;
+ m_r[ADCSRA] |= ADCSRA_ADIF_MASK;
+
+ // trigger another conversion if appropriate
+ if (ADCSRA_ADATE && (ADCSRB_ADTS == 0))
+ adc_start_conversion();
+}
+/************************************************************************************************/
/****************/
/* SPI Handling */
/****************/
-void avr8_device::enable_spi()
+template <int NumTimers>
+void avr8_device<NumTimers>::enable_spi()
{
// TODO
}
-void avr8_device::disable_spi()
+template <int NumTimers>
+void avr8_device<NumTimers>::disable_spi()
{
// TODO
}
-void avr8_device::spi_update_masterslave_select()
+template <int NumTimers>
+void avr8_device<NumTimers>::spi_update_masterslave_select()
{
// TODO
}
-void avr8_device::spi_update_clock_polarity()
+template <int NumTimers>
+void avr8_device<NumTimers>::spi_update_clock_polarity()
{
// TODO
}
-void avr8_device::spi_update_clock_phase()
+template <int NumTimers>
+void avr8_device<NumTimers>::spi_update_clock_phase()
{
// TODO
}
-const uint8_t avr8_device::spi_clock_divisor[8] = { 4, 16, 64, 128, 2, 8, 32, 64 };
-
-void avr8_device::spi_update_clock_rate()
+template <int NumTimers>
+void avr8_device<NumTimers>::spi_update_clock_rate()
{
- m_spi_prescale = spi_clock_divisor[AVR8_SPI_RATE];
+ static const uint8_t s_spi_clock_divisor[8] =
+ {
+ 4, 16, 64, 128, 2, 8, 32, 64
+ };
+ m_spi_prescale = s_spi_clock_divisor[SPI_RATE];
m_spi_prescale_count &= m_spi_prescale - 1;
}
-void avr8_device::change_spcr(uint8_t data)
+template <int NumTimers>
+void avr8_device<NumTimers>::change_spcr(uint8_t data)
{
- uint8_t oldspcr = AVR8_SPCR;
+ uint8_t oldspcr = m_r[SPCR];
uint8_t newspcr = data;
uint8_t changed = newspcr ^ oldspcr;
uint8_t high_to_low = ~newspcr & oldspcr;
uint8_t low_to_high = newspcr & ~oldspcr;
- AVR8_SPCR = data;
+ m_r[SPCR] = data;
- if(changed & AVR8_SPCR_SPIE_MASK)
+ if (changed & SPCR_SPIE_MASK)
{
// Check for SPI interrupt condition
- update_interrupt(AVR8_INTIDX_SPI);
+ update_interrupt(INTIDX_SPI);
}
- if(low_to_high & AVR8_SPCR_SPE_MASK)
+ if (low_to_high & SPCR_SPE_MASK)
{
enable_spi();
}
- else if(high_to_low & AVR8_SPCR_SPE_MASK)
+ else if (high_to_low & SPCR_SPE_MASK)
{
disable_spi();
}
- if(changed & AVR8_SPCR_MSTR_MASK)
+ if (changed & SPCR_MSTR_MASK)
{
spi_update_masterslave_select();
}
- if(changed & AVR8_SPCR_CPOL_MASK)
+ if (changed & SPCR_CPOL_MASK)
{
spi_update_clock_polarity();
}
- if(changed & AVR8_SPCR_CPHA_MASK)
+ if (changed & SPCR_CPHA_MASK)
{
spi_update_clock_phase();
}
- if(changed & AVR8_SPCR_SPR_MASK)
+ if (changed & SPCR_SPR_MASK)
{
spi_update_clock_rate();
}
}
-void avr8_device::change_spsr(uint8_t data)
+template <int NumTimers>
+void avr8_device<NumTimers>::change_spsr(uint8_t data)
{
- uint8_t oldspsr = AVR8_SPSR;
+ uint8_t oldspsr = m_r[SPSR];
uint8_t newspsr = data;
uint8_t changed = newspsr ^ oldspsr;
- AVR8_SPSR &= ~1;
- AVR8_SPSR |= data & 1;
+ m_r[SPSR] &= ~1;
+ m_r[SPSR] |= data & 1;
- if(changed & AVR8_SPSR_SPR2X_MASK)
+ if (changed & SPSR_SPR2X_MASK)
{
spi_update_clock_rate();
}
@@ -2084,1808 +2459,1065 @@ void avr8_device::change_spsr(uint8_t data)
/*****************************************************************************/
-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;
+template <int NumTimers>
+template <int Port>
+uint8_t avr8_device<NumTimers>::gpio_r()
+{
+ static constexpr uint16_t PORT_TO_REG[11] =
+ {
+ PORTA,
+ PORTB,
+ PORTC,
+ PORTD,
+ PORTE,
+ PORTF,
+ PORTG,
+ PORTH,
+ PORTJ,
+ PORTK,
+ PORTL
+ };
+ static constexpr char PORT_CHARS[GPIO_COUNT] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L' };
+ LOGMASKED(LOG_GPIO, "%s: Huh%c(%d) Read: %02x\n", machine().describe_context(), PORT_CHARS[Port], Port, m_r[PORT_TO_REG[Port]]);
+ return m_r[PORT_TO_REG[Port]];
+}
- case AVR8_REGIDX_PORTA:
- m_io->write_byte(AVR8_IO_PORTA, data);
- m_r[AVR8_REGIDX_PORTA] = data;
- break;
+template <int NumTimers>
+template <int Port>
+uint8_t avr8_device<NumTimers>::pin_r()
+{
+ static constexpr char PORT_CHARS[GPIO_COUNT] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L' };
+ // TODO: account for DDRH
+ const uint8_t data = m_gpio_in_cb[Port]();
+ LOGMASKED(LOG_GPIO, "%s: PIN%c(%d) Read: %02x\n", machine().describe_context(), PORT_CHARS[Port], Port, data);
+ return data;
+}
- case AVR8_REGIDX_PORTB:
- m_io->write_byte(AVR8_IO_PORTB, data);
- m_r[AVR8_REGIDX_PORTB] = data;
- break;
+template <int NumTimers>
+template <int Port>
+void avr8_device<NumTimers>::port_w(uint8_t data)
+{
+ static constexpr char PORT_CHARS[GPIO_COUNT] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L' };
+ static constexpr uint16_t PORT_TO_REG[11] =
+ {
+ PORTA,
+ PORTB,
+ PORTC,
+ PORTD,
+ PORTE,
+ PORTF,
+ PORTG,
+ PORTH,
+ PORTJ,
+ PORTK,
+ PORTL
+ };
- case AVR8_REGIDX_PORTC:
- m_io->write_byte(AVR8_IO_PORTC, data);
- m_r[AVR8_REGIDX_PORTC] = data;
- break;
+ LOGMASKED(LOG_GPIO, "%s: PORT%c Write: %02x\n", machine().describe_context(), PORT_CHARS[Port], data);
+ m_r[PORT_TO_REG[Port]] = data;
+ LOGMASKED(LOG_GPIO, "%s: PORT%c Write, XYZ m_r[%d[%d]] = %02x\n", machine().describe_context(), PORT_CHARS[Port], PORT_TO_REG[Port], Port, data);
+ m_gpio_out_cb[Port](data);
+}
- case AVR8_REGIDX_PORTD:
- m_io->write_byte(AVR8_IO_PORTD, data);
- m_r[AVR8_REGIDX_PORTD] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr0a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: TCCR0A = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR0A];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ m_r[TCCR0A] = data;
- case AVR8_REGIDX_PORTE:
- m_io->write_byte(AVR8_IO_PORTE, data);
- m_r[AVR8_REGIDX_PORTE] = data;
- break;
+ if (changed & TCCR0A_WGM0_10_MASK)
+ {
+ update_timer_waveform_gen_mode(0, WGM0);
+ }
- case AVR8_REGIDX_PORTF:
- m_io->write_byte(AVR8_IO_PORTF, data);
- m_r[AVR8_REGIDX_PORTF] = data;
- break;
+ m_timer0_tick = m_timer0_ticks[(WGM0 << 2) | TCCR0A_COM0B];
+}
- case AVR8_REGIDX_PORTG:
- m_io->write_byte(AVR8_IO_PORTG, data);
- m_r[AVR8_REGIDX_PORTG] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr0b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: TCCR0B = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR0B];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t oldcs = m_r[TCCR0B] & TCCR0B_CS_MASK;
- case AVR8_REGIDX_PORTH:
- m_io->write_byte(AVR8_IO_PORTH, data);
- m_r[AVR8_REGIDX_PORTH] = data;
- break;
+ m_r[TCCR0B] = data;
- case AVR8_REGIDX_PORTJ:
- m_io->write_byte(AVR8_IO_PORTJ, data);
- m_r[AVR8_REGIDX_PORTJ] = data;
- break;
+ if (changed & TCCR0B_FOC0A_MASK)
+ {
+ // TODO
+ timer0_force_output_compare(AVR8_REG_A);
+ }
- case AVR8_REGIDX_PORTK:
- m_io->write_byte(AVR8_IO_PORTK, data);
- m_r[AVR8_REGIDX_PORTK] = data;
- break;
+ if (changed & TCCR0B_FOC0B_MASK)
+ {
+ // TODO
+ timer0_force_output_compare(AVR8_REG_B);
+ }
- case AVR8_REGIDX_PORTL:
- m_io->write_byte(AVR8_IO_PORTL, data);
- m_r[AVR8_REGIDX_PORTL] = data;
- break;
+ if (changed & TCCR0B_WGM0_2_MASK)
+ {
+ update_timer_waveform_gen_mode(0, WGM0);
+ }
- 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;
+ if (changed & TCCR0B_CS_MASK)
+ {
+ update_timer_clock_source<0>(TIMER0_CLOCK_SELECT, oldcs);
+ }
- case AVR8_REGIDX_TCCR0B:
- verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data );
- changed_tccr0b(data);
- break;
+ m_timer0_tick = m_timer0_ticks[(WGM0 << 2) | TCCR0A_COM0B];
+}
- case AVR8_REGIDX_TCCR0A:
- verboselog(m_pc, 0, "AVR8: TCCR0A = %02x\n", data );
- changed_tccr0a(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr0a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: OCR0A = %02x\n", machine().describe_context(), data);
+ update_ocr0(data, AVR8_REG_A);
+}
- case AVR8_REGIDX_OCR0A:
- verboselog(m_pc, 0, "AVR8: OCR0A = %02x\n", data);
- update_ocr0(AVR8_OCR0A, AVR8_REG_A);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr0b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: OCR0B = %02x\n", machine().describe_context(), data);
+ update_ocr0(data, AVR8_REG_B);
+}
- case AVR8_REGIDX_OCR0B:
- verboselog(m_pc, 0, "AVR8: OCR0B = %02x\n", data );
- update_ocr0(AVR8_OCR0B, AVR8_REG_B);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tifr0_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: TIFR0 = %02x\n", machine().describe_context(), data);
+ m_r[TIFR0] &= ~(data & TIFR0_MASK);
+ update_interrupt(INTIDX_OCF0A);
+ update_interrupt(INTIDX_OCF0B);
+ update_interrupt(INTIDX_TOV0);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::tifr1_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: TIFR1 = %02x\n", machine().describe_context(), data);
+ m_r[TIFR1] &= ~(data & TIFR1_MASK);
+ update_interrupt(INTIDX_ICF1);
+ update_interrupt(INTIDX_OCF1A);
+ update_interrupt(INTIDX_OCF1B);
+ update_interrupt(INTIDX_TOV1);
+}
- case AVR8_REGIDX_TCNT0:
- AVR8_TCNT0 = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tifr2_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER2, "%s: TIFR2 = %02x\n", machine().describe_context(), data);
+ m_r[TIFR2] &= ~(data & TIFR2_MASK);
+ update_interrupt(INTIDX_OCF2A);
+ update_interrupt(INTIDX_OCF2B);
+ update_interrupt(INTIDX_TOV2);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::gtccr_w(uint8_t data)
+{
+ if (data & GTCCR_PSRASY_MASK)
+ {
+ data &= ~GTCCR_PSRASY_MASK;
+ m_timer_prescale_count[2] = 0;
+ }
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::eecr_w(uint8_t data)
+{
+ m_r[EECR] = data & EECR_MASK;
- case AVR8_REGIDX_GTCCR:
- if (data & AVR8_GTCCR_PSRASY_MASK)
- {
- data &= ~AVR8_GTCCR_PSRASY_MASK;
- m_timer_prescale_count[2] = 0;
- }
- break;
+ if (data & EECR_EERE_MASK)
+ {
+ uint16_t addr = (m_r[EEARH] & EEARH_MASK) << 8;
+ addr |= m_r[EEARL];
+ m_r[EEDR] = m_eeprom[addr];
+ LOGMASKED(LOG_EEPROM, "%s: EEPROM read @ %04x data = %02x\n", machine().describe_context(), addr, m_eeprom[addr]);
+ }
+ if ((data & EECR_EEPE_MASK) && (data & EECR_EEMPE_MASK))
+ {
+ uint16_t addr = (m_r[EEARH] & EEARH_MASK) << 8;
+ addr |= m_r[EEARL];
+ m_eeprom[addr] = m_r[EEDR];
+ LOGMASKED(LOG_EEPROM, "%s: EEPROM write @ %04x data = %02x ('%c')\n", machine().describe_context(), addr, m_eeprom[addr], m_eeprom[addr] >= 0x21 ? m_eeprom[addr] : ' ');
+
+ // Indicate that we've finished writing a value to the EEPROM.
+ // TODO: this should only happen after a certain dalay.
+ m_r[EECR] = data & ~EECR_EEPE_MASK;
+ }
+}
-// EEPROM registers:
- case AVR8_REGIDX_EEARL:
- case AVR8_REGIDX_EEARH:
- case AVR8_REGIDX_EEDR:
- m_r[offset] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::gpior0_w(uint8_t data)
+{
+ LOGMASKED(LOG_GPIO, "%s: GPIOR0 Write: %02x\n", machine().describe_context(), data);
+ m_r[GPIOR0] = data;
+}
- case AVR8_REGIDX_EECR:
- m_r[offset] = data;
+template <int NumTimers>
+void avr8_device<NumTimers>::gpior1_w(uint8_t data)
+{
+ LOGMASKED(LOG_GPIO, "%s: GPIOR1 Write: %02x\n", machine().describe_context(), data);
+ m_r[GPIOR1] = data;
+}
- if (data & AVR8_EECR_EERE_MASK)
- {
- uint16_t 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_t 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]);
+template <int NumTimers>
+void avr8_device<NumTimers>::gpior2_w(uint8_t data)
+{
+ LOGMASKED(LOG_GPIO, "%s: GPIOR2 Write: %02x\n", machine().describe_context(), data);
+ m_r[GPIOR2] = data;
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::spsr_w(uint8_t data)
+{
+ change_spsr(data);
+}
- case AVR8_REGIDX_GPIOR0:
- verboselog(m_pc, 1, "AVR8: GPIOR0 Write: %02x\n", data);
- m_r[AVR8_REGIDX_GPIOR0] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::spcr_w(uint8_t data)
+{
+ change_spcr(data);
+}
- case AVR8_REGIDX_GPIOR1:
- case AVR8_REGIDX_GPIOR2:
- m_r[offset] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::spdr_w(uint8_t data)
+{
+ m_r[SPDR] = data;
+ m_spi_active = true;
+ m_spi_prescale_countdown = 7;
+ m_spi_prescale_count = 0;
+}
- case AVR8_REGIDX_SPSR:
- change_spsr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::wdtcsr_w(uint8_t data)
+{
+ LOGMASKED(LOG_WDOG, "%s: (not yet implemented) WDTCSR = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_SPCR:
- change_spcr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::clkpr_w(uint8_t data)
+{
+ LOGMASKED(LOG_CLOCK, "%s: (not yet implemented) CLKPR = %02x\n", machine().describe_context(), data);
+}
- 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;
- }
+template <int NumTimers>
+void avr8_device<NumTimers>::prr0_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PRR0 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_WDTCSR:
- verboselog(m_pc, 0, "AVR8: WDTCSR = %02x\n", data );
- //TODO: changed_wdtcsr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::prr1_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PRR1 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_CLKPR:
- verboselog(m_pc, 0, "AVR8: CLKPR = %02x\n", data );
- //TODO: changed_clkpr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::osccal_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) OSCCAL = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_PRR0:
- verboselog(m_pc, 0, "AVR8: PRR0 = %02x\n", data );
- //TODO: changed_prr0(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::pcicr_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PCICR = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_PRR1:
- verboselog(m_pc, 0, "AVR8: PRR1 = %02x\n", data );
- //TODO: changed_prr1(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::eicra_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) EICRA = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_OSCCAL:
- verboselog(m_pc, 0, "AVR8: OSCCAL = %02x\n", data );
- //TODO: changed_osccal(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::eicrb_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) EICRB = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_PCICR:
- verboselog(m_pc, 0, "AVR8: PCICR = %02x\n", data );
- //TODO: changed_pcicr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::pcmsk0_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PCMSK0 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_EICRA:
- verboselog(m_pc, 0, "AVR8: EICRA = %02x\n", data );
- //TODO: changed_eicra(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::pcmsk1_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PCMSK1 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_EICRB:
- verboselog(m_pc, 0, "AVR8: EICRB = %02x\n", data );
- //TODO: changed_eicrb(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::pcmsk2_w(uint8_t data)
+{
+ LOGMASKED(LOG_POWER, "%s: (not yet implemented) PCMSK2 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_PCMSK0:
- verboselog(m_pc, 0, "AVR8: PCMSK0 = %02x\n", data );
- //TODO: changed_pcmsk0(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk0_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER0, "%s: TIMSK0 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK0] = data;
+ update_interrupt(INTIDX_OCF0A);
+ update_interrupt(INTIDX_OCF0B);
+ update_interrupt(INTIDX_TOV0);
+}
- case AVR8_REGIDX_PCMSK1:
- verboselog(m_pc, 0, "AVR8: PCMSK1 = %02x\n", data );
- //TODO: changed_pcmsk1(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk1_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: TIMSK1 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK1] = data;
+ update_interrupt(INTIDX_ICF1);
+ update_interrupt(INTIDX_OCF1A);
+ update_interrupt(INTIDX_OCF1B);
+ update_interrupt(INTIDX_TOV1);
+}
- case AVR8_REGIDX_PCMSK2:
- verboselog(m_pc, 0, "AVR8: PCMSK2 = %02x\n", data );
- //TODO: changed_pcmsk2(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk2_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER2, "%s: TIMSK2 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK2] = data;
+ update_interrupt(INTIDX_OCF2A);
+ update_interrupt(INTIDX_OCF2B);
+ update_interrupt(INTIDX_TOV2);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk3_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER3, "%s: TIMSK3 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK3] = data;
+ update_interrupt(INTIDX_OCF3A);
+ update_interrupt(INTIDX_OCF3B);
+ update_interrupt(INTIDX_TOV3);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk4_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER4, "%s: TIMSK4 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK4] = data;
+ update_interrupt(INTIDX_OCF4A);
+ update_interrupt(INTIDX_OCF4B);
+ update_interrupt(INTIDX_TOV4);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::timsk5_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER5, "%s: TIMSK5 = %02x\n", machine().describe_context(), data);
+ m_r[TIMSK5] = data;
+ update_interrupt(INTIDX_OCF5A);
+ update_interrupt(INTIDX_OCF5B);
+ update_interrupt(INTIDX_TOV5);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::xmcra_w(uint8_t data)
+{
+ LOGMASKED(LOG_EXTMEM, "%s: (not yet implemented) XMCRA = %02x\n", machine().describe_context(), data);
+}
- 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;
+template <int NumTimers>
+void avr8_device<NumTimers>::xmcrb_w(uint8_t data)
+{
+ LOGMASKED(LOG_EXTMEM, "%s: (not yet implemented) XMCRB = %02x\n", machine().describe_context(), data);
+}
- 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;
+template <int NumTimers>
+uint8_t avr8_device<NumTimers>::adcl_r()
+{
+ if (!machine().side_effects_disabled())
+ m_adc_hold = true;
+ if (ADMUX_ADLAR)
+ return (m_adc_data & 0x03) << 6;
+ else
+ return uint8_t(m_adc_data);
+}
- case AVR8_REGIDX_XMCRA:
- verboselog(m_pc, 0, "AVR8: XMCRA = %02x\n", data );
- //TODO: changed_xmcra(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::adcl_w(uint8_t data)
+{
+ LOGMASKED(LOG_ADC, "%s: ADCL = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_XMCRB:
- verboselog(m_pc, 0, "AVR8: XMCRB = %02x\n", data );
- //TODO: changed_xmcrb(data);
- break;
+template <int NumTimers>
+uint8_t avr8_device<NumTimers>::adch_r()
+{
+ uint8_t const result = ADMUX_ADLAR ? BIT(m_adc_data, 2, 8) : BIT(m_adc_data, 8, 2);
+ if (!machine().side_effects_disabled())
+ {
+ m_adc_data = m_adc_result;
+ m_adc_hold = false;
+ }
+ return result;
+}
- case AVR8_REGIDX_ADCL:
- verboselog(m_pc, 0, "AVR8: ADCL = %02x\n", data );
- //TODO: changed_adcl(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::adch_w(uint8_t data)
+{
+ LOGMASKED(LOG_ADC, "%s: ADCH = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_ADCH:
- verboselog(m_pc, 0, "AVR8: ADCH = %02x\n", data );
- //TODO: changed_adch(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::adcsra_w(uint8_t data)
+{
+ LOGMASKED(LOG_ADC, "%s: ADCSRA = %02x\n", machine().describe_context(), data);
- case AVR8_REGIDX_ADCSRA:
- verboselog(m_pc, 0, "AVR8: ADCSRA = %02x\n", data );
- //TODO: changed_adcsra(data);
- break;
+ // set auto trigger enable, interrupt enable, and prescaler directly
+ m_r[ADCSRA] &= ~(ADCSRA_ADATE_MASK | ADCSRA_ADIE_MASK | ADCSRA_ADPS_MASK);
+ m_r[ADCSRA] |= data & (ADCSRA_ADATE_MASK | ADCSRA_ADIE_MASK | ADCSRA_ADPS_MASK);
- case AVR8_REGIDX_ADCSRB:
- verboselog(m_pc, 0, "AVR8: ADCSRB = %02x\n", data );
- //TODO: changed_adcsrb(data);
- break;
+ // check enable bit
+ if (!(data & ADCSRA_ADEN_MASK))
+ {
+ // disable ADC, terminate any conversion in progress
+ m_r[ADCSRA] &= ~(ADCSRA_ADEN_MASK | ADCSRA_ADSC_MASK);
+ m_adc_timer->reset();
+ }
+ else
+ {
+ // first conversion after initial enable takes longer
+ if (!ADCSRA_ADEN)
+ {
+ m_adc_first = true;
+ m_r[ADCSRA] |= ADCSRA_ADEN_MASK;
+ }
- case AVR8_REGIDX_ADMUX:
- verboselog(m_pc, 0, "AVR8: ADMUX = %02x\n", data );
- //TODO: changed_admux(data);
- break;
+ // trigger conversion if necessary
+ if (!ADCSRA_ADSC && (data & ADCSRA_ADSC_MASK))
+ adc_start_conversion();
+ }
- case AVR8_REGIDX_DIDR0:
- verboselog(m_pc, 0, "AVR8: DIDR0 = %02x\n", data );
- //TODO: changed_didr0(data);
- break;
+ // writing with ADIF set clears the interrupt flag manually
+ if (data & ADCSRA_ADIF_MASK)
+ m_r[ADCSRA] &= ~ADCSRA_ADIF_MASK;
- case AVR8_REGIDX_DIDR1:
- verboselog(m_pc, 0, "AVR8: DIDR1 = %02x\n", data );
- //TODO: changed_didr1(data);
- break;
+ if (ADCSRA_ADIE)
+ logerror("%s: Unimplemented ADC interrupt enabled\n");
+}
- case AVR8_REGIDX_DIDR2:
- verboselog(m_pc, 0, "AVR8: DIDR2 = %02x\n", data );
- //TODO: changed_didr2(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::adcsrb_w(uint8_t data)
+{
+ LOGMASKED(LOG_ADC, "%s: ADCSRB = %02x\n", machine().describe_context(), data);
+ m_r[ADCSRB] = data & (ADCSRB_ACME_MASK | ADCSRB_ADTS_MASK);
+ if (ADCSRB_ADTS != 0)
+ logerror("%s: Unimplemented ADC auto trigger source %X selected\n", machine().describe_context(), ADCSRB_ADTS);
+}
- case AVR8_REGIDX_TCCR1A:
- verboselog(m_pc, 0, "AVR8: TCCR1A = %02x\n", data );
- changed_tccr1a(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::admux_w(uint8_t data)
+{
+ LOGMASKED(LOG_ADC, "%s: ADMUX = %02x\n", machine().describe_context(), data);
+ m_r[ADMUX] = data & (ADMUX_REFS_MASK | ADMUX_ADLAR_MASK | ADMUX_MUX_MASK);
+}
- case AVR8_REGIDX_TCCR1B:
- verboselog(m_pc, 0, "AVR8: TCCR1B = %02x\n", data );
- changed_tccr1b(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::didr0_w(uint8_t data)
+{
+ LOGMASKED(LOG_DIGINPUT, "%s: (not yet implemented) DIDR0 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_TCCR1C:
- verboselog(m_pc, 0, "AVR8: TCCR1C = %02x\n", data );
- //TODO: changed_tccr1c(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::didr1_w(uint8_t data)
+{
+ LOGMASKED(LOG_DIGINPUT, "%s: (not yet implemented) DIDR1 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_TCNT1L:
- AVR8_TCNT1L = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::didr2_w(uint8_t data)
+{
+ LOGMASKED(LOG_DIGINPUT, "%s: (not yet implemented) DIDR2 = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_TCNT1H:
- AVR8_TCNT1H = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr1a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: TCCR1A = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR1A];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ m_r[TCCR1A] = newtccr;
- case AVR8_REGIDX_ICR1L:
- AVR8_ICR1L = data;
- break;
+ if (changed & TCCR1A_WGM1_10_MASK)
+ {
+ update_timer_waveform_gen_mode(1, WGM1);
+ }
- case AVR8_REGIDX_ICR1H:
- AVR8_ICR1H = data;
- break;
+ m_timer1_tick = m_timer1_ticks[(WGM1 << 4) | ((m_r[TCCR1A] & TCCR1A_COM1AB_MASK) >> TCCR1A_COM1AB_SHIFT)];
+}
- case AVR8_REGIDX_OCR1AL:
- verboselog(m_pc, 0, "AVR8: OCR1AL = %02x\n", data );
- update_ocr1((AVR8_OCR1A & 0xff00) | data, AVR8_REG_A);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr1b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: TCCR1B = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR1B];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t oldcs = m_r[TCCR1B] & TCCR1B_CS_MASK;
- case AVR8_REGIDX_OCR1AH:
- verboselog(m_pc, 0, "AVR8: OCR1AH = %02x\n", data );
- update_ocr1((AVR8_OCR1A & 0x00ff) | (data << 8), AVR8_REG_A);
- break;
+ m_r[TCCR1B] = newtccr;
- case AVR8_REGIDX_OCR1BL:
- verboselog(m_pc, 0, "AVR8: OCR1BL = %02x\n", data );
- update_ocr1((AVR8_OCR1B & 0xff00) | data, AVR8_REG_B);
- break;
+ if (changed & TCCR1B_ICNC1_MASK)
+ {
+ update_timer1_input_noise_canceler();
+ }
- case AVR8_REGIDX_OCR1BH:
- verboselog(m_pc, 0, "AVR8: OCR1BH = %02x\n", data );
- update_ocr1((AVR8_OCR1B & 0x00ff) | (data << 8), AVR8_REG_B);
- break;
+ if (changed & TCCR1B_ICES1_MASK)
+ {
+ update_timer1_input_edge_select();
+ }
- case AVR8_REGIDX_OCR1CL:
- verboselog(m_pc, 0, "AVR8: OCR1CL = %02x\n", data );
- update_ocr1((AVR8_OCR1C & 0xff00) | data, AVR8_REG_C);
- break;
+ if (changed & TCCR1B_WGM1_32_MASK)
+ {
+ update_timer_waveform_gen_mode(1, WGM1);
+ }
- case AVR8_REGIDX_OCR1CH:
- verboselog(m_pc, 0, "AVR8: OCR1CH = %02x\n", data );
- update_ocr1((AVR8_OCR1C & 0x00ff) | (data << 8), AVR8_REG_C);
- break;
+ if (changed & TCCR1B_CS_MASK)
+ {
+ update_timer_clock_source<1>(TIMER1_CLOCK_SELECT, oldcs);
+ }
- case AVR8_REGIDX_TCCR2A:
- verboselog(m_pc, 0, "AVR8: TCCR2A = %02x\n", data );
- changed_tccr2a(data);
- break;
+ m_timer1_tick = m_timer1_ticks[(WGM1 << 4) | ((m_r[TCCR1A] & TCCR1A_COM1AB_MASK) >> TCCR1A_COM1AB_SHIFT)];
+}
- case AVR8_REGIDX_TCCR2B:
- verboselog(m_pc, 0, "AVR8: TCCR2B = %02x\n", data );
- changed_tccr2b(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr1c_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: (not yet implemented) TCCR1C = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_TCNT2:
- AVR8_TCNT2 = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::icr1l_w(uint8_t data)
+{
+ m_r[ICR1L] = data;
+}
- case AVR8_REGIDX_OCR2A:
- update_ocr2(data, AVR8_REG_A);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::icr1h_w(uint8_t data)
+{
+ m_r[ICR1H] = data;
+}
- case AVR8_REGIDX_OCR2B:
- update_ocr2(data, AVR8_REG_B);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1al_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1AL = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1A & 0xff00) | data, AVR8_REG_A);
+}
- case AVR8_REGIDX_TCCR3A:
- verboselog(m_pc, 0, "AVR8: TCCR3A = %02x\n", data );
- changed_tccr3a(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1ah_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1AH = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1A & 0x00ff) | (data << 8), AVR8_REG_A);
+}
- case AVR8_REGIDX_TCCR3B:
- verboselog(m_pc, 0, "AVR8: TCCR3B = %02x\n", data );
- changed_tccr3b(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1bl_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1BL = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1B & 0xff00) | data, AVR8_REG_B);
+}
- case AVR8_REGIDX_TCCR3C:
- verboselog(m_pc, 0, "AVR8: TCCR3C = %02x\n", data );
- changed_tccr3c(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1bh_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1BH = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1B & 0x00ff) | (data << 8), AVR8_REG_B);
+}
- case AVR8_REGIDX_TCNT3L:
- AVR8_TCNT3L = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1cl_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1CL = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1C & 0xff00) | data, AVR8_REG_C);
+}
- case AVR8_REGIDX_TCNT3H:
- AVR8_TCNT3H = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr1ch_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER1, "%s: OCR1CH = %02x\n", machine().describe_context(), data);
+ update_ocr1((OCR1C & 0x00ff) | (data << 8), AVR8_REG_C);
+}
- case AVR8_REGIDX_ICR3L:
- AVR8_ICR3L = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr2a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER2, "%s: TCCR2A = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR2A];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
- case AVR8_REGIDX_ICR3H:
- AVR8_ICR3H = data;
- break;
+ m_r[TCCR2A] = data;
- case AVR8_REGIDX_OCR3AL:
- AVR8_OCR3AL = data;
- break;
+ if (changed & TCCR2A_WGM2_10_MASK)
+ {
+ update_timer_waveform_gen_mode(2, WGM2);
+ }
- case AVR8_REGIDX_OCR3AH:
- AVR8_OCR3AH = data;
- break;
+ m_timer2_tick = m_timer2_ticks[((m_r[TCCR2B] & TCCR2B_WGM2_2_MASK) >> 1) | (m_r[TCCR2A] & TCCR2A_WGM2_10_MASK)];
+}
- case AVR8_REGIDX_OCR3BL:
- AVR8_OCR3BL = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr2b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER2, "%s: TCCR2B = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR2B];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t oldcs = m_r[TCCR2B] & TCCR2B_CS_MASK;
- case AVR8_REGIDX_OCR3BH:
- AVR8_OCR3BH = data;
- break;
+ m_r[TCCR2B] = data;
- case AVR8_REGIDX_OCR3CL:
- AVR8_OCR3CL = data;
- break;
+ if (changed & TCCR2B_FOC2A_MASK)
+ {
+ timer2_force_output_compare(AVR8_REG_A);
+ }
- case AVR8_REGIDX_OCR3CH:
- AVR8_OCR3CH = data;
- break;
+ if (changed & TCCR2B_FOC2B_MASK)
+ {
+ timer2_force_output_compare(AVR8_REG_B);
+ }
- case AVR8_REGIDX_TCCR4A:
- verboselog(m_pc, 0, "AVR8: TCCR4A = %02x\n", data );
- changed_tccr4a(data);
- break;
+ if (changed & TCCR2B_WGM2_2_MASK)
+ {
+ update_timer_waveform_gen_mode(2, WGM2);
+ }
- case AVR8_REGIDX_TCCR4B:
- verboselog(m_pc, 0, "AVR8: TCCR4B = %02x\n", data );
- changed_tccr4b(data);
- break;
+ if (changed & TCCR2B_CS_MASK)
+ {
+ update_timer_clock_source<2>(TIMER2_CLOCK_SELECT, oldcs);
+ }
- case AVR8_REGIDX_TCCR4C:
- verboselog(m_pc, 0, "AVR8: TCCR4C = %02x\n", data );
- changed_tccr4c(data);
- break;
+ m_timer2_tick = m_timer2_ticks[((m_r[TCCR2B] & TCCR2B_WGM2_2_MASK) >> 1) | (m_r[TCCR2A] & TCCR2A_WGM2_10_MASK)];
+}
- case AVR8_REGIDX_TCNT4L:
- AVR8_TCNT4L = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tcnt2_w(uint8_t data)
+{
+ m_r[TCNT2] = data;
+}
- case AVR8_REGIDX_TCNT4H:
- AVR8_TCNT4H = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr2a_w(uint8_t data)
+{
+ update_ocr2(data, AVR8_REG_A);
+}
- case AVR8_REGIDX_ICR4L:
- AVR8_ICR4L = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr2b_w(uint8_t data)
+{
+ update_ocr2(data, AVR8_REG_B);
+}
- case AVR8_REGIDX_ICR4H:
- AVR8_ICR4H = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr3a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER3, "%s: (not yet implemented) TCCR3A = %02x\n", machine().describe_context(), data);
+ // TODO
+ // AVR8_TCCR3A = data;
+}
- case AVR8_REGIDX_OCR4AL:
- AVR8_OCR4AL = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr3b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER3, "%s: (not yet implemented) TCCR3B = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_OCR4AH:
- AVR8_OCR4AH = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr3c_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER3, "%s: (not yet implemented) TCCR3C = %02x\n", machine().describe_context(), data);
+}
- case AVR8_REGIDX_OCR4BL:
- AVR8_OCR4BL = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::icr3l_w(uint8_t data)
+{
+ m_r[ICR3L] = data;
+}
- case AVR8_REGIDX_OCR4BH:
- AVR8_OCR4BH = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::icr3h_w(uint8_t data)
+{
+ m_r[ICR3H] = data;
+}
- case AVR8_REGIDX_OCR4CL:
- AVR8_OCR4CL = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3al_w(uint8_t data)
+{
+ m_r[OCR3AL] = data;
+}
- case AVR8_REGIDX_OCR4CH:
- AVR8_OCR4CH = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3ah_w(uint8_t data)
+{
+ m_r[OCR3AH] = data;
+}
- case AVR8_REGIDX_TCCR5A:
- verboselog(m_pc, 0, "AVR8: TCCR5A = %02x\n", data );
- changed_tccr5a(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3bl_w(uint8_t data)
+{
+ m_r[OCR3BL] = data;
+}
- case AVR8_REGIDX_TCCR5B:
- verboselog(m_pc, 0, "AVR8: TCCR5B = %02x\n", data );
- changed_tccr5b(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3bh_w(uint8_t data)
+{
+ m_r[OCR3BH] = data;
+}
- case AVR8_REGIDX_ASSR:
- verboselog(m_pc, 0, "AVR8: ASSR = %02x\n", data );
- //TODO: changed_assr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3cl_w(uint8_t data)
+{
+ m_r[OCR3CL] = data;
+}
- case AVR8_REGIDX_TWBR:
- verboselog(m_pc, 0, "AVR8: TWBR = %02x\n", data );
- //TODO: changed_twbr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr3ch_w(uint8_t data)
+{
+ m_r[OCR3CH] = data;
+}
- case AVR8_REGIDX_TWSR:
- verboselog(m_pc, 0, "AVR8: TWSR = %02x\n", data );
- //TODO: changed_twsr(data);
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr4a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER4, "%s: TCCR4A = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR4A];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
- case AVR8_REGIDX_TWAR:
- verboselog(m_pc, 0, "AVR8: TWAR = %02x\n", data );
- //TODO: changed_twar(data);
- break;
+ m_r[TCCR4A] = data;
- case AVR8_REGIDX_TWDR:
- verboselog(m_pc, 0, "AVR8: TWDR = %02x\n", data );
- //TODO: changed_twdr(data);
- break;
+ if (changed & TCCR4A_WGM4_10_MASK)
+ {
+ update_timer_waveform_gen_mode(4, WGM4);
+ }
+}
- case AVR8_REGIDX_TWCR:
- verboselog(m_pc, 0, "AVR8: TWCR = %02x\n", data );
- //TODO: changed_twcr(data);
- m_r[AVR8_REGIDX_TWCR] = data;
- break;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr4b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER4, "%s: TCCR4B = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR4B];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t oldcs = (m_r[TCCR4B] & TCCR4B_CS_MASK) >> TCCR4B_CS_SHIFT;
- case AVR8_REGIDX_TWAMR:
- verboselog(m_pc, 0, "AVR8: TWAMR = %02x\n", data );
- //TODO: changed_twamr(data);
- break;
+ m_r[TCCR4B] = data;
- case AVR8_REGIDX_UCSR0A:
- verboselog(m_pc, 0, "AVR8: UCSR0A = %02x\n", data );
- //TODO: changed_ucsr0a(data);
- break;
+ if (changed & TCCR4B_FOC4A_MASK)
+ {
+ // TODO
+ // timer4_force_output_compare(AVR8_REG_A);
+ }
- case AVR8_REGIDX_UCSR0B:
- verboselog(m_pc, 0, "AVR8: UCSR0B = %02x\n", data );
- //TODO: changed_ucsr0b(data);
- break;
+ if (changed & TCCR4B_FOC4B_MASK)
+ {
+ // TODO
+ // timer4_force_output_compare(AVR8_REG_B);
+ }
- 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;
+ if (changed & TCCR4B_WGM4_32_MASK)
+ {
+ update_timer_waveform_gen_mode(4, WGM4);
+ }
+
+ if (changed & TCCR4B_CS_MASK)
+ {
+ update_timer_clock_source<4>(TIMER4_CLOCK_SELECT, oldcs);
}
}
-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);
-// machine().debug_break();
- return 0;
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr4c_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER4, "%s: TCCR4C = %02x\n", machine().describe_context(), data);
+ // uint8_t oldtccr = m_r[TCCR4C];
+ // uint8_t newtccr = data;
+ // uint8_t changed = newtccr ^ oldtccr;
+
+ m_r[TCCR4C] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::tcnt4l_w(uint8_t data)
+{
+ m_r[TCNT4L] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::tcnt4h_w(uint8_t data)
+{
+ m_r[TCNT4H] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::icr4l_w(uint8_t data)
+{
+ m_r[ICR4L] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::icr4h_w(uint8_t data)
+{
+ m_r[ICR4H] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4al_w(uint8_t data)
+{
+ m_r[OCR4AL] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4ah_w(uint8_t data)
+{
+ m_r[OCR4AH] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4bl_w(uint8_t data)
+{
+ m_r[OCR4BL] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4bh_w(uint8_t data)
+{
+ m_r[OCR4BH] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4cl_w(uint8_t data)
+{
+ m_r[OCR4CL] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::ocr4ch_w(uint8_t data)
+{
+ m_r[OCR4CH] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr5a_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER5, "%s: TCCR5A = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR5A];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+
+ m_r[TCCR5A] = data;
+
+ if (changed & TCCR5A_WGM5_10_MASK)
+ {
+ update_timer_waveform_gen_mode(5, WGM5);
}
}
+template <int NumTimers>
+void avr8_device<NumTimers>::tccr5b_w(uint8_t data)
+{
+ LOGMASKED(LOG_TIMER5, "%s: TCCR5B = %02x\n", machine().describe_context(), data);
+ const uint8_t oldtccr = m_r[TCCR5B];
+ const uint8_t newtccr = data;
+ const uint8_t changed = newtccr ^ oldtccr;
+ const uint8_t oldcs = (m_r[TCCR5B] & TCCR5B_CS_MASK) >> TCCR5B_CS_SHIFT;
-//**************************************************************************
-// CORE EXECUTION LOOP
-//**************************************************************************
+ m_r[TCCR5B] = data;
-//-------------------------------------------------
-// execute_min_cycles - return minimum number of
-// cycles it takes for one instruction to execute
-//-------------------------------------------------
+ if (changed & TCCR5C_FOC5A_MASK)
+ {
+ // TODO
+ // timer5_force_output_compare(AVR8_REG_A);
+ }
+
+ if (changed & TCCR5C_FOC5B_MASK)
+ {
+ // TODO
+ // timer5_force_output_compare(AVR8_REG_B);
+ }
-uint32_t avr8_device::execute_min_cycles() const
+ if (changed & TCCR5C_FOC5C_MASK)
+ {
+ // TODO
+ // timer5_force_output_compare(AVR8_REG_C);
+ }
+
+ if (changed & TCCR5B_WGM5_32_MASK)
+ {
+ update_timer_waveform_gen_mode(5, WGM5);
+ }
+
+ if (changed & TCCR5B_CS_MASK)
+ {
+ update_timer_clock_source<5>(TIMER5_CLOCK_SELECT, oldcs);
+ }
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::assr_w(uint8_t data)
{
- return 1;
+ LOGMASKED(LOG_ASYNC, "%s: (not yet implemented) ASSR = %02x\n", machine().describe_context(), data);
}
+template <int NumTimers>
+void avr8_device<NumTimers>::twbr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWBR = %02x\n", machine().describe_context(), data);
+}
-//-------------------------------------------------
-// execute_max_cycles - return maximum number of
-// cycles it takes for one instruction to execute
-//-------------------------------------------------
+template <int NumTimers>
+uint8_t avr8_device<NumTimers>::twsr_r()
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) Read TWSR: %02x\n", machine().describe_context(), 0);
+ // HACK for Replicator 1:
+ // 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.
+ return 0x00;
+}
-uint32_t avr8_device::execute_max_cycles() const
+template <int NumTimers>
+void avr8_device<NumTimers>::twsr_w(uint8_t data)
{
- return 4;
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWSR = %02x\n", machine().describe_context(), data);
}
+template <int NumTimers>
+void avr8_device<NumTimers>::twar_w(uint8_t data)
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWAR = %02x\n", machine().describe_context(), data);
+}
-//-------------------------------------------------
-// execute_input_lines - return the number of
-// input/interrupt lines
-//-------------------------------------------------
+template <int NumTimers>
+void avr8_device<NumTimers>::twdr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWDR = %02x\n", machine().describe_context(), data);
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::twcr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWCR = %02x\n", machine().describe_context(), data);
+ m_r[TWCR] = data;
+}
+
+template <int NumTimers>
+void avr8_device<NumTimers>::twamr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TWI, "%s: (not yet implemented) TWAMR = %02x\n", machine().describe_context(), data);
+}
-uint32_t avr8_device::execute_input_lines() const
+template <int NumTimers>
+void avr8_device<NumTimers>::ucsr0a_w(uint8_t data)
{
- return 0;
+ LOGMASKED(LOG_UART, "%s: (not yet implemented) UCSR0A = %02x\n", machine().describe_context(), data);
}
+template <int NumTimers>
+void avr8_device<NumTimers>::ucsr0b_w(uint8_t data)
+{
+ LOGMASKED(LOG_UART, "%s: (not yet implemented) UCSR0B = %02x\n", machine().describe_context(), data);
+}
-void avr8_device::execute_set_input(int inputnum, int state)
+template <int NumTimers>
+void avr8_device<NumTimers>::ucsr0c_w(uint8_t data)
{
+ LOGMASKED(LOG_UART, "%s: (not yet implemented) UCSR0C = %02x\n", machine().describe_context(), data);
}
+//**************************************************************************
+// CORE EXECUTION LOOP
+//**************************************************************************
+
+#include "avr8ops.hxx"
+
//-------------------------------------------------
// execute_run - execute a timeslice's worth of
// opcodes
//-------------------------------------------------
-void avr8_device::execute_run()
+template <int NumTimers>
+void avr8_device<NumTimers>::execute_run()
{
- uint32_t op;
- int32_t offs;
- uint8_t rd;
- uint8_t rr;
- uint8_t res;
- uint16_t pd;
- uint32_t pd32;
- int16_t sd;
- int32_t opcycles;
-
while (m_icount > 0)
{
- opcycles = 1;
-
m_pc &= m_addr_mask;
- m_shifted_pc &= (m_addr_mask << 1) | 1;
+ debugger_instruction_hook(m_pc);
- debugger_instruction_hook(m_shifted_pc);
+ const uint16_t op = (uint32_t)m_program->read_word(m_pc);
+ m_opcycles = m_op_cycles[op];
+ ((this)->*(m_op_funcs[op]))(op);
+ m_pc += 2;
- op = (uint32_t)m_program->read_word(m_shifted_pc);
+ m_icount -= m_opcycles;
- switch(op & 0xf000)
+ for (int i = 0; i < m_opcycles; i++)
{
- 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_t)m_r[16 + RD4(op)] * (int8_t)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_t)m_r[16 + RD3(op)] * (uint8_t)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_t)m_r[16 + RD3(op)] * (uint8_t)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_t)m_r[16 + RD3(op)] * (int8_t)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_t)m_r[16 + RD3(op)] * (uint8_t)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_t)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)
+ if (m_spi_active && m_spi_prescale > 0)
+ {
+ if (m_spi_prescale_countdown >= 0)
{
- 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_t)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_t)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_t)m_r[RD5(op)] * (uint8_t)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;
+ m_spi_prescale_count++;
+ if (m_spi_prescale_count >= m_spi_prescale)
+ {
+ spi_tick();
+ m_spi_prescale_count -= m_spi_prescale;
+ }
}
- break;
- case 0xb000:
- if(op & 0x0800) // OUT A,Rr
+ }
+
+ m_timer_prescale_count[0]++;
+ if (m_timer_prescale_count[0] > m_timer_prescale[0])
+ m_timer0_tick();
+
+ m_timer_prescale_count[1]++;
+ if (m_timer_prescale_count[1] > m_timer_prescale[1])
+ m_timer1_tick();
+
+ m_timer_prescale_count[2]++;
+ if (m_timer_prescale_count[2] > m_timer_prescale[2])
+ m_timer2_tick();
+
+ if (NumTimers > 5)
+ {
+ m_timer_prescale_count[3]++;
+ if (m_timer_prescale_count[3] > m_timer_prescale[3])
{
- m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]);
+ timer3_tick();
+ m_timer_prescale_count[3] -= m_timer_prescale[3];
}
- else // IN Rd,A
+
+ m_timer_prescale_count[4]++;
+ if (m_timer_prescale_count[4] > m_timer_prescale[4])
{
- m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op));
+ timer4_tick();
+ m_timer_prescale_count[4] -= m_timer_prescale[4];
}
- break;
- case 0xc000: // RJMP k
- offs = (int32_t)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff));
- m_pc += offs;
- opcycles = 2;
- break;
- case 0xd000: // RCALL k
- offs = (int32_t)((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)
+
+ m_timer_prescale_count[5]++;
+ if (m_timer_prescale_count[5] > m_timer_prescale[5])
{
- case 0x0000: // BRLO through BRIE
- if(SREG_R(op & 0x0007))
- {
- offs = (int32_t)(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_t)(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_t)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_t)m_program->read_word(m_shifted_pc + 2);
- m_pc += is_long_opcode(op) ? 2 : 1;
- opcycles = is_long_opcode(op) ? 3 : 2;
- }
- }
- break;
+ timer5_tick();
+ m_timer_prescale_count[5] -= m_timer_prescale[5];
}
- break;
+ }
}
-
- m_pc++;
-
- m_shifted_pc = m_pc << 1;
-
- m_icount -= opcycles;
-
- timer_tick(opcycles);
}
}
+
+template class avr8_device<2>;
+template class avr8_device<3>;
+template class avr8_device<6>;
diff --git a/src/devices/cpu/avr8/avr8.h b/src/devices/cpu/avr8/avr8.h
index 36b20738979..fbf34b5c1d9 100644
--- a/src/devices/cpu/avr8/avr8.h
+++ b/src/devices/cpu/avr8/avr8.h
@@ -3,38 +3,6 @@
/*
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 encountered 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: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL
-
- - Changelist -
- 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 [Ryan Holtz]
- - Fixed incorrect flag calculation in ROR opcode [Ryan Holtz]
- - Fixed incorrect bit testing in SBIC/SBIS opcodes [Ryan Holtz]
-
- 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 [Ryan Holtz]
- - Corrected cycle counts for LD and ST opcodes [Ryan Holtz]
- - 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 [Ryan Holtz]
- - Fixed register behavior in MULSU, LD -Z, and LD -Y opcodes [Ryan Holtz]
-
- 18 Oct. 2012
- - Added OR, SBCI, ORI, ST Y+, ADIQ opcodes [Ryan Holtz]
- - Fixed COM, NEG, LSR opcodes [Ryan Holtz]
-
*/
#ifndef MAME_CPU_AVR8_AVR8_H
@@ -47,12 +15,10 @@
// TYPE DEFINITIONS
//**************************************************************************
-class avr8_device;
-
-// ======================> avr8_device
+// ======================> avr8_base_device
// Used by core CPU interface
-class avr8_device : public cpu_device
+class avr8_base_device : public cpu_device
{
public:
// inline configuration helpers
@@ -66,34 +32,579 @@ public:
// public interfaces
virtual void update_interrupt(int source);
- uint64_t get_elapsed_cycles() const { return m_elapsed_cycles; }
- // register handling
- DECLARE_WRITE8_MEMBER(regs_w);
- DECLARE_READ8_MEMBER(regs_r);
- uint32_t m_shifted_pc;
+ // GPIO
+ enum gpio_t : int
+ {
+ GPIOA,
+ GPIOB,
+ GPIOC,
+ GPIOD,
+ GPIOE,
+ GPIOF,
+ GPIOG,
+ GPIOH,
+ GPIOJ,
+ GPIOK,
+ GPIOL,
+
+ GPIO_COUNT
+ };
+
+ enum : uint8_t
+ {
+ ADC0 = 0,
+ ADC1,
+ ADC2,
+ ADC3,
+ ADC4,
+ ADC5,
+ ADC6,
+ ADC7
+ };
protected:
- enum
+ avr8_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t address_mask, address_map_constructor internal_map);
+
+ typedef void (avr8_base_device::*op_func) (uint16_t op);
+
+ enum : uint8_t
+ {
+ AVR8_INT_RESET = 0,
+ AVR8_INT_INT0,
+ AVR8_INT_INT1,
+ AVR8_INT_PCINT0,
+ AVR8_INT_PCINT1,
+ AVR8_INT_PCINT2,
+ AVR8_INT_WDT,
+ AVR8_INT_T2COMPA,
+ AVR8_INT_T2COMPB,
+ AVR8_INT_T2OVF,
+ AVR8_INT_T1CAPT,
+ AVR8_INT_T1COMPA,
+ AVR8_INT_T1COMPB,
+ AVR8_INT_T1OVF,
+ AVR8_INT_T0COMPA,
+ AVR8_INT_T0COMPB,
+ AVR8_INT_T0OVF,
+ AVR8_INT_SPI_STC,
+ AVR8_INT_USART_RX,
+ AVR8_INT_USART_UDRE,
+ AVR8_INT_USART_TX,
+ AVR8_INT_ADC,
+ AVR8_INT_EE_RDY,
+ AVR8_INT_ANALOG_COMP,
+ AVR8_INT_TWI,
+ AVR8_INT_SPM_RDY,
+ };
+
+ // Used by I/O register handling
+ enum : uint16_t
+ {
+ R0 = 0x00,
+ R1,
+ R2,
+ R3,
+ R4,
+ R5,
+ R6,
+ R7,
+ R8,
+ R9,
+ R10,
+ R11,
+ R12,
+ R13,
+ R14,
+ R15,
+ R16,
+ R17,
+ R18,
+ R19,
+ R20,
+ R21,
+ R22,
+ R23,
+ R24,
+ R25,
+ R26,
+ R27,
+ R28,
+ R29,
+ R30,
+ R31,
+ PINA = 0x20,
+ DDRA,
+ PORTA,
+ PINB,
+ DDRB,
+ PORTB,
+ PINC,
+ DDRC,
+ PORTC,
+ PIND,
+ DDRD,
+ PORTD,
+ PINE,
+ DDRE,
+ PORTE,
+ PINF,
+ DDRF,
+ PORTF,
+ PING,
+ DDRG,
+ PORTG,
+ TIFR0 = 0x35,
+ TIFR1,
+ TIFR2,
+ TIFR3,
+ TIFR4,
+ TIFR5,
+ PCIFR = 0x3B,
+ EIFR,
+ EIMSK,
+ GPIOR0,
+ EECR,
+ EEDR,
+ EEARL,
+ EEARH,
+ GTCCR,
+ TCCR0A,
+ TCCR0B,
+ TCNT0,
+ OCR0A,
+ OCR0B,
+ //0x49: Reserved
+ GPIOR1 = 0x4A,
+ GPIOR2,
+ SPCR,
+ SPSR,
+ SPDR,
+ //0x4F: Reserved
+ ACSR = 0x50,
+ OCDR,
+ //0x52: Reserved
+ SMCR = 0x53,
+ MCUSR,
+ MCUCR,
+ //0x56: Reserved
+ SPMCSR = 0x57,
+ //0x58: Reserved
+ //0x59: Reserved
+ //0x5A: Reserved
+ RAMPZ = 0x5B,
+ EIND,
+ SPL,
+ SPH,
+ SREG,
+ //--------------------------
+ WDTCSR = 0x60,
+ CLKPR,
+ //0x62: Reserved
+ //0x63: Reserved
+ PRR0 = 0x64,
+ PRR1,
+ OSCCAL,
+ //0x67: Reserved
+ PCICR = 0x68,
+ EICRA,
+ EICRB,
+ PCMSK0,
+ PCMSK1,
+ PCMSK2,
+ TIMSK0,
+ TIMSK1,
+ TIMSK2,
+ TIMSK3,
+ TIMSK4,
+ TIMSK5,
+ XMCRA,
+ XMCRB,
+ //0x76: Reserved
+ //0x77: Reserved
+ ADCL = 0x78,
+ ADCH,
+ ADCSRA,
+ ADCSRB,
+ ADMUX,
+ DIDR2,
+ DIDR0,
+ DIDR1,
+ TCCR1A,
+ TCCR1B,
+ TCCR1C,
+ //0x83: Reserved
+ TCNT1L = 0x84,
+ TCNT1H,
+ ICR1L,
+ ICR1H,
+ OCR1AL,
+ OCR1AH,
+ OCR1BL,
+ OCR1BH,
+ OCR1CL,
+ OCR1CH,
+ //0x8E: Reserved
+ //0x8F: Reserved
+ TCCR3A = 0x90,
+ TCCR3B,
+ TCCR3C,
+ //0x93: Reserved
+ TCNT3L = 0x94,
+ TCNT3H,
+ ICR3L,
+ ICR3H,
+ OCR3AL,
+ OCR3AH,
+ OCR3BL,
+ OCR3BH,
+ OCR3CL,
+ OCR3CH,
+ //0x9E: Reserved
+ //0x9F: Reserved
+ TCCR4A = 0xA0,
+ TCCR4B,
+ TCCR4C,
+ //0xA3: Reserved
+ TCNT4L = 0xA4,
+ TCNT4H,
+ ICR4L,
+ ICR4H,
+ OCR4AL,
+ OCR4AH,
+ OCR4BL,
+ OCR4BH,
+ OCR4CL,
+ OCR4CH,
+ //0xAE: Reserved
+ //0xAF: Reserved
+ TCCR2A = 0xB0,
+ TCCR2B,
+ TCNT2,
+ OCR2A,
+ OCR2B,
+ //0xB5: Reserved
+ ASSR = 0xB6,
+ //0xB7: Reserved
+ TWBR = 0xB8,
+ TWSR,
+ TWAR,
+ TWDR,
+ TWCR,
+ TWAMR,
+ //0xBE: Reserved
+ //0xBF: Reserved
+ UCSR0A = 0xC0,
+ UCSR0B,
+ UCSR0C,
+ //0xC3: Reserved
+ UBRR0L = 0xC4,
+ UBRR0H,
+ UDR0,
+ //0xC7: Reserved
+ UCSR1A = 0xC8,
+ UCSR1B,
+ UCSR1C,
+ //0xCB: Reserved
+ UBRR1L = 0xCC,
+ UBRR1H,
+ UDR1,
+ //0xCF: Reserved
+ UCSR2A = 0xD0,
+ UCSR2B,
+ UCSR2C,
+ //0xD3: Reserved
+ UBRR2L = 0xD4,
+ UBRR2H,
+ UDR2,
+ //0xD7: Reserved
+ //0xD8: Reserved
+ //0xD9: Reserved
+ //0xDA: Reserved
+ //0xDB: Reserved
+ //0xDC: Reserved
+ //0xDD: Reserved
+ //0xDE: Reserved
+ //0xDF: Reserved
+ //0xE0: Reserved
+ //0xE1: Reserved
+ //0xE2: Reserved
+ //0xE3: Reserved
+ //0xE4: Reserved
+ //0xE5: Reserved
+ //0xE6: Reserved
+ //0xE7: Reserved
+ //0xE8: Reserved
+ //0xE9: Reserved
+ //0xEA: Reserved
+ //0xEB: Reserved
+ //0xEC: Reserved
+ //0xED: Reserved
+ //0xEE: Reserved
+ //0xEF: Reserved
+ //0xF0: Reserved
+ //0xF1: Reserved
+ //0xF2: Reserved
+ //0xF3: Reserved
+ //0xF4: Reserved
+ //0xF5: Reserved
+ //0xF6: Reserved
+ //0xF7: Reserved
+ //0xF8: Reserved
+ //0xF9: Reserved
+ //0xFA: Reserved
+ //0xFB: Reserved
+ //0xFC: Reserved
+ //0xFD: Reserved
+ //0xFE: Reserved
+ //0xFF: Reserved
+ PINH = 0x100,
+ DDRH,
+ PORTH,
+ PINJ,
+ DDRJ,
+ PORTJ,
+ PINK,
+ DDRK,
+ PORTK,
+ PINL,
+ DDRL,
+ PORTL,
+ //0x10C: Reserved
+ //0x10D: Reserved
+ //0x10E: Reserved
+ //0x10F: Reserved
+ //0x110: Reserved
+ //0x111: Reserved
+ //0x112: Reserved
+ //0x113: Reserved
+ //0x114: Reserved
+ //0x115: Reserved
+ //0x116: Reserved
+ //0x117: Reserved
+ //0x118: Reserved
+ //0x119: Reserved
+ //0x11A: Reserved
+ //0x11B: Reserved
+ //0x11C: Reserved
+ //0x11D: Reserved
+ //0x11E: Reserved
+ //0x11F: Reserved
+ TCCR5A = 0x120,
+ TCCR5B,
+ TCCR5C,
+ //0x123: Reserved
+ TCNT5L = 0x124,
+ TCNT5H,
+ ICR5L,
+ ICR5H,
+ OCR5AL,
+ OCR5AH,
+ OCR5BL,
+ OCR5BH,
+ OCR5CL,
+ OCR5CH,
+ //0x12E: Reserved
+ //0x12F: Reserved
+ UCSR3A = 0x130,
+ UCSR3B,
+ UCSR3C,
+ //0x133: Reserved
+ UBRR3L = 0x134,
+ UBRR3H,
+ UDR3
+ //0x137: Reserved
+ // .
+ // . up to
+ // .
+ //0x1FF: Reserved
+ };
+
+ enum : uint8_t
+ {
+ AVR8_IO_PORTA = 0,
+ AVR8_IO_PORTB,
+ AVR8_IO_PORTC,
+ AVR8_IO_PORTD,
+ AVR8_IO_PORTE,
+ AVR8_IO_PORTF,
+ AVR8_IO_PORTG,
+ AVR8_IO_PORTH,
+ AVR8_IO_PORTJ,
+ AVR8_IO_PORTK,
+ AVR8_IO_PORTL
+ };
+
+ enum : uint8_t
+ {
+ AVR8_REG_A = 0,
+ AVR8_REG_B,
+ AVR8_REG_C,
+ AVR8_REG_D,
+ AVR8_REG_E,
+ AVR8_REG_F,
+ AVR8_REG_G,
+ AVR8_REG_H,
+ AVR8_REG_J,
+ AVR8_REG_K,
+ AVR8_REG_L
+ };
+
+ enum : uint8_t
+ {
+ INTIDX_SPI,
+
+ INTIDX_OCF0B,
+ INTIDX_OCF0A,
+ INTIDX_TOV0,
+
+ INTIDX_ICF1,
+
+ INTIDX_OCF1B,
+ INTIDX_OCF1A,
+ INTIDX_TOV1,
+
+ INTIDX_OCF2B,
+ INTIDX_OCF2A,
+ INTIDX_TOV2,
+
+ //------ TODO: review this --------
+ INTIDX_OCF3B,
+ INTIDX_OCF3A,
+ INTIDX_TOV3,
+
+ INTIDX_OCF4B,
+ INTIDX_OCF4A,
+ INTIDX_TOV4,
+
+ INTIDX_OCF5B,
+ INTIDX_OCF5A,
+ INTIDX_TOV5,
+ //---------------------------------
+
+ INTIDX_COUNT
+ };
+
+ enum : uint8_t
+ {
+ ATMEGA644_INT_RESET = 0,
+ ATMEGA644_INT_INT0,
+ ATMEGA644_INT_INT1,
+ ATMEGA644_INT_INT2,
+ ATMEGA644_INT_PCINT0,
+ ATMEGA644_INT_PCINT1,
+ ATMEGA644_INT_PCINT2,
+ ATMEGA644_INT_PCINT3,
+ ATMEGA644_INT_WDT,
+ ATMEGA644_INT_T2COMPA,
+ ATMEGA644_INT_T2COMPB,
+ ATMEGA644_INT_T2OVF,
+ ATMEGA644_INT_T1CAPT,
+ ATMEGA644_INT_T1COMPA,
+ ATMEGA644_INT_T1COMPB,
+ ATMEGA644_INT_T1OVF,
+ ATMEGA644_INT_T0COMPA,
+ ATMEGA644_INT_T0COMPB,
+ ATMEGA644_INT_T0OVF,
+ ATMEGA644_INT_SPI_STC,
+ ATMEGA644_INT_USART_RX,
+ ATMEGA644_INT_USART_UDRE,
+ ATMEGA644_INT_USART_TX,
+ ATMEGA644_INT_ADC,
+ ATMEGA644_INT_EE_RDY,
+ ATMEGA644_INT_ANALOG_COMP,
+ ATMEGA644_INT_TWI,
+ ATMEGA644_INT_SPM_RDY
+ };
+
+ // lock bit masks
+ enum : uint8_t
+ {
+ LB1 = (1 << 0),
+ LB2 = (1 << 1),
+ BLB01 = (1 << 2),
+ BLB02 = (1 << 3),
+ BLB11 = (1 << 4),
+ BLB12 = (1 << 5)
+ };
+
+ // extended fuses bit masks
+ enum : uint8_t
+ {
+ BODLEVEL0 = (1 << 0),
+ BODLEVEL1 = (1 << 1),
+ BODLEVEL2 = (1 << 2)
+ };
+
+ // high fuses bit masks
+ enum : uint8_t
+ {
+ BOOTRST = (1 << 0),
+ BOOTSZ0 = (1 << 1),
+ BOOTSZ1 = (1 << 2),
+ EESAVE = (1 << 3),
+ WDTON = (1 << 4),
+ SPIEN = (1 << 5),
+ JTAGEN = (1 << 6),
+ OCDEN = (1 << 7)
+ };
+
+ // low fuses bit masks
+ enum : uint8_t
+ {
+ CKSEL0 = (1 << 0),
+ CKSEL1 = (1 << 1),
+ CKSEL2 = (1 << 2),
+ CKSEL3 = (1 << 3),
+ SUT0 = (1 << 4),
+ SUT1 = (1 << 5),
+ CKOUT = (1 << 6),
+ CKDIV8 = (1 << 7)
+ };
+
+ enum : uint8_t
{
- CPU_TYPE_ATMEGA88,
- CPU_TYPE_ATMEGA644,
- CPU_TYPE_ATMEGA1280,
- CPU_TYPE_ATMEGA2560
+ EEARH_MASK = (1 << 0),
+
+ SPSR_SPR2X_MASK = (1 << 0),
+ SPSR_SPIF_SHIFT = 7,
+ SPSR_SPIF_MASK = (1 << SPSR_SPIF_SHIFT),
+
+ SPCR_SPR_MASK = (3 << 0),
+ SPCR_CPHA_MASK = (1 << 2),
+ SPCR_CPOL_MASK = (1 << 3),
+ SPCR_MSTR_MASK = (1 << 4),
+ SPCR_DORD_MASK = (1 << 5),
+ SPCR_SPE_MASK = (1 << 6),
+ SPCR_SPIE_MASK = (1 << 7)
};
- avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t address_mask, address_map_constructor internal_map, uint8_t cpu_type);
+ struct interrupt_condition
+ {
+ uint8_t m_intindex;
+ uint8_t m_intreg;
+ uint8_t m_intmask;
+ uint8_t m_regindex;
+ uint8_t m_regmask;
+ };
+
+ op_func m_op_funcs[0x10000];
+ int m_op_cycles[0x10000];
+ int m_opcycles;
+ std::unique_ptr<uint8_t[]> m_add_flag_cache;
+ std::unique_ptr<uint8_t[]> m_adc_flag_cache;
+ std::unique_ptr<uint8_t[]> m_sub_flag_cache;
+ std::unique_ptr<uint8_t[]> m_sbc_flag_cache;
+ std::unique_ptr<uint8_t[]> m_bool_flag_cache;
+ std::unique_ptr<uint8_t[]> m_shift_flag_cache;
// device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
// device_execute_interface overrides
- virtual uint32_t execute_min_cycles() const override;
- virtual uint32_t execute_max_cycles() const override;
- virtual uint32_t execute_input_lines() const override;
- virtual void execute_run() override;
- virtual void execute_set_input(int inputnum, int state) override;
+ virtual uint32_t execute_min_cycles() const noexcept override { return 1; }
+ virtual uint32_t execute_max_cycles() const noexcept override { return 4; }
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
@@ -107,12 +618,10 @@ protected:
// address spaces
const address_space_config m_program_config;
const address_space_config m_data_config;
- const address_space_config m_io_config;
required_region_ptr<uint8_t> m_eeprom;
// bootloader
uint16_t m_boot_size;
- uint8_t m_cpu_type;
// Fuses
uint8_t m_lfuses;
@@ -121,30 +630,8 @@ protected:
uint8_t m_lock_bits;
// CPU registers
+ required_shared_ptr<uint8_t> m_r;
uint32_t m_pc;
- uint8_t m_r[0x200];
-
- // internal timers
- int32_t m_timer_top[6];
- uint8_t m_timer_increment[6];
- uint16_t m_timer_prescale[6];
- uint16_t m_timer_prescale_count[6];
- bool m_ocr2_not_reached_yet;
-
- // SPI
- bool m_spi_active;
- uint8_t m_spi_prescale;
- uint8_t m_spi_prescale_count;
- int8_t m_spi_prescale_countdown;
- static const uint8_t spi_clock_divisor[8];
- void enable_spi();
- void disable_spi();
- void spi_update_masterslave_select();
- void spi_update_clock_polarity();
- void spi_update_clock_phase();
- void spi_update_clock_rate();
- void change_spcr(uint8_t data);
- void change_spsr(uint8_t data);
// internal CPU state
uint32_t m_addr_mask;
@@ -152,7 +639,6 @@ protected:
// other internal states
int m_icount;
- uint64_t m_elapsed_cycles;
// memory access
inline void push(uint8_t val);
@@ -165,119 +651,534 @@ protected:
// interrupts
void set_irq_line(uint16_t vector, int state);
+ // ops
+ void populate_ops();
+ void populate_add_flag_cache();
+ void populate_adc_flag_cache();
+ void populate_sub_flag_cache();
+ void populate_sbc_flag_cache();
+ void populate_bool_flag_cache();
+ void populate_shift_flag_cache();
+ void op_nop(uint16_t op);
+ void op_movw(uint16_t op);
+ void op_muls(uint16_t op);
+ void op_mulsu(uint16_t op);
+ void op_fmul(uint16_t op);
+ void op_fmuls(uint16_t op);
+ void op_fmulsu(uint16_t op);
+ void op_cpc(uint16_t op);
+ void op_sbc(uint16_t op);
+ void op_add(uint16_t op);
+ void op_cpse(uint16_t op);
+ void op_cp(uint16_t op);
+ void op_sub(uint16_t op);
+ void op_adc(uint16_t op);
+ void op_and(uint16_t op);
+ void op_eor(uint16_t op);
+ void op_or(uint16_t op);
+ void op_mov(uint16_t op);
+ void op_cpi(uint16_t op);
+ void op_sbci(uint16_t op);
+ void op_subi(uint16_t op);
+ void op_ori(uint16_t op);
+ void op_andi(uint16_t op);
+ void op_lddz(uint16_t op);
+ void op_lddy(uint16_t op);
+ void op_stdz(uint16_t op);
+ void op_stdy(uint16_t op);
+ void op_lds(uint16_t op);
+ void op_ldzi(uint16_t op);
+ void op_ldzd(uint16_t op);
+ void op_lpmz(uint16_t op);
+ void op_lpmzi(uint16_t op);
+ void op_elpmz(uint16_t op);
+ void op_elpmzi(uint16_t op);
+ void op_ldyi(uint16_t op);
+ void op_ldyd(uint16_t op);
+ void op_ldx(uint16_t op);
+ void op_ldxi(uint16_t op);
+ void op_ldxd(uint16_t op);
+ void op_pop(uint16_t op);
+ void op_sts(uint16_t op);
+ void op_stzi(uint16_t op);
+ void op_stzd(uint16_t op);
+ void op_styi(uint16_t op);
+ void op_styd(uint16_t op);
+ void op_stx(uint16_t op);
+ void op_stxi(uint16_t op);
+ void op_stxd(uint16_t op);
+ void op_push(uint16_t op);
+ void op_com(uint16_t op);
+ void op_neg(uint16_t op);
+ void op_swap(uint16_t op);
+ void op_inc(uint16_t op);
+ void op_asr(uint16_t op);
+ void op_lsr(uint16_t op);
+ void op_ror(uint16_t op);
+ void op_setf(uint16_t op);
+ void op_clrf(uint16_t op);
+ void op_ijmp(uint16_t op);
+ void op_eijmp(uint16_t op);
+ void op_dec(uint16_t op);
+ void op_jmp(uint16_t op);
+ void op_call(uint16_t op);
+ void op_ret(uint16_t op);
+ void op_reti(uint16_t op);
+ void op_sleep(uint16_t op);
+ void op_break(uint16_t op);
+ void op_wdr(uint16_t op);
+ void op_lpm(uint16_t op);
+ void op_elpm(uint16_t op);
+ void op_spm(uint16_t op);
+ void op_spmzi(uint16_t op);
+ void op_icall(uint16_t op);
+ void op_eicall(uint16_t op);
+ void op_adiw(uint16_t op);
+ void op_sbiw(uint16_t op);
+ void op_cbi(uint16_t op);
+ void op_sbic(uint16_t op);
+ void op_sbi(uint16_t op);
+ void op_sbis(uint16_t op);
+ void op_mul(uint16_t op);
+ void op_out(uint16_t op);
+ void op_in(uint16_t op);
+ void op_rjmp(uint16_t op);
+ void op_rcall(uint16_t op);
+ void op_ldi(uint16_t op);
+ void op_brset(uint16_t op);
+ void op_brclr(uint16_t op);
+ void op_bst(uint16_t op);
+ void op_bld(uint16_t op);
+ void op_sbrs(uint16_t op);
+ void op_sbrc(uint16_t op);
+ void op_unimpl(uint16_t op);
+
+ // address spaces
+ address_space *m_program;
+ address_space *m_data;
+
+ static const interrupt_condition s_int_conditions[INTIDX_COUNT];
+ static const interrupt_condition s_mega644_int_conditions[INTIDX_COUNT];
+};
+
+// ======================> avr8_device
+
+template <int NumTimers>
+class avr8_device : public avr8_base_device
+{
+public:
+ // GPIO
+ template <gpio_t Port> auto gpio_out() { return m_gpio_out_cb[Port].bind(); }
+ template <gpio_t Port> auto gpio_in() { return m_gpio_in_cb[Port].bind(); }
+ template <int Port> uint8_t pin_r();
+ template <int Port> void port_w(uint8_t data);
+ template <int Port> uint8_t gpio_r();
+
+ // ADC
+ template<uint8_t Pin> auto adc_in() { return m_adc_in_cb[Pin].bind(); }
+
+protected:
+ avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, uint32_t address_mask, address_map_constructor internal_map);
+
+ typedef delegate<void (void)> timer_func;
+
+ // device-level overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+
+ // device_execute_interface overrides
+ virtual void execute_run() override;
+
+ // address maps
+ void base_internal_map(address_map &map) ATTR_COLD;
+
+ // Miscellaneous registers
+ void wdtcsr_w(uint8_t data);
+ void clkpr_w(uint8_t data);
+ void prr0_w(uint8_t data);
+ void prr1_w(uint8_t data);
+ void osccal_w(uint8_t data);
+ void pcicr_w(uint8_t data);
+ void eicra_w(uint8_t data);
+ void eicrb_w(uint8_t data);
+ void pcmsk0_w(uint8_t data);
+ void pcmsk1_w(uint8_t data);
+ void pcmsk2_w(uint8_t data);
+ void xmcra_w(uint8_t data);
+ void xmcrb_w(uint8_t data);
+ void didr0_w(uint8_t data);
+ void didr1_w(uint8_t data);
+ void didr2_w(uint8_t data);
+ void assr_w(uint8_t data);
+ void twbr_w(uint8_t data);
+ uint8_t twsr_r();
+ void twsr_w(uint8_t data);
+ void twar_w(uint8_t data);
+ void twdr_w(uint8_t data);
+ void twcr_w(uint8_t data);
+ void twamr_w(uint8_t data);
+ void ucsr0a_w(uint8_t data);
+ void ucsr0b_w(uint8_t data);
+ void ucsr0c_w(uint8_t data);
+
+ // EEPROM
+ void eecr_w(uint8_t data);
+
+ void gpior0_w(uint8_t data);
+ void gpior1_w(uint8_t data);
+ void gpior2_w(uint8_t data);
+
+ devcb_write8::array<11> m_gpio_out_cb;
+ devcb_read8::array<11> m_gpio_in_cb;
+
+ // ADC
+ uint8_t adcl_r();
+ void adcl_w(uint8_t data);
+ uint8_t adch_r();
+ void adch_w(uint8_t data);
+ void adcsra_w(uint8_t data);
+ void adcsrb_w(uint8_t data);
+ void admux_w(uint8_t data);
+
+ void adc_start_conversion();
+ TIMER_CALLBACK_MEMBER(adc_conversion_complete);
+
+ devcb_read16::array<8> m_adc_in_cb;
+ emu_timer *m_adc_timer;
+ uint16_t m_adc_sample;
+ uint16_t m_adc_result;
+ uint16_t m_adc_data;
+ bool m_adc_first;
+ bool m_adc_hold;
+
+ // SPI
+ void spsr_w(uint8_t data);
+ void spcr_w(uint8_t data);
+ void spdr_w(uint8_t data);
+
+ void spi_tick();
+ void enable_spi();
+ void disable_spi();
+ void spi_update_masterslave_select();
+ void spi_update_clock_polarity();
+ void spi_update_clock_phase();
+ void spi_update_clock_rate();
+ void change_spcr(uint8_t data);
+ void change_spsr(uint8_t data);
+
+ bool m_spi_active;
+ uint8_t m_spi_prescale;
+ uint8_t m_spi_prescale_count;
+ int8_t m_spi_prescale_countdown;
+
// timers
- void timer_tick(int cycles);
- void update_timer_clock_source(uint8_t timer, uint8_t selection);
+ void gtccr_w(uint8_t data);
+
+ template <int Timer> void update_timer_clock_source(uint8_t selection, const uint8_t old_clock_select);
void update_timer_waveform_gen_mode(uint8_t timer, uint8_t mode);
+ int32_t m_timer_top[6];
+ uint16_t m_timer_prescale[6];
+ uint16_t m_timer_prescale_count[6];
+
// timer 0
- void timer0_tick();
- void changed_tccr0a(uint8_t data);
- void changed_tccr0b(uint8_t data);
+ void tccr0a_w(uint8_t data);
+ void tccr0b_w(uint8_t data);
+ void ocr0a_w(uint8_t data);
+ void ocr0b_w(uint8_t data);
+ void tifr0_w(uint8_t data);
+ void timsk0_w(uint8_t data);
+
+ void timer0_tick_norm();
+ void timer0_tick_pwm_pc();
+ void timer0_tick_ctc_norm();
+ void timer0_tick_ctc_toggle();
+ void timer0_tick_ctc_clear();
+ void timer0_tick_ctc_set();
+ void timer0_tick_fast_pwm();
+ void timer0_tick_pwm_pc_cmp();
+ void timer0_tick_fast_pwm_cmp();
+ void timer0_tick_default();
+
void update_ocr0(uint8_t newval, uint8_t reg);
void timer0_force_output_compare(int reg);
+ timer_func m_timer0_ticks[8*4];
+ timer_func m_timer0_tick;
+
// timer 1
- void timer1_tick();
- void changed_tccr1a(uint8_t data);
- void changed_tccr1b(uint8_t data);
+ enum wgm1_mode_t
+ {
+ 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 ocr_mode_t
+ {
+ OCR_NORM = 0,
+ OCR_TOGGLE,
+ OCR_CLEAR,
+ OCR_SET
+ };
+
+ void tccr1a_w(uint8_t data);
+ void tccr1b_w(uint8_t data);
+ void tccr1c_w(uint8_t data);
+ //void tcnt1l_w(uint8_t data);
+ //void tcnt1h_w(uint8_t data);
+ void icr1l_w(uint8_t data);
+ void icr1h_w(uint8_t data);
+ void ocr1al_w(uint8_t data);
+ void ocr1ah_w(uint8_t data);
+ void ocr1bl_w(uint8_t data);
+ void ocr1bh_w(uint8_t data);
+ void ocr1cl_w(uint8_t data);
+ void ocr1ch_w(uint8_t data);
+ void tifr1_w(uint8_t data);
+ void timsk1_w(uint8_t data);
+
+ template <int TimerMode, int ChannelModeA, int ChannelModeB> void timer1_tick();
+ void timer1_tick_normal() { timer1_tick<WGM1_NORMAL, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm8_pc() { timer1_tick<WGM1_PWM_8_PC, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm9_pc() { timer1_tick<WGM1_PWM_9_PC, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm10_pc() { timer1_tick<WGM1_PWM_10_PC, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_ctc_ocr_norm_norm() { timer1_tick<WGM1_CTC_OCR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_ctc_ocr_norm_toggle() { timer1_tick<WGM1_CTC_OCR, OCR_NORM, OCR_TOGGLE>(); };
+ void timer1_tick_ctc_ocr_norm_clear() { timer1_tick<WGM1_CTC_OCR, OCR_NORM, OCR_CLEAR>(); };
+ void timer1_tick_ctc_ocr_norm_set() { timer1_tick<WGM1_CTC_OCR, OCR_NORM, OCR_SET>(); };
+ void timer1_tick_ctc_ocr_toggle_norm() { timer1_tick<WGM1_CTC_OCR, OCR_TOGGLE, OCR_NORM>(); };
+ void timer1_tick_ctc_ocr_toggle_toggle() { timer1_tick<WGM1_CTC_OCR, OCR_TOGGLE, OCR_TOGGLE>(); };
+ void timer1_tick_ctc_ocr_toggle_clear() { timer1_tick<WGM1_CTC_OCR, OCR_TOGGLE, OCR_CLEAR>(); };
+ void timer1_tick_ctc_ocr_toggle_set() { timer1_tick<WGM1_CTC_OCR, OCR_TOGGLE, OCR_SET>(); };
+ void timer1_tick_ctc_ocr_clear_norm() { timer1_tick<WGM1_CTC_OCR, OCR_CLEAR, OCR_NORM>(); };
+ void timer1_tick_ctc_ocr_clear_toggle() { timer1_tick<WGM1_CTC_OCR, OCR_CLEAR, OCR_TOGGLE>(); };
+ void timer1_tick_ctc_ocr_clear_clear() { timer1_tick<WGM1_CTC_OCR, OCR_CLEAR, OCR_CLEAR>(); };
+ void timer1_tick_ctc_ocr_clear_set() { timer1_tick<WGM1_CTC_OCR, OCR_CLEAR, OCR_SET>(); };
+ void timer1_tick_ctc_ocr_set_norm() { timer1_tick<WGM1_CTC_OCR, OCR_SET, OCR_NORM>(); };
+ void timer1_tick_ctc_ocr_set_toggle() { timer1_tick<WGM1_CTC_OCR, OCR_SET, OCR_TOGGLE>(); };
+ void timer1_tick_ctc_ocr_set_clear() { timer1_tick<WGM1_CTC_OCR, OCR_SET, OCR_CLEAR>(); };
+ void timer1_tick_ctc_ocr_set_set() { timer1_tick<WGM1_CTC_OCR, OCR_SET, OCR_SET>(); };
+ void timer1_tick_fast_pwm8() { timer1_tick<WGM1_FAST_PWM_8, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_fast_pwm9() { timer1_tick<WGM1_FAST_PWM_9, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_fast_pwm10() { timer1_tick<WGM1_FAST_PWM_10, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm_pfc_icr() { timer1_tick<WGM1_PWM_PFC_ICR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm_pfc_ocr() { timer1_tick<WGM1_PWM_PFC_OCR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm_pc_icr() { timer1_tick<WGM1_PWM_PC_ICR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_pwm_pc_ocr() { timer1_tick<WGM1_PWM_PC_OCR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_ctc_icr() { timer1_tick<WGM1_CTC_ICR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_resv() { timer1_tick<WGM1_RESERVED, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_icr_norm_norm() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_icr_norm_toggle() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_NORM, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_icr_norm_clear() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_NORM, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_icr_norm_set() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_NORM, OCR_SET>(); };
+ void timer1_tick_fast_pwm_icr_toggle_norm() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_TOGGLE, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_icr_toggle_toggle() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_TOGGLE, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_icr_toggle_clear() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_TOGGLE, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_icr_toggle_set() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_TOGGLE, OCR_SET>(); };
+ void timer1_tick_fast_pwm_icr_clear_norm() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_CLEAR, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_icr_clear_toggle() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_CLEAR, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_icr_clear_clear() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_CLEAR, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_icr_clear_set() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_CLEAR, OCR_SET>(); };
+ void timer1_tick_fast_pwm_icr_set_norm() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_SET, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_icr_set_toggle() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_SET, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_icr_set_clear() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_SET, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_icr_set_set() { timer1_tick<WGM1_FAST_PWM_ICR, OCR_SET, OCR_SET>(); };
+ void timer1_tick_fast_pwm_ocr_norm_norm() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_NORM, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_ocr_norm_toggle() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_NORM, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_ocr_norm_clear() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_NORM, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_ocr_norm_set() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_NORM, OCR_SET>(); };
+ void timer1_tick_fast_pwm_ocr_toggle_norm() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_TOGGLE, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_ocr_toggle_toggle() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_TOGGLE, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_ocr_toggle_clear() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_TOGGLE, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_ocr_toggle_set() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_TOGGLE, OCR_SET>(); };
+ void timer1_tick_fast_pwm_ocr_clear_norm() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_CLEAR, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_ocr_clear_toggle() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_CLEAR, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_ocr_clear_clear() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_CLEAR, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_ocr_clear_set() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_CLEAR, OCR_SET>(); };
+ void timer1_tick_fast_pwm_ocr_set_norm() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_SET, OCR_NORM>(); };
+ void timer1_tick_fast_pwm_ocr_set_toggle() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_SET, OCR_TOGGLE>(); };
+ void timer1_tick_fast_pwm_ocr_set_clear() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_SET, OCR_CLEAR>(); };
+ void timer1_tick_fast_pwm_ocr_set_set() { timer1_tick<WGM1_FAST_PWM_OCR, OCR_SET, OCR_SET>(); };
void update_timer1_input_noise_canceler();
void update_timer1_input_edge_select();
void update_ocr1(uint16_t newval, uint8_t reg);
+ timer_func m_timer1_ticks[16*16];
+ timer_func m_timer1_tick;
+ uint16_t m_ocr1[3];
+
// timer 2
- void timer2_tick();
- void changed_tccr2a(uint8_t data);
- void changed_tccr2b(uint8_t data);
+ void tccr2a_w(uint8_t data);
+ void tccr2b_w(uint8_t data);
+ void tcnt2_w(uint8_t data);
+ void ocr2a_w(uint8_t data);
+ void ocr2b_w(uint8_t data);
+ void tifr2_w(uint8_t data);
+ void timsk2_w(uint8_t data);
+
+ void timer2_tick_default();
+ void timer2_tick_norm();
+ void timer2_tick_fast_pwm();
+ void timer2_tick_fast_pwm_cmp();
void update_ocr2(uint8_t newval, uint8_t reg);
void timer2_force_output_compare(int reg);
+ timer_func m_timer2_ticks[8];
+ timer_func m_timer2_tick;
+ bool m_ocr2_not_reached_yet;
+
// timer 3
+ void tccr3a_w(uint8_t data);
+ void tccr3b_w(uint8_t data);
+ void tccr3c_w(uint8_t data);
+ //void tcnt3l_w(uint8_t data);
+ //void tcnt3h_w(uint8_t data);
+ void icr3l_w(uint8_t data);
+ void icr3h_w(uint8_t data);
+ void ocr3al_w(uint8_t data);
+ void ocr3ah_w(uint8_t data);
+ void ocr3bl_w(uint8_t data);
+ void ocr3bh_w(uint8_t data);
+ void ocr3cl_w(uint8_t data);
+ void ocr3ch_w(uint8_t data);
+ void timsk3_w(uint8_t data);
+
void timer3_tick();
- void changed_tccr3a(uint8_t data);
- void changed_tccr3b(uint8_t data);
- void changed_tccr3c(uint8_t data);
-// void update_ocr3(uint8_t newval, uint8_t reg);
-// void timer3_force_output_compare(int reg);
// timer 4
+ void tccr4a_w(uint8_t data);
+ void tccr4b_w(uint8_t data);
+ void tccr4c_w(uint8_t data);
+ void tcnt4l_w(uint8_t data);
+ void tcnt4h_w(uint8_t data);
+ void icr4l_w(uint8_t data);
+ void icr4h_w(uint8_t data);
+ void ocr4al_w(uint8_t data);
+ void ocr4ah_w(uint8_t data);
+ void ocr4bl_w(uint8_t data);
+ void ocr4bh_w(uint8_t data);
+ void ocr4cl_w(uint8_t data);
+ void ocr4ch_w(uint8_t data);
+ void timsk4_w(uint8_t data);
+
void timer4_tick();
- void changed_tccr4a(uint8_t data);
- void changed_tccr4b(uint8_t data);
- void changed_tccr4c(uint8_t data);
- //void update_ocr4(uint8_t newval, uint8_t reg);
- //void timer4_force_output_compare(int reg);
// timer 5
- void timer5_tick();
- void changed_tccr5a(uint8_t data);
- void changed_tccr5b(uint8_t data);
-// void update_ocr5(uint8_t newval, uint8_t reg);
-// void timer5_force_output_compare(int reg);
+ void tccr5a_w(uint8_t data);
+ void tccr5b_w(uint8_t data);
+ void timsk5_w(uint8_t data);
- // address spaces
- address_space *m_program;
- address_space *m_data;
- address_space *m_io;
+ void timer5_tick();
};
// device type definition
DECLARE_DEVICE_TYPE(ATMEGA88, atmega88_device)
+DECLARE_DEVICE_TYPE(ATMEGA168, atmega168_device)
+DECLARE_DEVICE_TYPE(ATMEGA328, atmega328_device)
DECLARE_DEVICE_TYPE(ATMEGA644, atmega644_device)
DECLARE_DEVICE_TYPE(ATMEGA1280, atmega1280_device)
DECLARE_DEVICE_TYPE(ATMEGA2560, atmega2560_device)
+DECLARE_DEVICE_TYPE(ATTINY15, attiny15_device)
// ======================> atmega88_device
-class atmega88_device : public avr8_device
+class atmega88_device : public avr8_device<3>
{
public:
// construction/destruction
atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- void atmega88_internal_map(address_map &map);
+ void atmega88_internal_map(address_map &map) ATTR_COLD;
+};
+
+// ======================> atmega168_device
+
+class atmega168_device : public avr8_device<3>
+{
+public:
+ // construction/destruction
+ atmega168_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void update_interrupt(int source) override;
+ void atmega168_internal_map(address_map &map) ATTR_COLD;
+};
+
+// ======================> atmega328_device
+
+class atmega328_device : public avr8_device<3>
+{
+public:
+ // construction/destruction
+ atmega328_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void update_interrupt(int source) override;
+ void atmega328_internal_map(address_map &map) ATTR_COLD;
};
// ======================> atmega644_device
-class atmega644_device : public avr8_device
+class atmega644_device : public avr8_device<3>
{
public:
// construction/destruction
atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual void update_interrupt(int source) override;
- void atmega644_internal_map(address_map &map);
+ void atmega644_internal_map(address_map &map) ATTR_COLD;
};
// ======================> atmega1280_device
-class atmega1280_device : public avr8_device
+class atmega1280_device : public avr8_device<6>
{
public:
// construction/destruction
atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual void update_interrupt(int source) override;
- void atmega1280_internal_map(address_map &map);
+ void atmega1280_internal_map(address_map &map) ATTR_COLD;
};
// ======================> atmega2560_device
-class atmega2560_device : public avr8_device
+class atmega2560_device : public avr8_device<6>
{
public:
// construction/destruction
atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual void update_interrupt(int source) override;
- void atmega2560_internal_map(address_map &map);
+ void atmega2560_internal_map(address_map &map) ATTR_COLD;
+};
+
+// ======================> attiny15_device
+
+class attiny15_device : public avr8_device<2>
+{
+public:
+ // construction/destruction
+ attiny15_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void attiny15_internal_map(address_map &map) ATTR_COLD;
};
/***************************************************************************
REGISTER ENUMERATION
***************************************************************************/
-enum
+enum : uint8_t
{
AVR8_SREG = 1,
AVR8_PC,
@@ -320,510 +1221,4 @@ enum
AVR8_SPL
};
-enum
-{
- AVR8_INT_RESET = 0,
- AVR8_INT_INT0,
- AVR8_INT_INT1,
- AVR8_INT_PCINT0,
- AVR8_INT_PCINT1,
- AVR8_INT_PCINT2,
- AVR8_INT_WDT,
- AVR8_INT_T2COMPA,
- AVR8_INT_T2COMPB,
- AVR8_INT_T2OVF,
- AVR8_INT_T1CAPT,
- AVR8_INT_T1COMPA,
- AVR8_INT_T1COMPB,
- AVR8_INT_T1OVF,
- AVR8_INT_T0COMPA,
- AVR8_INT_T0COMPB,
- AVR8_INT_T0OVF,
- AVR8_INT_SPI_STC,
- AVR8_INT_USART_RX,
- AVR8_INT_USART_UDRE,
- AVR8_INT_USART_TX,
- AVR8_INT_ADC,
- AVR8_INT_EE_RDY,
- AVR8_INT_ANALOG_COMP,
- AVR8_INT_TWI,
- AVR8_INT_SPM_RDY,
-
- // ATMEGA644
- ATMEGA644_INT_RESET = 0,
- ATMEGA644_INT_INT0,
- ATMEGA644_INT_INT1,
- ATMEGA644_INT_INT2,
- ATMEGA644_INT_PCINT0,
- ATMEGA644_INT_PCINT1,
- ATMEGA644_INT_PCINT2,
- ATMEGA644_INT_PCINT3,
- ATMEGA644_INT_WDT,
- ATMEGA644_INT_T2COMPA,
- ATMEGA644_INT_T2COMPB,
- ATMEGA644_INT_T2OVF,
- ATMEGA644_INT_T1CAPT,
- ATMEGA644_INT_T1COMPA,
- ATMEGA644_INT_T1COMPB,
- ATMEGA644_INT_T1OVF,
- ATMEGA644_INT_T0COMPA,
- ATMEGA644_INT_T0COMPB,
- ATMEGA644_INT_T0OVF,
- ATMEGA644_INT_SPI_STC,
- ATMEGA644_INT_USART_RX,
- ATMEGA644_INT_USART_UDRE,
- ATMEGA644_INT_USART_TX,
- ATMEGA644_INT_ADC,
- ATMEGA644_INT_EE_RDY,
- ATMEGA644_INT_ANALOG_COMP,
- ATMEGA644_INT_TWI,
- ATMEGA644_INT_SPM_RDY
-};
-
-// Used by I/O register handling
-enum
-{
- AVR8_REGIDX_R0 = 0x00,
- AVR8_REGIDX_R1,
- AVR8_REGIDX_R2,
- AVR8_REGIDX_R3,
- AVR8_REGIDX_R4,
- AVR8_REGIDX_R5,
- AVR8_REGIDX_R6,
- AVR8_REGIDX_R7,
- AVR8_REGIDX_R8,
- AVR8_REGIDX_R9,
- AVR8_REGIDX_R10,
- AVR8_REGIDX_R11,
- AVR8_REGIDX_R12,
- AVR8_REGIDX_R13,
- AVR8_REGIDX_R14,
- AVR8_REGIDX_R15,
- AVR8_REGIDX_R16,
- AVR8_REGIDX_R17,
- AVR8_REGIDX_R18,
- AVR8_REGIDX_R19,
- AVR8_REGIDX_R20,
- AVR8_REGIDX_R21,
- AVR8_REGIDX_R22,
- AVR8_REGIDX_R23,
- AVR8_REGIDX_R24,
- AVR8_REGIDX_R25,
- AVR8_REGIDX_R26,
- AVR8_REGIDX_R27,
- AVR8_REGIDX_R28,
- AVR8_REGIDX_R29,
- AVR8_REGIDX_R30,
- AVR8_REGIDX_R31,
- AVR8_REGIDX_PINA = 0x20,
- AVR8_REGIDX_DDRA,
- AVR8_REGIDX_PORTA,
- AVR8_REGIDX_PINB,
- AVR8_REGIDX_DDRB,
- AVR8_REGIDX_PORTB,
- AVR8_REGIDX_PINC,
- AVR8_REGIDX_DDRC,
- AVR8_REGIDX_PORTC,
- AVR8_REGIDX_PIND,
- AVR8_REGIDX_DDRD,
- AVR8_REGIDX_PORTD,
- AVR8_REGIDX_PINE,
- AVR8_REGIDX_DDRE,
- AVR8_REGIDX_PORTE,
- AVR8_REGIDX_PINF,
- AVR8_REGIDX_DDRF,
- AVR8_REGIDX_PORTF,
- AVR8_REGIDX_PING,
- AVR8_REGIDX_DDRG,
- AVR8_REGIDX_PORTG,
- AVR8_REGIDX_TIFR0 = 0x35,
- AVR8_REGIDX_TIFR1,
- AVR8_REGIDX_TIFR2,
- AVR8_REGIDX_TIFR3,
- AVR8_REGIDX_TIFR4,
- AVR8_REGIDX_TIFR5,
- AVR8_REGIDX_PCIFR = 0x3B,
- AVR8_REGIDX_EIFR,
- AVR8_REGIDX_EIMSK,
- AVR8_REGIDX_GPIOR0,
- AVR8_REGIDX_EECR,
- AVR8_REGIDX_EEDR,
- AVR8_REGIDX_EEARL,
- AVR8_REGIDX_EEARH,
- AVR8_REGIDX_GTCCR,
- AVR8_REGIDX_TCCR0A,
- AVR8_REGIDX_TCCR0B,
- AVR8_REGIDX_TCNT0,
- AVR8_REGIDX_OCR0A,
- AVR8_REGIDX_OCR0B,
- //0x49: Reserved
- AVR8_REGIDX_GPIOR1 = 0x4A,
- AVR8_REGIDX_GPIOR2,
- AVR8_REGIDX_SPCR,
- AVR8_REGIDX_SPSR,
- AVR8_REGIDX_SPDR,
- //0x4F: Reserved
- AVR8_REGIDX_ACSR = 0x50,
- AVR8_REGIDX_OCDR,
- //0x52: Reserved
- AVR8_REGIDX_SMCR = 0x53,
- AVR8_REGIDX_MCUSR,
- AVR8_REGIDX_MCUCR,
- //0x56: Reserved
- AVR8_REGIDX_SPMCSR = 0x57,
- //0x58: Reserved
- //0x59: Reserved
- //0x5A: Reserved
- AVR8_REGIDX_RAMPZ = 0x5B,
- AVR8_REGIDX_EIND,
- AVR8_REGIDX_SPL,
- AVR8_REGIDX_SPH,
- AVR8_REGIDX_SREG,
-//--------------------------
- AVR8_REGIDX_WDTCSR = 0x60,
- AVR8_REGIDX_CLKPR,
- //0x62: Reserved
- //0x63: Reserved
- AVR8_REGIDX_PRR0 = 0x64,
- AVR8_REGIDX_PRR1,
- AVR8_REGIDX_OSCCAL,
- //0x67: Reserved
- AVR8_REGIDX_PCICR = 0x68,
- AVR8_REGIDX_EICRA,
- AVR8_REGIDX_EICRB,
- AVR8_REGIDX_PCMSK0,
- AVR8_REGIDX_PCMSK1,
- AVR8_REGIDX_PCMSK2,
- AVR8_REGIDX_TIMSK0,
- AVR8_REGIDX_TIMSK1,
- AVR8_REGIDX_TIMSK2,
- AVR8_REGIDX_TIMSK3,
- AVR8_REGIDX_TIMSK4,
- AVR8_REGIDX_TIMSK5,
- AVR8_REGIDX_XMCRA,
- AVR8_REGIDX_XMCRB,
- //0x76: Reserved
- //0x77: Reserved
- AVR8_REGIDX_ADCL = 0x78,
- AVR8_REGIDX_ADCH,
- AVR8_REGIDX_ADCSRA,
- AVR8_REGIDX_ADCSRB,
- AVR8_REGIDX_ADMUX,
- AVR8_REGIDX_DIDR2,
- AVR8_REGIDX_DIDR0,
- AVR8_REGIDX_DIDR1,
- AVR8_REGIDX_TCCR1A,
- AVR8_REGIDX_TCCR1B,
- AVR8_REGIDX_TCCR1C,
- //0x83: Reserved
- AVR8_REGIDX_TCNT1L = 0x84,
- AVR8_REGIDX_TCNT1H,
- AVR8_REGIDX_ICR1L,
- AVR8_REGIDX_ICR1H,
- AVR8_REGIDX_OCR1AL,
- AVR8_REGIDX_OCR1AH,
- AVR8_REGIDX_OCR1BL,
- AVR8_REGIDX_OCR1BH,
- AVR8_REGIDX_OCR1CL,
- AVR8_REGIDX_OCR1CH,
- //0x8E: Reserved
- //0x8F: Reserved
- AVR8_REGIDX_TCCR3A = 0x90,
- AVR8_REGIDX_TCCR3B,
- AVR8_REGIDX_TCCR3C,
- //0x93: Reserved
- AVR8_REGIDX_TCNT3L = 0x94,
- AVR8_REGIDX_TCNT3H,
- AVR8_REGIDX_ICR3L,
- AVR8_REGIDX_ICR3H,
- AVR8_REGIDX_OCR3AL,
- AVR8_REGIDX_OCR3AH,
- AVR8_REGIDX_OCR3BL,
- AVR8_REGIDX_OCR3BH,
- AVR8_REGIDX_OCR3CL,
- AVR8_REGIDX_OCR3CH,
- //0x9E: Reserved
- //0x9F: Reserved
- AVR8_REGIDX_TCCR4A = 0xA0,
- AVR8_REGIDX_TCCR4B,
- AVR8_REGIDX_TCCR4C,
- //0xA3: Reserved
- AVR8_REGIDX_TCNT4L = 0xA4,
- AVR8_REGIDX_TCNT4H,
- AVR8_REGIDX_ICR4L,
- AVR8_REGIDX_ICR4H,
- AVR8_REGIDX_OCR4AL,
- AVR8_REGIDX_OCR4AH,
- AVR8_REGIDX_OCR4BL,
- AVR8_REGIDX_OCR4BH,
- AVR8_REGIDX_OCR4CL,
- AVR8_REGIDX_OCR4CH,
- //0xAE: Reserved
- //0xAF: Reserved
- AVR8_REGIDX_TCCR2A = 0xB0,
- AVR8_REGIDX_TCCR2B,
- AVR8_REGIDX_TCNT2,
- AVR8_REGIDX_OCR2A,
- AVR8_REGIDX_OCR2B,
- //0xB5: Reserved
- AVR8_REGIDX_ASSR = 0xB6,
- //0xB7: Reserved
- AVR8_REGIDX_TWBR = 0xB8,
- AVR8_REGIDX_TWSR,
- AVR8_REGIDX_TWAR,
- AVR8_REGIDX_TWDR,
- AVR8_REGIDX_TWCR,
- AVR8_REGIDX_TWAMR,
- //0xBE: Reserved
- //0xBF: Reserved
- AVR8_REGIDX_UCSR0A = 0xC0,
- AVR8_REGIDX_UCSR0B,
- AVR8_REGIDX_UCSR0C,
- //0xC3: Reserved
- AVR8_REGIDX_UBRR0L = 0xC4,
- AVR8_REGIDX_UBRR0H,
- AVR8_REGIDX_UDR0,
- //0xC7: Reserved
- AVR8_REGIDX_UCSR1A = 0xC8,
- AVR8_REGIDX_UCSR1B,
- AVR8_REGIDX_UCSR1C,
- //0xCB: Reserved
- AVR8_REGIDX_UBRR1L = 0xCC,
- AVR8_REGIDX_UBRR1H,
- AVR8_REGIDX_UDR1,
- //0xCF: Reserved
- AVR8_REGIDX_UCSR2A = 0xD0,
- AVR8_REGIDX_UCSR2B,
- AVR8_REGIDX_UCSR2C,
- //0xD3: Reserved
- AVR8_REGIDX_UBRR2L = 0xD4,
- AVR8_REGIDX_UBRR2H,
- AVR8_REGIDX_UDR2,
- //0xD7: Reserved
- //0xD8: Reserved
- //0xD9: Reserved
- //0xDA: Reserved
- //0xDB: Reserved
- //0xDC: Reserved
- //0xDD: Reserved
- //0xDE: Reserved
- //0xDF: Reserved
- //0xE0: Reserved
- //0xE1: Reserved
- //0xE2: Reserved
- //0xE3: Reserved
- //0xE4: Reserved
- //0xE5: Reserved
- //0xE6: Reserved
- //0xE7: Reserved
- //0xE8: Reserved
- //0xE9: Reserved
- //0xEA: Reserved
- //0xEB: Reserved
- //0xEC: Reserved
- //0xED: Reserved
- //0xEE: Reserved
- //0xEF: Reserved
- //0xF0: Reserved
- //0xF1: Reserved
- //0xF2: Reserved
- //0xF3: Reserved
- //0xF4: Reserved
- //0xF5: Reserved
- //0xF6: Reserved
- //0xF7: Reserved
- //0xF8: Reserved
- //0xF9: Reserved
- //0xFA: Reserved
- //0xFB: Reserved
- //0xFC: Reserved
- //0xFD: Reserved
- //0xFE: Reserved
- //0xFF: Reserved
- AVR8_REGIDX_PINH = 0x100,
- AVR8_REGIDX_DDRH,
- AVR8_REGIDX_PORTH,
- AVR8_REGIDX_PINJ,
- AVR8_REGIDX_DDRJ,
- AVR8_REGIDX_PORTJ,
- AVR8_REGIDX_PINK,
- AVR8_REGIDX_DDRK,
- AVR8_REGIDX_PORTK,
- AVR8_REGIDX_PINL,
- AVR8_REGIDX_DDRL,
- AVR8_REGIDX_PORTL,
- //0x10C: Reserved
- //0x10D: Reserved
- //0x10E: Reserved
- //0x10F: Reserved
- //0x110: Reserved
- //0x111: Reserved
- //0x112: Reserved
- //0x113: Reserved
- //0x114: Reserved
- //0x115: Reserved
- //0x116: Reserved
- //0x117: Reserved
- //0x118: Reserved
- //0x119: Reserved
- //0x11A: Reserved
- //0x11B: Reserved
- //0x11C: Reserved
- //0x11D: Reserved
- //0x11E: Reserved
- //0x11F: Reserved
- AVR8_REGIDX_TCCR5A = 0x120,
- AVR8_REGIDX_TCCR5B,
- AVR8_REGIDX_TCCR5C,
- //0x123: Reserved
- AVR8_REGIDX_TCNT5L = 0x124,
- AVR8_REGIDX_TCNT5H,
- AVR8_REGIDX_ICR5L,
- AVR8_REGIDX_ICR5H,
- AVR8_REGIDX_OCR5AL,
- AVR8_REGIDX_OCR5AH,
- AVR8_REGIDX_OCR5BL,
- AVR8_REGIDX_OCR5BH,
- AVR8_REGIDX_OCR5CL,
- AVR8_REGIDX_OCR5CH,
- //0x12E: Reserved
- //0x12F: Reserved
- AVR8_REGIDX_UCSR3A = 0x130,
- AVR8_REGIDX_UCSR3B,
- AVR8_REGIDX_UCSR3C,
- //0x133: Reserved
- AVR8_REGIDX_UBRR3L = 0x134,
- AVR8_REGIDX_UBRR3H,
- AVR8_REGIDX_UDR3
- //0x137: Reserved
- // .
- // . up to
- // .
- //0x1FF: Reserved
-};
-
-enum {
- AVR8_IO_PORTA = 0,
- AVR8_IO_PORTB,
- AVR8_IO_PORTC,
- AVR8_IO_PORTD,
- AVR8_IO_PORTE,
- AVR8_IO_PORTF,
- AVR8_IO_PORTG,
- AVR8_IO_PORTH,
- AVR8_IO_PORTJ,
- AVR8_IO_PORTK,
- AVR8_IO_PORTL
-};
-
-//TODO: AVR8_REG_* and AVR8_IO_PORT* seem to serve the same purpose and thus should be unified. Verify this!
-enum
-{
- AVR8_REG_A = 0,
- AVR8_REG_B,
- AVR8_REG_C,
- AVR8_REG_D,
- AVR8_REG_E,
- AVR8_REG_F,
- AVR8_REG_G,
- AVR8_REG_H,
- AVR8_REG_J,
- AVR8_REG_K,
- AVR8_REG_L
-};
-
-enum
-{
- AVR8_INTIDX_SPI,
-
- AVR8_INTIDX_OCF0B,
- AVR8_INTIDX_OCF0A,
- AVR8_INTIDX_TOV0,
-
- AVR8_INTIDX_ICF1,
-
- AVR8_INTIDX_OCF1B,
- AVR8_INTIDX_OCF1A,
- AVR8_INTIDX_TOV1,
-
- AVR8_INTIDX_OCF2B,
- AVR8_INTIDX_OCF2A,
- AVR8_INTIDX_TOV2,
-
-//------ TODO: review this --------
- AVR8_INTIDX_OCF3B,
- AVR8_INTIDX_OCF3A,
- AVR8_INTIDX_TOV3,
-
- AVR8_INTIDX_OCF4B,
- AVR8_INTIDX_OCF4A,
- AVR8_INTIDX_TOV4,
-
- AVR8_INTIDX_OCF5B,
- AVR8_INTIDX_OCF5A,
- AVR8_INTIDX_TOV5,
-//---------------------------------
-
- AVR8_INTIDX_COUNT
-};
-
-//lock bit masks
-enum
-{
- LB1 = (1 << 0),
- LB2 = (1 << 1),
- BLB01 = (1 << 2),
- BLB02 = (1 << 3),
- BLB11 = (1 << 4),
- BLB12 = (1 << 5)
-};
-
-//extended fuses bit masks
-enum
-{
- BODLEVEL0 = (1 << 0),
- BODLEVEL1 = (1 << 1),
- BODLEVEL2 = (1 << 2)
-};
-
-//high fuses bit masks
-enum
-{
- BOOTRST = (1 << 0),
- BOOTSZ0 = (1 << 1),
- BOOTSZ1 = (1 << 2),
- EESAVE = (1 << 3),
- WDTON = (1 << 4),
- SPIEN = (1 << 5),
- JTAGEN = (1 << 6),
- OCDEN = (1 << 7)
-};
-
-//low fuses bit masks
-enum
-{
- CKSEL0 = (1 << 0),
- CKSEL1 = (1 << 1),
- CKSEL2 = (1 << 2),
- CKSEL3 = (1 << 3),
- SUT0 = (1 << 4),
- SUT1 = (1 << 5),
- CKOUT = (1 << 6),
- CKDIV8 = (1 << 7)
-};
-
-#define AVR8_EEARH_MASK 0x01
-
-#define AVR8_SPSR_SPIF_MASK 0x80
-#define AVR8_SPSR_SPIF_SHIFT 7
-#define AVR8_SPSR_SPR2X_MASK 0x01
-
-#define AVR8_SPCR_SPIE_MASK 0x80
-#define AVR8_SPCR_SPE_MASK 0x40
-#define AVR8_SPCR_DORD_MASK 0x20
-#define AVR8_SPCR_MSTR_MASK 0x10
-#define AVR8_SPCR_CPOL_MASK 0x08
-#define AVR8_SPCR_CPHA_MASK 0x04
-#define AVR8_SPCR_SPR_MASK 0x03
-
#endif /* MAME_CPU_AVR8_AVR8_H */
diff --git a/src/devices/cpu/avr8/avr8dasm.cpp b/src/devices/cpu/avr8/avr8dasm.cpp
index 5f47198c425..866845ceb15 100644
--- a/src/devices/cpu/avr8/avr8dasm.cpp
+++ b/src/devices/cpu/avr8/avr8dasm.cpp
@@ -104,575 +104,556 @@ offs_t avr8_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat
/* SPH */ { "SP8", "SP9", "SP10", "SP11", "SP12", "SP13", "SP14", "SP15"},
/* SREG */ { "C", "Z", "N", "V", "S", "H", "T", "I"}};
+ offs_t flags = 0;
switch(op & 0xf000)
{
+ case 0x0000:
+ switch(op & 0x0f00)
+ {
case 0x0000:
- switch(op & 0x0f00)
+ util::stream_format(stream, "NOP");
+ break;
+ case 0x0100:
+ util::stream_format(stream, "MOVW R%d:R%d, R%d:R%d", (RD4(op) << 1)+1, RD4(op) << 1, (RR4(op) << 1)+1, RR4(op) << 1);
+ break;
+ case 0x0200:
+ util::stream_format(stream, "MULS R%d, R%d", 16+RD4(op), 16+RR4(op));
+ break;
+ case 0x0300:
+ switch(MULCONST2(op))
{
- case 0x0000:
- util::stream_format(stream, "NOP");
- break;
- case 0x0100:
- util::stream_format(stream, "MOVW R%d:R%d, R%d:R%d", (RD4(op) << 1)+1, RD4(op) << 1, (RR4(op) << 1)+1, RR4(op) << 1);
- break;
- case 0x0200:
- util::stream_format(stream, "MULS R%d, R%d", 16+RD4(op), 16+RR4(op));
- break;
- case 0x0300:
- switch(MULCONST2(op))
- {
- case 0:
- util::stream_format(stream, "MULSU R%d, R%d", 16+RD3(op), 16+RR3(op));
- break;
- case 1:
- util::stream_format(stream, "FMUL R%d, R%d", 16+RD3(op), 16+RR3(op));
- break;
- case 2:
- util::stream_format(stream, "FMULS R%d, R%d", 16+RD3(op), 16+RR3(op));
- break;
- case 3:
- util::stream_format(stream, "FMULSU R%d, R%d", 16+RD3(op), 16+RR3(op));
- break;
- }
- break;
- case 0x0400:
- case 0x0500:
- case 0x0600:
- case 0x0700:
- util::stream_format(stream, "CPC R%d, R%d", RD5(op), RR5(op));
- break;
- case 0x0800:
- case 0x0900:
- case 0x0a00:
- case 0x0b00:
- util::stream_format(stream, "SBC R%d, R%d", RD5(op), RR5(op));
- break;
- case 0x0c00:
- case 0x0d00:
- case 0x0e00:
- case 0x0f00:
- util::stream_format(stream, "ADD R%d, R%d", RD5(op), RR5(op));
- break;
+ case 0:
+ util::stream_format(stream, "MULSU R%d, R%d", 16+RD3(op), 16+RR3(op));
+ break;
+ case 1:
+ util::stream_format(stream, "FMUL R%d, R%d", 16+RD3(op), 16+RR3(op));
+ break;
+ case 2:
+ util::stream_format(stream, "FMULS R%d, R%d", 16+RD3(op), 16+RR3(op));
+ break;
+ case 3:
+ util::stream_format(stream, "FMULSU R%d, R%d", 16+RD3(op), 16+RR3(op));
+ break;
}
break;
- case 0x1000:
- switch(op & 0x0c00)
+ case 0x0400:
+ case 0x0500:
+ case 0x0600:
+ case 0x0700:
+ util::stream_format(stream, "CPC R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0800:
+ case 0x0900:
+ case 0x0a00:
+ case 0x0b00:
+ util::stream_format(stream, "SBC R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00:
+ util::stream_format(stream, "ADD R%d, R%d", RD5(op), RR5(op));
+ break;
+ }
+ break;
+ case 0x1000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000:
+ util::stream_format(stream, "CPSE R%d, R%d", RD5(op), RR5(op));
+ flags = STEP_COND;
+ break;
+ case 0x0400:
+ util::stream_format(stream, "CP R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0800:
+ util::stream_format(stream, "SUB R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0c00:
+ util::stream_format(stream, "ADC R%d, R%d", RD5(op), RR5(op));
+ break;
+ }
+ break;
+ case 0x2000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000:
+ util::stream_format(stream, "AND R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0400:
+ util::stream_format(stream, "EOR R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0800:
+ util::stream_format(stream, "OR R%d, R%d", RD5(op), RR5(op));
+ break;
+ case 0x0c00:
+ util::stream_format(stream, "MOV R%d, R%d", RD5(op), RR5(op));
+ break;
+ }
+ break;
+ case 0x3000:
+ util::stream_format(stream, "CPI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
+ break;
+ case 0x4000:
+ util::stream_format(stream, "SBCI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
+ break;
+ case 0x5000:
+ util::stream_format(stream, "SUBI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
+ break;
+ case 0x6000:
+ util::stream_format(stream, "ORI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
+ break;
+ case 0x7000:
+ util::stream_format(stream, "ANDI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
+ break;
+ case 0x8000:
+ case 0xa000:
+ switch(op & 0x0208)
+ {
+ case 0x0000:
+ util::stream_format(stream, "LD(D) R%d, Z+%02x", RD5(op), QCONST6(op));
+ break;
+ case 0x0008:
+ util::stream_format(stream, "LD(D) R%d, Y+%02x", RD5(op), QCONST6(op));
+ break;
+ case 0x0200:
+ util::stream_format(stream, "ST(D) Z+%02x, R%d", QCONST6(op), RD5(op));
+ break;
+ case 0x0208:
+ util::stream_format(stream, "ST(D) Y+%02x, R%d", QCONST6(op), RD5(op));
+ break;
+ }
+ break;
+ case 0x9000:
+ switch(op & 0x0f00)
+ {
+ case 0x0000:
+ case 0x0100:
+ switch(op & 0x000f)
+ {
+ case 0x0000:
+ op <<= 16;
+ op |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "LDS R%d, (0x%04x)", RD5(op >> 16), op & 0x0000ffff);
+ break;
+ case 0x0001:
+ util::stream_format(stream, "LD R%d, Z+", RD5(op));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "LD R%d,-Z", RD5(op));
+ break;
+ case 0x0004:
+ util::stream_format(stream, "LPM R%d, Z", RD5(op));
+ break;
+ case 0x0005:
+ util::stream_format(stream, "LPM R%d, Z+", RD5(op));
+ break;
+ case 0x0006:
+ util::stream_format(stream, "ELPM R%d, Z", RD5(op));
+ break;
+ case 0x0007:
+ util::stream_format(stream, "ELPM R%d, Z+", RD5(op));
+ break;
+ case 0x0009:
+ util::stream_format(stream, "LD R%d, Y+", RD5(op));
+ break;
+ case 0x000a:
+ util::stream_format(stream, "LD R%d,-Y", RD5(op));
+ break;
+ case 0x000c:
+ util::stream_format(stream, "LD R%d, X", RD5(op));
+ break;
+ case 0x000d:
+ util::stream_format(stream, "LD R%d, X+", RD5(op));
+ break;
+ case 0x000e:
+ util::stream_format(stream, "LD R%d,-X", RD5(op));
+ break;
+ case 0x000f:
+ util::stream_format(stream, "POP R%d", RD5(op));
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x0200:
+ case 0x0300:
+ switch(op & 0x000f)
+ {
+ case 0x0000:
+ op <<= 16;
+ op |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "STS (0x%04x), R%d", op & 0x0000ffff, RD5(op >> 16));
+ break;
+ case 0x0001:
+ util::stream_format(stream, "ST Z+, R%d", RD5(op));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "ST -Z , R%d", RD5(op));
+ break;
+ case 0x0009:
+ util::stream_format(stream, "ST Y+, R%d", RD5(op));
+ break;
+ case 0x000a:
+ util::stream_format(stream, "ST -Y , R%d", RD5(op));
+ break;
+ case 0x000c:
+ util::stream_format(stream, "ST X , R%d", RD5(op));
+ break;
+ case 0x000d:
+ util::stream_format(stream, "ST X+, R%d", RD5(op));
+ break;
+ case 0x000e:
+ util::stream_format(stream, "ST -X , R%d", RD5(op));
+ break;
+ case 0x000f:
+ util::stream_format(stream, "PUSH R%d", RD5(op));
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x0400:
+ switch(op & 0x000f)
{
+ case 0x0000:
+ util::stream_format(stream, "COM R%d", RD5(op));
+ break;
+ case 0x0001:
+ util::stream_format(stream, "NEG R%d", RD5(op));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "SWAP R%d", RD5(op));
+ break;
+ case 0x0003:
+ util::stream_format(stream, "INC R%d", RD5(op));
+ break;
+ case 0x0005:
+ util::stream_format(stream, "ASR R%d", RD5(op));
+ break;
+ case 0x0006:
+ util::stream_format(stream, "LSR R%d", RD5(op));
+ break;
+ case 0x0007:
+ util::stream_format(stream, "ROR R%d", RD5(op));
+ break;
+ case 0x0008:
+ switch(op & 0x00f0)
+ {
case 0x0000:
- util::stream_format(stream, "CPSE R%d, R%d", RD5(op), RR5(op));
+ util::stream_format(stream, "SEC");
break;
- case 0x0400:
- util::stream_format(stream, "CP R%d, R%d", RD5(op), RR5(op));
+ case 0x0010:
+ util::stream_format(stream, "SEZ");
break;
- case 0x0800:
- util::stream_format(stream, "SUB R%d, R%d", RD5(op), RR5(op));
+ case 0x0020:
+ util::stream_format(stream, "SEN");
break;
- case 0x0c00:
- util::stream_format(stream, "ADC R%d, R%d", RD5(op), RR5(op));
+ case 0x0030:
+ util::stream_format(stream, "SEV");
break;
- }
- break;
- case 0x2000:
- switch(op & 0x0c00)
- {
- case 0x0000:
- util::stream_format(stream, "AND R%d, R%d", RD5(op), RR5(op));
+ case 0x0040:
+ util::stream_format(stream, "SES");
break;
- case 0x0400:
- util::stream_format(stream, "EOR R%d, R%d", RD5(op), RR5(op));
+ case 0x0050:
+ util::stream_format(stream, "SEH");
break;
- case 0x0800:
- util::stream_format(stream, "OR R%d, R%d", RD5(op), RR5(op));
+ case 0x0060:
+ util::stream_format(stream, "SET");
break;
- case 0x0c00:
- util::stream_format(stream, "MOV R%d, R%d", RD5(op), RR5(op));
+ case 0x0070:
+ util::stream_format(stream, "SEI");
break;
- }
- break;
- case 0x3000:
- util::stream_format(stream, "CPI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
- break;
- case 0x4000:
- util::stream_format(stream, "SBCI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
- break;
- case 0x5000:
- util::stream_format(stream, "SUBI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
- break;
- case 0x6000:
- util::stream_format(stream, "ORI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
- break;
- case 0x7000:
- util::stream_format(stream, "ANDI R%d, 0x%02x", 16+RD4(op), KCONST8(op));
- break;
- case 0x8000:
- case 0xa000:
- switch(op & 0x0208)
- {
- case 0x0000:
- util::stream_format(stream, "LD(D) R%d, Z+%02x", RD5(op), QCONST6(op));
+ case 0x0080:
+ util::stream_format(stream, "CLC");
+ break;
+ case 0x0090:
+ util::stream_format(stream, "CLZ");
break;
- case 0x0008:
- util::stream_format(stream, "LD(D) R%d, Y+%02x", RD5(op), QCONST6(op));
+ case 0x00a0:
+ util::stream_format(stream, "CLN");
break;
- case 0x0200:
- util::stream_format(stream, "ST(D) Z+%02x, R%d", QCONST6(op), RD5(op));
+ case 0x00b0:
+ util::stream_format(stream, "CLV");
break;
- case 0x0208:
- util::stream_format(stream, "ST(D) Y+%02x, R%d", QCONST6(op), RD5(op));
+ case 0x00c0:
+ util::stream_format(stream, "CLS");
break;
+ case 0x00d0:
+ util::stream_format(stream, "CLH");
+ break;
+ case 0x00e0:
+ util::stream_format(stream, "CLT");
+ break;
+ case 0x00f0:
+ util::stream_format(stream, "CLI");
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x0009:
+ switch(op & 0x00f0)
+ {
+ case 0x0000:
+ util::stream_format(stream, "IJMP");
+ break;
+ case 0x0010:
+ util::stream_format(stream, "EIJMP");
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x000a:
+ util::stream_format(stream, "DEC R%d", RD5(op));
+ break;
+ case 0x000c:
+ case 0x000d:
+ addr = KCONST22(op) << 16;
+ addr |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "JMP 0x%06x", addr << 1);
+ break;
+ case 0x000e:
+ case 0x000f:
+ addr = KCONST22(op) << 16;
+ addr |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "CALL 0x%06x", addr << 1);
+ flags = STEP_OVER;
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
}
break;
- case 0x9000:
- switch(op & 0x0f00)
+ case 0x0500:
+ switch(op & 0x000f)
{
+ case 0x0000:
+ util::stream_format(stream, "COM R%d", RD5(op));
+ break;
+ case 0x0001:
+ util::stream_format(stream, "NEG R%d", RD5(op));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "SWAP R%d", RD5(op));
+ break;
+ case 0x0003:
+ util::stream_format(stream, "INC R%d", RD5(op));
+ break;
+ case 0x0005:
+ util::stream_format(stream, "ASR R%d", RD5(op));
+ break;
+ case 0x0006:
+ util::stream_format(stream, "LSR R%d", RD5(op));
+ break;
+ case 0x0007:
+ util::stream_format(stream, "ROR R%d", RD5(op));
+ break;
+ case 0x0008:
+ switch(op & 0x00f0)
+ {
case 0x0000:
- case 0x0100:
- switch(op & 0x000f)
- {
- case 0x0000:
- op <<= 16;
- op |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "LDS R%d, (0x%04x)", RD5(op >> 16), op & 0x0000ffff);
- break;
- case 0x0001:
- util::stream_format(stream, "LD R%d, Z+", RD5(op));
- break;
- case 0x0002:
- util::stream_format(stream, "LD R%d,-Z", RD5(op));
- break;
- case 0x0004:
- util::stream_format(stream, "LPM R%d, Z", RD5(op));
- break;
- case 0x0005:
- util::stream_format(stream, "LPM R%d, Z+", RD5(op));
- break;
- case 0x0006:
- util::stream_format(stream, "ELPM R%d, Z", RD5(op));
- break;
- case 0x0007:
- util::stream_format(stream, "ELPM R%d, Z+", RD5(op));
- break;
- case 0x0009:
- util::stream_format(stream, "LD R%d, Y+", RD5(op));
- break;
- case 0x000a:
- util::stream_format(stream, "LD R%d,-Y", RD5(op));
- break;
- case 0x000c:
- util::stream_format(stream, "LD R%d, X", RD5(op));
- break;
- case 0x000d:
- util::stream_format(stream, "LD R%d, X+", RD5(op));
- break;
- case 0x000e:
- util::stream_format(stream, "LD R%d,-X", RD5(op));
- break;
- case 0x000f:
- util::stream_format(stream, "POP R%d", RD5(op));
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x0200:
- case 0x0300:
- switch(op & 0x000f)
- {
- case 0x0000:
- op <<= 16;
- op |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "STS (0x%04x), R%d", op & 0x0000ffff, RD5(op >> 16));
- break;
- case 0x0001:
- util::stream_format(stream, "ST Z+, R%d", RD5(op));
- break;
- case 0x0002:
- util::stream_format(stream, "ST -Z , R%d", RD5(op));
- break;
- case 0x0009:
- util::stream_format(stream, "ST Y+, R%d", RD5(op));
- break;
- case 0x000a:
- util::stream_format(stream, "ST -Y , R%d", RD5(op));
- break;
- case 0x000c:
- util::stream_format(stream, "ST X , R%d", RD5(op));
- break;
- case 0x000d:
- util::stream_format(stream, "ST X+, R%d", RD5(op));
- break;
- case 0x000e:
- util::stream_format(stream, "ST -X , R%d", RD5(op));
- break;
- case 0x000f:
- util::stream_format(stream, "PUSH R%d", RD5(op));
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x0400:
- switch(op & 0x000f)
- {
- case 0x0000:
- util::stream_format(stream, "COM R%d", RD5(op));
- break;
- case 0x0001:
- util::stream_format(stream, "NEG R%d", RD5(op));
- break;
- case 0x0002:
- util::stream_format(stream, "SWAP R%d", RD5(op));
- break;
- case 0x0003:
- util::stream_format(stream, "INC R%d", RD5(op));
- break;
- case 0x0005:
- util::stream_format(stream, "ASR R%d", RD5(op));
- break;
- case 0x0006:
- util::stream_format(stream, "LSR R%d", RD5(op));
- break;
- case 0x0007:
- util::stream_format(stream, "ROR R%d", RD5(op));
- break;
- case 0x0008:
- switch(op & 0x00f0)
- {
- case 0x0000:
- util::stream_format(stream, "SEC");
- break;
- case 0x0010:
- util::stream_format(stream, "SEZ");
- break;
- case 0x0020:
- util::stream_format(stream, "SEN");
- break;
- case 0x0030:
- util::stream_format(stream, "SEV");
- break;
- case 0x0040:
- util::stream_format(stream, "SES");
- break;
- case 0x0050:
- util::stream_format(stream, "SEH");
- break;
- case 0x0060:
- util::stream_format(stream, "SET");
- break;
- case 0x0070:
- util::stream_format(stream, "SEI");
- break;
- case 0x0080:
- util::stream_format(stream, "CLC");
- break;
- case 0x0090:
- util::stream_format(stream, "CLZ");
- break;
- case 0x00a0:
- util::stream_format(stream, "CLN");
- break;
- case 0x00b0:
- util::stream_format(stream, "CLV");
- break;
- case 0x00c0:
- util::stream_format(stream, "CLS");
- break;
- case 0x00d0:
- util::stream_format(stream, "CLH");
- break;
- case 0x00e0:
- util::stream_format(stream, "CLT");
- break;
- case 0x00f0:
- util::stream_format(stream, "CLI");
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x0009:
- switch(op & 0x00f0)
- {
- case 0x0000:
- util::stream_format(stream, "IJMP");
- break;
- case 0x0010:
- util::stream_format(stream, "EIJMP");
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x000a:
- util::stream_format(stream, "DEC R%d", RD5(op));
- break;
- case 0x000c:
- case 0x000d:
- addr = KCONST22(op) << 16;
- addr |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "JMP 0x%06x", addr << 1);
- break;
- case 0x000e:
- case 0x000f:
- addr = KCONST22(op) << 16;
- addr |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "CALL 0x%06x", addr << 1);
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x0500:
- switch(op & 0x000f)
- {
- case 0x0000:
- util::stream_format(stream, "COM R%d", RD5(op));
- break;
- case 0x0001:
- util::stream_format(stream, "NEG R%d", RD5(op));
- break;
- case 0x0002:
- util::stream_format(stream, "SWAP R%d", RD5(op));
- break;
- case 0x0003:
- util::stream_format(stream, "INC R%d", RD5(op));
- break;
- case 0x0005:
- util::stream_format(stream, "ASR R%d", RD5(op));
- break;
- case 0x0006:
- util::stream_format(stream, "LSR R%d", RD5(op));
- break;
- case 0x0007:
- util::stream_format(stream, "ROR R%d", RD5(op));
- break;
- case 0x0008:
- switch(op & 0x00f0)
- {
- case 0x0000:
- util::stream_format(stream, "RET");
- break;
- case 0x0010:
- util::stream_format(stream, "RETI");
- break;
- case 0x0080:
- util::stream_format(stream, "SLEEP");
- break;
- case 0x0090:
- util::stream_format(stream, "BREAK");
- break;
- case 0x00a0:
- util::stream_format(stream, "WDR");
- break;
- case 0x00c0:
- util::stream_format(stream, "LPM");
- break;
- case 0x00d0:
- util::stream_format(stream, "ELPM");
- break;
- case 0x00e0:
- util::stream_format(stream, "SPM");
- break;
- case 0x00f0:
- util::stream_format(stream, "SPM Z+");
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x0009:
- switch(op & 0x00f0)
- {
- case 0x0000:
- util::stream_format(stream, "ICALL");
- break;
- case 0x0010:
- util::stream_format(stream, "EICALL");
- break;
- default:
- util::stream_format(stream, "Undefined (%08x)", op);
- break;
- }
- break;
- case 0x000a:
- util::stream_format(stream, "DEC R%d", RD5(op));
- break;
- case 0x000c:
- case 0x000d:
- op <<= 16;
- op |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "JMP 0x%06x", KCONST22(op) << 1);
- break;
- case 0x000e:
- case 0x000f:
- op <<= 16;
- op |= opcodes.r16(pc);
- pc += 2;
- util::stream_format(stream, "CALL 0x%06x", KCONST22(op) << 1);
- break;
- }
- break;
- case 0x0600:
- util::stream_format(stream, "ADIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op));
- break;
- case 0x0700:
- util::stream_format(stream, "SBIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op));
- break;
- case 0x0800:
- if (ACONST5(op) < 0x20)
- util::stream_format(stream, "CBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
- else
- util::stream_format(stream, "CBI 0x%02x, %d", ACONST5(op), RR3(op));
+ util::stream_format(stream, "RET");
+ flags = STEP_OUT;
break;
- case 0x0900:
- if (ACONST5(op) < 0x20)
- util::stream_format(stream, "SBIC %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
- else
- util::stream_format(stream, "SBIC 0x%02x, %d", ACONST5(op), RR3(op));
+ case 0x0010:
+ util::stream_format(stream, "RETI");
+ flags = STEP_OUT;
break;
- case 0x0a00:
- if (ACONST5(op) < 0x20)
- util::stream_format(stream, "SBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
- else
- util::stream_format(stream, "SBI 0x%02x, %d", ACONST5(op), RR3(op));
+ case 0x0080:
+ util::stream_format(stream, "SLEEP");
break;
- case 0x0b00:
- if (ACONST5(op) < 0x20)
- util::stream_format(stream, "SBIS %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
- else
- util::stream_format(stream, "SBIS 0x%02x, %d", ACONST5(op), RR3(op));
+ case 0x0090:
+ util::stream_format(stream, "BREAK");
break;
- case 0x0c00:
- case 0x0d00:
- case 0x0e00:
- case 0x0f00:
- util::stream_format(stream, "MUL R%d, R%d", RD5(op), RR5(op));
+ case 0x00a0:
+ util::stream_format(stream, "WDR");
break;
+ case 0x00c0:
+ util::stream_format(stream, "LPM");
+ break;
+ case 0x00d0:
+ util::stream_format(stream, "ELPM");
+ break;
+ case 0x00e0:
+ util::stream_format(stream, "SPM");
+ break;
+ case 0x00f0:
+ util::stream_format(stream, "SPM Z+");
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x0009:
+ switch(op & 0x00f0)
+ {
+ case 0x0000:
+ util::stream_format(stream, "ICALL");
+ flags = STEP_OVER;
+ break;
+ case 0x0010:
+ util::stream_format(stream, "EICALL");
+ flags = STEP_OVER;
+ break;
+ default:
+ util::stream_format(stream, "Undefined (%08x)", op);
+ break;
+ }
+ break;
+ case 0x000a:
+ util::stream_format(stream, "DEC R%d", RD5(op));
+ break;
+ case 0x000c:
+ case 0x000d:
+ op <<= 16;
+ op |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "JMP 0x%06x", KCONST22(op) << 1);
+ break;
+ case 0x000e:
+ case 0x000f:
+ op <<= 16;
+ op |= opcodes.r16(pc);
+ pc += 2;
+ util::stream_format(stream, "CALL 0x%06x", KCONST22(op) << 1);
+ flags = STEP_OVER;
+ break;
}
break;
- case 0xb000:
- if(op & 0x0800)
- {
- if (ACONST6(op) < 0x40 ) {
- util::stream_format(stream, "OUT %s, R%d", register_names[ACONST6(op)], RD5(op));
- } else {
- util::stream_format(stream, "OUT 0x%02x, R%d", ACONST6(op), RD5(op));
- }
- }
- else
- {
- if (ACONST6(op) < 0x40 ) {
- util::stream_format(stream, "IN R%d, %s", RD5(op), register_names[ACONST6(op)]);
- } else {
- util::stream_format(stream, "IN R%d, 0x%02x", RD5(op), ACONST6(op));
- }
- }
+ case 0x0600:
+ util::stream_format(stream, "ADIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op));
+ break;
+ case 0x0700:
+ util::stream_format(stream, "SBIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op));
+ break;
+ case 0x0800:
+ util::stream_format(stream, "CBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
break;
- case 0xc000:
- //I'm not sure if this is correct. why pc + ... : pc + 8 + ... ?
- util::stream_format(stream, "RJMP %08x", (((op & 0x0800) ? pc + ((op & 0x0fff) | 0xfffff000) : pc + 8 + (op & 0x0fff)) << 0));
+ case 0x0900:
+ util::stream_format(stream, "SBIC %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
+ flags = STEP_COND;
+ break;
+ case 0x0a00:
+ util::stream_format(stream, "SBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
break;
- case 0xd000:
- util::stream_format(stream, "RCALL %08x", (((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)) << 1));
+ case 0x0b00:
+ util::stream_format(stream, "SBIS %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)]);
+ flags = STEP_COND;
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00:
+ util::stream_format(stream, "MUL R%d, R%d", RD5(op), RR5(op));
break;
- case 0xe000:
- util::stream_format(stream, "LDI R%d, 0x%02x", 16 + RD4(op), KCONST8(op));
+ }
+ break;
+ case 0xb000:
+ if(op & 0x0800)
+ util::stream_format(stream, "OUT %s, R%d", register_names[ACONST6(op)], RD5(op));
+ else
+ util::stream_format(stream, "IN R%d, %s", RD5(op), register_names[ACONST6(op)]);
+ break;
+ case 0xc000:
+ util::stream_format(stream, "RJMP %08x", (((op & 0x0800) ? pc + ((op & 0x0fff) | 0xfffff000) : pc + 2 + (op & 0x0fff)) << 0));
+ break;
+ case 0xd000:
+ util::stream_format(stream, "RCALL %08x", (((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)) << 1));
+ flags = STEP_OVER;
+ break;
+ case 0xe000:
+ util::stream_format(stream, "LDI R%d, 0x%02x", 16 + RD4(op), KCONST8(op));
+ break;
+ case 0xf000:
+ switch(op & 0x0c00)
+ {
+ case 0x0000:
+ switch(op & 0x0007)
+ {
+ case 0x0000:
+ util::stream_format(stream, "BRLO %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0001:
+ util::stream_format(stream, "BREQ %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "BRMI %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0003:
+ util::stream_format(stream, "BRVS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0004:
+ util::stream_format(stream, "BRLT %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0005:
+ util::stream_format(stream, "BRHS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0006:
+ util::stream_format(stream, "BRTS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0007:
+ util::stream_format(stream, "BRIE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ }
+ flags = STEP_COND;
break;
- case 0xf000:
- switch(op & 0x0c00)
+ case 0x0400:
+ switch(op & 0x0007)
{
- case 0x0000:
- switch(op & 0x0007)
- {
- case 0x0000:
- util::stream_format(stream, "BRLO %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0001:
- util::stream_format(stream, "BREQ %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0002:
- util::stream_format(stream, "BRMI %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0003:
- util::stream_format(stream, "BRVS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0004:
- util::stream_format(stream, "BRLT %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0005:
- util::stream_format(stream, "BRHS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0006:
- util::stream_format(stream, "BRTS %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0007:
- util::stream_format(stream, "BRIE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- }
- break;
- case 0x0400:
- switch(op & 0x0007)
- {
- case 0x0000:
- util::stream_format(stream, "BRSH %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0001:
- util::stream_format(stream, "BRNE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0002:
- util::stream_format(stream, "BRPL %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0003:
- util::stream_format(stream, "BRVC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0004:
- util::stream_format(stream, "BRGE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0005:
- util::stream_format(stream, "BRHC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0006:
- util::stream_format(stream, "BRTC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- case 0x0007:
- util::stream_format(stream, "BRID %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
- break;
- }
- break;
- case 0x0800:
- if(op & 0x0200)
- {
- util::stream_format(stream, "BST R%d, %d", RD5(op), RR3(op));
- }
- else
- {
- util::stream_format(stream, "BLD R%d, %d", RD5(op), RR3(op));
- }
- break;
- case 0x0c00:
- if(op & 0x0200)
- {
- util::stream_format(stream, "SBRS R%d, %d", RD5(op), RR3(op));
- }
- else
- {
- util::stream_format(stream, "SBRC R%d, %d", RD5(op), RR3(op));
- }
- break;
+ case 0x0000:
+ util::stream_format(stream, "BRSH %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0001:
+ util::stream_format(stream, "BRNE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0002:
+ util::stream_format(stream, "BRPL %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0003:
+ util::stream_format(stream, "BRVC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0004:
+ util::stream_format(stream, "BRGE %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0005:
+ util::stream_format(stream, "BRHC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0006:
+ util::stream_format(stream, "BRTC %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
+ case 0x0007:
+ util::stream_format(stream, "BRID %08x", (((op & 0x0200) ? (KCONST7(op) | 0xff80) : KCONST7(op)) << 1));
+ break;
}
+ flags = STEP_COND;
+ break;
+ case 0x0800:
+ if(op & 0x0200)
+ util::stream_format(stream, "BST R%d, %d", RD5(op), RR3(op));
+ else
+ util::stream_format(stream, "BLD R%d, %d", RD5(op), RR3(op));
break;
+ case 0x0c00:
+ if(op & 0x0200)
+ util::stream_format(stream, "SBRS R%d, %d", RD5(op), RR3(op));
+ else
+ util::stream_format(stream, "SBRC R%d, %d", RD5(op), RR3(op));
+ flags = STEP_COND;
+ break;
+ }
+ break;
}
- return (pc - base_pc) | SUPPORTED;
+ return (pc - base_pc) | flags | SUPPORTED;
}
diff --git a/src/devices/cpu/avr8/avr8ops.hxx b/src/devices/cpu/avr8/avr8ops.hxx
new file mode 100644
index 00000000000..614adac97b5
--- /dev/null
+++ b/src/devices/cpu/avr8/avr8ops.hxx
@@ -0,0 +1,1403 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz, Sandro Ronco, Felipe Sanches
+/***************************************************************************
+
+ Atmel 8-bit AVR simulator
+
+ Opcode implementations
+
+***************************************************************************/
+
+void avr8_base_device::populate_ops()
+{
+ for (uint32_t op = 0; op < 0x10000; op++)
+ {
+ m_op_cycles[op] = 1;
+
+ switch (op & 0xf000)
+ {
+ case 0x0000:
+ switch (op & 0x0f00)
+ {
+ case 0x0000: // NOP
+ m_op_funcs[op] = &avr8_base_device::op_nop;
+ break;
+ case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd
+ m_op_funcs[op] = &avr8_base_device::op_movw;
+ break;
+ case 0x0200: // MULS Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_muls;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0300: // Multiplication
+ switch (MULCONST2(op))
+ {
+ case 0x0000: // MULSU Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_mulsu;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0001: // FMUL Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_fmul;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0002: // FMULS Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_fmuls;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0003: // FMULSU Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_fmulsu;
+ m_op_cycles[op] = 2;
+ break;
+ }
+ break;
+ case 0x0400:
+ case 0x0500:
+ case 0x0600:
+ case 0x0700: // CPC Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_cpc;
+ break;
+ case 0x0800:
+ case 0x0900:
+ case 0x0a00:
+ case 0x0b00: // SBC Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_sbc;
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00: // ADD Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_add;
+ break;
+ }
+ break;
+ case 0x1000:
+ switch (op & 0x0c00)
+ {
+ case 0x0000: // CPSE Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_cpse;
+ break;
+ case 0x0400: // CP Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_cp;
+ break;
+ case 0x0800: // SUB Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_sub;
+ break;
+ case 0x0c00: // ADC Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_adc;
+ break;
+ }
+ break;
+ case 0x2000:
+ switch (op & 0x0c00)
+ {
+ case 0x0000: // AND Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_and;
+ break;
+ case 0x0400: // EOR Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_eor;
+ break;
+ case 0x0800: // OR Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_or;
+ break;
+ case 0x0c00: // MOV Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_mov;
+ break;
+ }
+ break;
+ case 0x3000: // CPI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_cpi;
+ break;
+ case 0x4000: // SBCI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_sbci;
+ break;
+ case 0x5000: // SUBI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_subi;
+ break;
+ case 0x6000: // ORI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_ori;
+ break;
+ case 0x7000: // ANDI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_andi;
+ break;
+ case 0x8000:
+ case 0xa000:
+ switch (op & 0x0208)
+ {
+ case 0x0000: // LDD Rd,Z+q
+ m_op_funcs[op] = &avr8_base_device::op_lddz;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0008: // LDD Rd,Y+q
+ m_op_funcs[op] = &avr8_base_device::op_lddy;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0200: // STD Z+q,Rr
+ m_op_funcs[op] = &avr8_base_device::op_stdz;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0208: // STD Y+q,Rr
+ m_op_funcs[op] = &avr8_base_device::op_stdy;
+ m_op_cycles[op] = 2;
+ break;
+ }
+ break;
+ case 0x9000:
+ switch (op & 0x0f00)
+ {
+ case 0x0000:
+ case 0x0100:
+ switch (op & 0x000f)
+ {
+ case 0x0000: // LDS Rd,k
+ m_op_funcs[op] = &avr8_base_device::op_lds;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0001: // LD Rd,Z+
+ m_op_funcs[op] = &avr8_base_device::op_ldzi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0002: // LD Rd,-Z
+ m_op_funcs[op] = &avr8_base_device::op_ldzd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0004: // LPM Rd,Z
+ m_op_funcs[op] = &avr8_base_device::op_lpmz;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x0005: // LPM Rd,Z+
+ m_op_funcs[op] = &avr8_base_device::op_lpmzi;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x0006: // ELPM Rd,Z
+ m_op_funcs[op] = &avr8_base_device::op_elpmz;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x0007: // ELPM Rd,Z+
+ m_op_funcs[op] = &avr8_base_device::op_elpmzi;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x0009: // LD Rd,Y+
+ m_op_funcs[op] = &avr8_base_device::op_ldyi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000a: // LD Rd,-Y
+ m_op_funcs[op] = &avr8_base_device::op_ldyd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000c: // LD Rd,X
+ m_op_funcs[op] = &avr8_base_device::op_ldx;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000d: // LD Rd,X+
+ m_op_funcs[op] = &avr8_base_device::op_ldxi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000e: // LD Rd,-X
+ m_op_funcs[op] = &avr8_base_device::op_ldxd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000f: // POP Rd
+ m_op_funcs[op] = &avr8_base_device::op_pop;
+ m_op_cycles[op] = 2;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x0200:
+ case 0x0300:
+ switch (op & 0x000f)
+ {
+ case 0x0000: // STS k,Rr
+ m_op_funcs[op] = &avr8_base_device::op_sts;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0001: // ST Z+,Rd
+ m_op_funcs[op] = &avr8_base_device::op_stzi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0002: // ST -Z,Rd
+ m_op_funcs[op] = &avr8_base_device::op_stzd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0009: // ST Y+,Rd
+ m_op_funcs[op] = &avr8_base_device::op_styi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000a: // ST -Y,Rd
+ m_op_funcs[op] = &avr8_base_device::op_styd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000c: // ST X,Rd
+ m_op_funcs[op] = &avr8_base_device::op_stx;
+ break;
+ case 0x000d: // ST X+,Rd
+ m_op_funcs[op] = &avr8_base_device::op_stxi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000e: // ST -X,Rd
+ m_op_funcs[op] = &avr8_base_device::op_stxd;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x000f: // PUSH Rd
+ m_op_funcs[op] = &avr8_base_device::op_push;
+ m_op_cycles[op] = 2;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x0400:
+ switch (op & 0x000f)
+ {
+ case 0x0000: // COM Rd
+ m_op_funcs[op] = &avr8_base_device::op_com;
+ break;
+ case 0x0001: // NEG Rd
+ m_op_funcs[op] = &avr8_base_device::op_neg;
+ break;
+ case 0x0002: // SWAP Rd
+ m_op_funcs[op] = &avr8_base_device::op_swap;
+ break;
+ case 0x0003: // INC Rd
+ m_op_funcs[op] = &avr8_base_device::op_inc;
+ break;
+ case 0x0005: // ASR Rd
+ m_op_funcs[op] = &avr8_base_device::op_asr;
+ break;
+ case 0x0006: // LSR Rd
+ m_op_funcs[op] = &avr8_base_device::op_lsr;
+ break;
+ case 0x0007: // ROR Rd
+ m_op_funcs[op] = &avr8_base_device::op_ror;
+ 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
+ m_op_funcs[op] = &avr8_base_device::op_setf;
+ 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
+ m_op_funcs[op] = &avr8_base_device::op_clrf;
+ break;
+ }
+ break;
+ case 0x0009:
+ switch (op & 0x00f0)
+ {
+ case 0x0000: // IJMP
+ m_op_funcs[op] = &avr8_base_device::op_ijmp;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0010: // EIJMP
+ m_op_funcs[op] = &avr8_base_device::op_eijmp;
+ m_op_cycles[op] = 2;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x000a: // DEC Rd
+ m_op_funcs[op] = &avr8_base_device::op_dec;
+ break;
+ case 0x000c:
+ case 0x000d: // JMP k
+ m_op_funcs[op] = &avr8_base_device::op_jmp;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x000e: // CALL k
+ case 0x000f:
+ m_op_funcs[op] = &avr8_base_device::op_call;
+ m_op_cycles[op] = 4;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x0500:
+ switch (op & 0x000f)
+ {
+ case 0x0000: // COM Rd
+ m_op_funcs[op] = &avr8_base_device::op_com;
+ break;
+ case 0x0001: // NEG Rd
+ m_op_funcs[op] = &avr8_base_device::op_neg;
+ break;
+ case 0x0002: // SWAP Rd
+ m_op_funcs[op] = &avr8_base_device::op_swap;
+ break;
+ case 0x0003: // INC Rd
+ m_op_funcs[op] = &avr8_base_device::op_inc;
+ break;
+ case 0x0005: // ASR Rd
+ m_op_funcs[op] = &avr8_base_device::op_asr;
+ break;
+ case 0x0006: // LSR Rd
+ m_op_funcs[op] = &avr8_base_device::op_lsr;
+ break;
+ case 0x0007: // ROR Rd
+ m_op_funcs[op] = &avr8_base_device::op_ror;
+ break;
+ case 0x0008:
+ switch (op & 0x00f0)
+ {
+ case 0x0000: // RET
+ m_op_funcs[op] = &avr8_base_device::op_ret;
+ m_op_cycles[op] = 4;
+ break;
+ case 0x0010: // RETI
+ m_op_funcs[op] = &avr8_base_device::op_reti;
+ m_op_cycles[op] = 4;
+ break;
+ case 0x0080: // SLEEP
+ m_op_funcs[op] = &avr8_base_device::op_sleep;
+ m_op_cycles[op] = 1;
+ break;
+ case 0x0090: // BREAK
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ case 0x00a0: // WDR
+ m_op_funcs[op] = &avr8_base_device::op_wdr;
+ break;
+ case 0x00c0: // LPM
+ m_op_funcs[op] = &avr8_base_device::op_lpm;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x00d0: // ELPM
+ m_op_funcs[op] = &avr8_base_device::op_elpm;
+ break;
+ case 0x00e0: // SPM
+ m_op_funcs[op] = &avr8_base_device::op_spm;
+ break;
+ case 0x00f0: // SPM Z+
+ m_op_funcs[op] = &avr8_base_device::op_spmzi;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x0009:
+ switch (op & 0x00f0)
+ {
+ case 0x0000: // ICALL
+ m_op_funcs[op] = &avr8_base_device::op_icall;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x0010: // EICALL
+ m_op_funcs[op] = &avr8_base_device::op_eicall;
+ break;
+ default:
+ m_op_funcs[op] = &avr8_base_device::op_unimpl;
+ break;
+ }
+ break;
+ case 0x000a: // DEC Rd
+ m_op_funcs[op] = &avr8_base_device::op_dec;
+ break;
+ case 0x000c:
+ case 0x000d: // JMP k
+ m_op_funcs[op] = &avr8_base_device::op_jmp;
+ m_op_cycles[op] = 3;
+ break;
+ case 0x000e:
+ case 0x000f: // CALL k
+ m_op_funcs[op] = &avr8_base_device::op_call;
+ m_op_cycles[op] = 4;
+ break;
+ }
+ break;
+ case 0x0600: // ADIW Rd+1:Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_adiw;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0700: // SBIW Rd+1:Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_sbiw;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0800: // CBI A,b
+ m_op_funcs[op] = &avr8_base_device::op_cbi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0900: // SBIC A,b
+ m_op_funcs[op] = &avr8_base_device::op_sbic;
+ break;
+ case 0x0a00: // SBI A,b
+ m_op_funcs[op] = &avr8_base_device::op_sbi;
+ m_op_cycles[op] = 2;
+ break;
+ case 0x0b00: // SBIS A,b
+ m_op_funcs[op] = &avr8_base_device::op_sbis;
+ break;
+ case 0x0c00:
+ case 0x0d00:
+ case 0x0e00:
+ case 0x0f00: // MUL Rd,Rr
+ m_op_funcs[op] = &avr8_base_device::op_mul;
+ m_op_cycles[op] = 2;
+ break;
+ }
+ break;
+ case 0xb000:
+ if (op & 0x0800) // OUT A,Rr
+ {
+ m_op_funcs[op] = &avr8_base_device::op_out;
+ }
+ else // IN Rd,A
+ {
+ m_op_funcs[op] = &avr8_base_device::op_in;
+ }
+ break;
+ case 0xc000: // RJMP k
+ m_op_funcs[op] = &avr8_base_device::op_rjmp;
+ m_op_cycles[op] = 2;
+ break;
+ case 0xd000: // RCALL k
+ m_op_funcs[op] = &avr8_base_device::op_rcall;
+ m_op_cycles[op] = 3;
+ break;
+ case 0xe000: // LDI Rd,K
+ m_op_funcs[op] = &avr8_base_device::op_ldi;
+ break;
+ case 0xf000:
+ switch (op & 0x0c00)
+ {
+ case 0x0000: // BRLO through BRIE
+ m_op_funcs[op] = &avr8_base_device::op_brset;
+ break;
+ case 0x0400: // BRSH through BRID
+ m_op_funcs[op] = &avr8_base_device::op_brclr;
+ break;
+ case 0x0800:
+ if (op & 0x0200) // BST Rd, b
+ {
+ m_op_funcs[op] = &avr8_base_device::op_bst;
+ }
+ else // BLD Rd, b
+ {
+ m_op_funcs[op] = &avr8_base_device::op_bld;
+ }
+ break;
+ case 0x0c00:
+ if (op & 0x0200) // SBRS Rd, b
+ {
+ m_op_funcs[op] = &avr8_base_device::op_sbrs;
+ }
+ else // SBRC Rd, b
+ {
+ m_op_funcs[op] = &avr8_base_device::op_sbrc;
+ }
+ break;
+ }
+ break;
+ }
+ }
+}
+
+void avr8_base_device::populate_add_flag_cache()
+{
+ for (uint16_t rd = 0; rd < 0x100; rd++)
+ {
+ for (uint16_t rr = 0; rr < 0x100; rr++)
+ {
+ const uint8_t res = rd + rr;
+ uint8_t flags = 0;
+ flags |= (((rd & 8) && (rr & 8)) || ((rr & 8) && !(res & 8)) || (!(res & 8) && (rd & 8))) ? SREG_MASK_H : 0;
+ flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && !(rr & 0x80) && (res & 0x80))) ? SREG_MASK_V : 0;
+ flags |= (res & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ flags |= (res == 0) ? SREG_MASK_Z : 0;
+ flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? SREG_MASK_C : 0;
+ m_add_flag_cache[(rd << 8) | rr] = flags;
+ }
+ }
+}
+
+void avr8_base_device::populate_adc_flag_cache()
+{
+ for (uint16_t rd = 0; rd < 0x100; rd++)
+ {
+ for (uint16_t rr = 0; rr < 0x100; rr++)
+ {
+ for (uint8_t c = 0; c < 2; c++)
+ {
+ const uint8_t res = rd + rr + c;
+ uint8_t flags = 0;
+ flags |= (((rd & 8) && (rr & 8)) || ((rr & 8) && !(res & 8)) || (!(res & 8) && (rd & 8))) ? SREG_MASK_H : 0;
+ flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && !(rr & 0x80) && (res & 0x80))) ? SREG_MASK_V : 0;
+ flags |= (res & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ flags |= (res == 0) ? SREG_MASK_Z : 0;
+ flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? SREG_MASK_C : 0;
+ m_adc_flag_cache[(c << 16) | (rd << 8) | rr] = flags;
+ }
+ }
+ }
+}
+
+void avr8_base_device::populate_sub_flag_cache()
+{
+ for (uint16_t rd = 0; rd < 0x100; rd++)
+ {
+ for (uint16_t rr = 0; rr < 0x100; rr++)
+ {
+ const uint8_t res = rd - rr;
+ uint8_t flags = 0;
+ flags |= ((!(rd & 8) && (rr & 8)) || ((rr & 8) && (res & 8)) || ((res & 8) && !(rd & 8))) ? SREG_MASK_H : 0;
+ flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? SREG_MASK_V : 0;
+ flags |= (res & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ flags |= (res == 0) ? SREG_MASK_Z : 0;
+ flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? SREG_MASK_C : 0;
+ m_sub_flag_cache[(rd << 8) | rr] = flags;
+ }
+ }
+}
+
+void avr8_base_device::populate_sbc_flag_cache()
+{
+ for (uint16_t rd = 0; rd < 0x100; rd++)
+ {
+ for (uint16_t rr = 0; rr < 0x100; rr++)
+ {
+ for (uint8_t c = 0; c < 2; c++)
+ {
+ for (uint8_t z = 0; z < 2; z++)
+ {
+ const uint8_t res = rd - (rr + c);
+ uint8_t flags = 0;
+ flags |= ((!(rd & 8) && (rr & 8)) || ((rr & 8) && (res & 8)) || ((res & 8) && !(rd & 8))) ? SREG_MASK_H : 0;
+ flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? SREG_MASK_V : 0;
+ flags |= (res & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ flags |= (res == 0) ? (z ? SREG_MASK_Z : 0) : 0;
+ flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? SREG_MASK_C : 0;
+ m_sbc_flag_cache[(z << 17) | (c << 16) | (rd << 8) | rr] = flags;
+ }
+ }
+ }
+ }
+}
+
+void avr8_base_device::populate_bool_flag_cache()
+{
+ for (uint16_t res = 0; res < 0x100; res++)
+ {
+ uint8_t flags = 0;
+ flags |= (res & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ flags |= (res == 0) ? SREG_MASK_Z : 0;
+ m_bool_flag_cache[res] = flags;
+ }
+}
+
+void avr8_base_device::populate_shift_flag_cache()
+{
+ for (uint16_t rd = 0; rd < 0x100; rd++)
+ {
+ for (uint16_t res = 0; res < 0x100; res++)
+ {
+ uint8_t flags = 0;
+ flags |= (rd & 1) ? SREG_MASK_C : 0;
+ flags |= (res == 0) ? SREG_MASK_Z : 0;
+ flags |= (rd & 0x80) ? SREG_MASK_N : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_C)) ? SREG_MASK_V : 0;
+ flags |= (bool(flags & SREG_MASK_N) != bool(flags & SREG_MASK_V)) ? SREG_MASK_S : 0;
+ m_shift_flag_cache[(rd << 8) | res] = flags;
+ }
+ }
+}
+
+void avr8_base_device::op_nop(uint16_t op)
+{
+}
+
+void avr8_base_device::op_movw(uint16_t op)
+{
+ m_r[(RD4(op) << 1) + 1] = m_r[(RR4(op) << 1) + 1];
+ m_r[RD4(op) << 1] = m_r[RR4(op) << 1];
+}
+
+void avr8_base_device::op_muls(uint16_t op)
+{
+ const int16_t sd = (int8_t)m_r[16 + RD4(op)] * (int8_t)m_r[16 + RR4(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+ else if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+}
+
+void avr8_base_device::op_mulsu(uint16_t op)
+{
+ const int16_t sd = (int8_t)m_r[16 + RD3(op)] * (uint8_t)m_r[16 + RR3(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+ else if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+}
+
+void avr8_base_device::op_fmul(uint16_t op)
+{
+ const int16_t sd = ((uint8_t)m_r[16 + RD3(op)] * (uint8_t)m_r[16 + RR3(op)]) << 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+ else if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+}
+
+void avr8_base_device::op_fmuls(uint16_t op)
+{
+ const int16_t sd = ((int8_t)m_r[16 + RD3(op)] * (int8_t)m_r[16 + RR3(op)]) << 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+ else if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+}
+
+void avr8_base_device::op_fmulsu(uint16_t op)
+{
+ const int16_t sd = ((int8_t)m_r[16 + RD3(op)] * (uint8_t)m_r[16 + RR3(op)]) << 1;
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+ else if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+}
+
+void avr8_base_device::op_cpc(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ const uint8_t c = m_r[SREG] & SREG_MASK_C;
+ const uint32_t z = (m_r[SREG] & SREG_MASK_Z) ? (1 << 17) : 0;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr];
+}
+
+void avr8_base_device::op_sbc(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ const uint8_t c = m_r[SREG] & SREG_MASK_C;
+ const uint8_t res = rd - (rr + c);
+ m_r[RD5(op)] = res;
+ const uint32_t z = (m_r[SREG] & SREG_MASK_Z) ? (1 << 17) : 0;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr];
+}
+
+void avr8_base_device::op_add(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ const uint8_t res = rd + rr;
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_add_flag_cache[(rd << 8) | rr];
+}
+
+void avr8_base_device::op_cpse(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ if (rd == rr)
+ {
+ const uint16_t data = (uint32_t)m_program->read_word(m_pc + 2);
+ m_opcycles += is_long_opcode(data) ? 2 : 1;
+ m_pc += is_long_opcode(data) ? 4 : 2;
+ }
+}
+
+void avr8_base_device::op_cp(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sub_flag_cache[(rd << 8) | rr];
+}
+
+void avr8_base_device::op_sub(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ const uint8_t res = rd - rr;
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sub_flag_cache[(rd << 8) | rr];
+}
+
+void avr8_base_device::op_adc(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t rr = m_r[RR5(op)];
+ const uint8_t c = m_r[SREG] & SREG_MASK_C;
+ const uint8_t res = rd + rr + c;
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_adc_flag_cache[(c << 16) | (rd << 8) | rr];
+}
+
+void avr8_base_device::op_and(uint16_t op)
+{
+ const uint8_t res = m_r[RD5(op)] & m_r[RR5(op)];
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ m_r[SREG] |= m_bool_flag_cache[res];
+}
+
+void avr8_base_device::op_eor(uint16_t op)
+{
+ const uint8_t res = m_r[RD5(op)] ^ m_r[RR5(op)];
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ m_r[SREG] |= m_bool_flag_cache[res];
+}
+
+void avr8_base_device::op_or(uint16_t op)
+{
+ const uint8_t res = m_r[RD5(op)] | m_r[RR5(op)];
+ m_r[RD5(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ m_r[SREG] |= m_bool_flag_cache[res];
+}
+
+void avr8_base_device::op_mov(uint16_t op)
+{
+ m_r[RD5(op)] = m_r[RR5(op)];
+}
+
+void avr8_base_device::op_cpi(uint16_t op)
+{
+ const uint8_t rd = m_r[16 + RD4(op)];
+ const uint8_t rr = KCONST8(op);
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sub_flag_cache[(rd << 8) | rr];
+}
+
+void avr8_base_device::op_sbci(uint16_t op)
+{
+ const uint8_t rd = m_r[16 + RD4(op)];
+ const uint8_t rr = KCONST8(op);
+ const uint8_t c = m_r[SREG] & SREG_MASK_C;
+ const uint8_t res = rd - (rr + c);
+ m_r[16 + RD4(op)] = res;
+ const uint32_t z = (m_r[SREG] & SREG_MASK_Z) ? (1 << 17) : 0;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr];
+}
+
+void avr8_base_device::op_subi(uint16_t op)
+{
+ const uint8_t rd = m_r[16 + RD4(op)];
+ const uint8_t rr = KCONST8(op);
+ const uint8_t res = rd - rr;
+ m_r[16 + RD4(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_H | SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ m_r[SREG] |= m_sub_flag_cache[(rd << 8) | rr];
+}
+
+void avr8_base_device::op_ori(uint16_t op)
+{
+ const uint8_t res = m_r[16 + RD4(op)] | KCONST8(op);
+ m_r[16 + RD4(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ m_r[SREG] |= m_bool_flag_cache[res];
+}
+
+void avr8_base_device::op_andi(uint16_t op)
+{
+ const uint8_t res = m_r[16 + RD4(op)] & KCONST8(op);
+ m_r[16 + RD4(op)] = res;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ m_r[SREG] |= m_bool_flag_cache[res];
+}
+
+void avr8_base_device::op_lddz(uint16_t op)
+{
+ m_r[RD5(op)] = m_data->read_byte(ZREG + QCONST6(op));
+}
+
+void avr8_base_device::op_lddy(uint16_t op)
+{
+ m_r[RD5(op)] = m_data->read_byte(YREG + QCONST6(op));
+}
+
+void avr8_base_device::op_stdz(uint16_t op)
+{
+ m_data->write_byte(ZREG + QCONST6(op), m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_stdy(uint16_t op)
+{
+ m_data->write_byte(YREG + QCONST6(op), m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_lds(uint16_t op)
+{
+ m_pc += 2;
+ const uint16_t addr = m_program->read_word(m_pc);
+ m_r[RD5(op)] = m_data->read_byte(addr);
+}
+
+void avr8_base_device::op_ldzi(uint16_t op)
+{
+ uint16_t pd = ZREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_ldzd(uint16_t op)
+{
+ const uint16_t pd = ZREG - 1;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_lpmz(uint16_t op)
+{
+ m_r[RD5(op)] = m_program->read_byte(ZREG);
+}
+
+void avr8_base_device::op_lpmzi(uint16_t op)
+{
+ uint16_t pd = ZREG;
+ m_r[RD5(op)] = m_program->read_byte(pd);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_elpmz(uint16_t op)
+{
+ m_r[RD5(op)] = m_program->read_byte((m_r[RAMPZ] << 16) | ZREG);
+}
+
+void avr8_base_device::op_elpmzi(uint16_t op)
+{
+ uint32_t pd32 = (m_r[RAMPZ] << 16) | ZREG;
+ m_r[RD5(op)] = m_program->read_byte(pd32);
+ pd32++;
+ m_r[RAMPZ] = (pd32 >> 16) & 0x00ff;
+ m_r[31] = (pd32 >> 8) & 0x00ff;
+ m_r[30] = pd32 & 0x00ff;
+}
+
+void avr8_base_device::op_ldyi(uint16_t op)
+{
+ uint16_t pd = YREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_ldyd(uint16_t op)
+{
+ const uint16_t pd = YREG - 1;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_ldx(uint16_t op)
+{
+ m_r[RD5(op)] = m_data->read_byte(XREG);
+}
+
+void avr8_base_device::op_ldxi(uint16_t op)
+{
+ uint16_t pd = XREG;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ pd++;
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_ldxd(uint16_t op)
+{
+ const uint16_t pd = XREG - 1;
+ m_r[RD5(op)] = m_data->read_byte(pd);
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_pop(uint16_t op)
+{
+ m_r[RD5(op)] = pop();
+}
+
+void avr8_base_device::op_sts(uint16_t op)
+{
+ m_pc += 2;
+ const uint16_t addr = m_program->read_word(m_pc);
+ m_data->write_byte(addr, m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_stzi(uint16_t op)
+{
+ uint16_t pd = ZREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_stzd(uint16_t op)
+{
+ const uint16_t pd = ZREG - 1;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[31] = (pd >> 8) & 0x00ff;
+ m_r[30] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_styi(uint16_t op)
+{
+ uint16_t pd = YREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_styd(uint16_t op)
+{
+ const uint16_t pd = YREG - 1;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[29] = (pd >> 8) & 0x00ff;
+ m_r[28] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_stx(uint16_t op)
+{
+ m_data->write_byte(XREG, m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_stxi(uint16_t op)
+{
+ uint16_t pd = XREG;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ pd++;
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_stxd(uint16_t op)
+{
+ const uint16_t pd = XREG - 1;
+ m_data->write_byte(pd, m_r[RD5(op)]);
+ m_r[27] = (pd >> 8) & 0x00ff;
+ m_r[26] = pd & 0x00ff;
+}
+
+void avr8_base_device::op_push(uint16_t op)
+{
+ push(m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_com(uint16_t op)
+{
+ const uint8_t res = ~m_r[RD5(op)];
+ m_r[SREG] &= ~(SREG_MASK_Z | SREG_MASK_N | SREG_MASK_V | SREG_MASK_S);
+ m_r[SREG] |= SREG_MASK_C;
+ if (BIT(res, 7))
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_S;
+ else if (res == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_neg(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = 0 - rd;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z | SREG_MASK_N | SREG_MASK_V | SREG_MASK_S | SREG_MASK_H);
+ if (res == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ else
+ {
+ m_r[SREG] |= SREG_MASK_C;
+ if (res == 0x80)
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_V;
+ else if (BIT(res, 7))
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_S;
+ }
+ if (BIT(rd, 3) || BIT(res, 3))
+ m_r[SREG] |= SREG_MASK_H;
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_swap(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ m_r[RD5(op)] = (rd >> 4) | (rd << 4);
+}
+
+void avr8_base_device::op_inc(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = rd + 1;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ if (res == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ else if (res == 0x80)
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_V;
+ else if (BIT(res, 7))
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_S;
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_asr(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = (rd & 0x80) | (rd >> 1);
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z | SREG_MASK_N | SREG_MASK_V | SREG_MASK_S);
+ m_r[SREG] |= m_shift_flag_cache[(rd << 8) | res];
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_lsr(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = rd >> 1;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z | SREG_MASK_N | SREG_MASK_V | SREG_MASK_S);
+ m_r[SREG] |= m_shift_flag_cache[(rd << 8) | res];
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_ror(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = (rd >> 1) | (m_r[SREG] << 7);
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z | SREG_MASK_N | SREG_MASK_V | SREG_MASK_S);
+ m_r[SREG] |= m_shift_flag_cache[(rd << 8) | res];
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_setf(uint16_t op)
+{
+ m_r[SREG] |= 1 << ((op >> 4) & 0x07);
+}
+
+void avr8_base_device::op_clrf(uint16_t op)
+{
+ m_r[SREG] &= ~(1 << ((op >> 4) & 0x07));
+}
+
+void avr8_base_device::op_ijmp(uint16_t op)
+{
+ m_pc = (ZREG << 1) - 2;
+}
+
+void avr8_base_device::op_eijmp(uint16_t op)
+{
+ m_pc = ((m_r[EIND] << 16 | ZREG) << 1) - 2;
+}
+
+void avr8_base_device::op_dec(uint16_t op)
+{
+ const uint8_t rd = m_r[RD5(op)];
+ const uint8_t res = rd - 1;
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z);
+ if (res == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ else if (res == 0x7f)
+ m_r[SREG] |= SREG_MASK_V | SREG_MASK_S;
+ else if (BIT(res, 7))
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_S;
+ m_r[RD5(op)] = res;
+}
+
+void avr8_base_device::op_jmp(uint16_t op)
+{
+ uint32_t offs = KCONST22(op) << 16;
+ m_pc += 2;
+ offs |= m_program->read_word(m_pc);
+ m_pc = offs << 1;
+ m_pc -= 2;
+}
+
+void avr8_base_device::op_call(uint16_t op)
+{
+ push(((m_pc >> 1) + 2) & 0x00ff);
+ push((((m_pc >> 1) + 2) >> 8) & 0x00ff);
+ uint32_t offs = KCONST22(op) << 16;
+ m_pc += 2;
+ offs |= m_program->read_word(m_pc);
+ m_pc = offs << 1;
+ m_pc -= 2;
+}
+
+void avr8_base_device::op_ret(uint16_t op)
+{
+ m_pc = pop() << 8;
+ m_pc |= pop();
+ m_pc = (m_pc << 1) - 2;
+}
+
+void avr8_base_device::op_reti(uint16_t op)
+{
+ m_pc = pop() << 8;
+ m_pc |= pop();
+ m_pc = (m_pc << 1) - 2;
+ m_r[SREG] |= SREG_MASK_I;
+}
+
+void avr8_base_device::op_sleep(uint16_t op)
+{
+ m_pc -= 2;
+}
+
+void avr8_base_device::op_break(uint16_t op)
+{
+ op_unimpl(op);
+}
+
+void avr8_base_device::op_wdr(uint16_t op)
+{
+ LOGMASKED(LOG_WDOG, "%s: Watchdog reset opcode\n", machine().describe_context());
+ //op_unimpl(op);
+}
+
+void avr8_base_device::op_lpm(uint16_t op)
+{
+ m_r[0] = m_program->read_byte(ZREG);
+}
+
+void avr8_base_device::op_elpm(uint16_t op)
+{
+ op_unimpl(op);
+}
+
+void avr8_base_device::op_spm(uint16_t op)
+{
+ op_unimpl(op);
+}
+
+void avr8_base_device::op_spmzi(uint16_t op)
+{
+ op_unimpl(op);
+}
+
+void avr8_base_device::op_icall(uint16_t op)
+{
+ push(((m_pc >> 1) + 1) & 0x00ff);
+ push((((m_pc >> 1) + 1) >> 8) & 0x00ff);
+ m_pc = (ZREG << 1) - 2;
+}
+
+void avr8_base_device::op_eicall(uint16_t op)
+{
+ op_unimpl(op);
+}
+
+void avr8_base_device::op_adiw(uint16_t op)
+{
+ const uint8_t rd = m_r[24 + (DCONST(op) << 1)];
+ const uint8_t rr = m_r[25 + (DCONST(op) << 1)];
+ const uint16_t pd = ((rr << 8) | rd) + KCONST6(op);
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ if (BIT(pd, 15))
+ {
+ m_r[SREG] |= SREG_MASK_N;
+ if (BIT(rr, 7))
+ m_r[SREG] |= SREG_MASK_S;
+ else
+ m_r[SREG] |= SREG_MASK_V;
+ }
+ else
+ {
+ if (pd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ if (BIT(rr, 7))
+ m_r[SREG] |= SREG_MASK_C;
+ }
+ m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff;
+ m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff;
+}
+
+void avr8_base_device::op_sbiw(uint16_t op)
+{
+ const uint8_t rd = m_r[24 + (DCONST(op) << 1)];
+ const uint8_t rr = m_r[25 + (DCONST(op) << 1)];
+ const uint16_t pd = ((rr << 8) | rd) - KCONST6(op);
+ m_r[SREG] &= ~(SREG_MASK_V | SREG_MASK_N | SREG_MASK_S | SREG_MASK_Z | SREG_MASK_C);
+ if (BIT(pd, 15))
+ {
+ m_r[SREG] |= SREG_MASK_N | SREG_MASK_S;
+ if (!BIT(rr, 7))
+ m_r[SREG] |= SREG_MASK_C;
+ }
+ else
+ {
+ if (pd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ if (BIT(rr, 7))
+ m_r[SREG] |= SREG_MASK_V | SREG_MASK_S;
+ }
+ m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff;
+ m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff;
+}
+
+void avr8_base_device::op_cbi(uint16_t op)
+{
+ m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) &~ (1 << RR3(op)));
+}
+
+void avr8_base_device::op_sbic(uint16_t op)
+{
+ if (!BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op)))
+ {
+ const uint16_t data = (uint32_t)m_program->read_word(m_pc + 2);
+ m_opcycles += is_long_opcode(data) ? 2 : 1;
+ m_pc += is_long_opcode(data) ? 4 : 2;
+ }
+}
+
+void avr8_base_device::op_sbi(uint16_t op)
+{
+ m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) | (1 << RR3(op)));
+}
+
+void avr8_base_device::op_sbis(uint16_t op)
+{
+ if (BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op)))
+ {
+ const uint16_t data = (uint32_t)m_program->read_word(m_pc + 2);
+ m_opcycles += is_long_opcode(data) ? 2 : 1;
+ m_pc += is_long_opcode(data) ? 4 : 2;
+ }
+}
+
+void avr8_base_device::op_mul(uint16_t op)
+{
+ const int16_t sd = (uint8_t)m_r[RD5(op)] * (uint8_t)m_r[RR5(op)];
+ m_r[1] = (sd >> 8) & 0x00ff;
+ m_r[0] = sd & 0x00ff;
+ m_r[SREG] &= ~(SREG_MASK_C | SREG_MASK_Z);
+ if (sd == 0)
+ m_r[SREG] |= SREG_MASK_Z;
+ else if (BIT(sd, 15))
+ m_r[SREG] |= SREG_MASK_C;
+}
+
+void avr8_base_device::op_out(uint16_t op)
+{
+ m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]);
+}
+
+void avr8_base_device::op_in(uint16_t op)
+{
+ m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op));
+}
+
+void avr8_base_device::op_rjmp(uint16_t op)
+{
+ m_pc += (int32_t)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)) << 1;
+}
+
+void avr8_base_device::op_rcall(uint16_t op)
+{
+ const int32_t offs = (int32_t)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)) << 1;
+ push(((m_pc >> 1) + 1) & 0x00ff);
+ push((((m_pc >> 1) + 1) >> 8) & 0x00ff);
+ m_pc += offs;
+}
+
+void avr8_base_device::op_ldi(uint16_t op)
+{
+ m_r[16 + RD4(op)] = KCONST8(op);
+}
+
+void avr8_base_device::op_brset(uint16_t op)
+{
+ if (BIT(m_r[SREG], op & 0x0007))
+ {
+ m_pc += util::sext(KCONST7(op), 7) << 1;
+ m_opcycles++;
+ }
+}
+
+void avr8_base_device::op_brclr(uint16_t op)
+{
+ if (!BIT(m_r[SREG], op & 0x0007))
+ {
+ m_pc += util::sext(KCONST7(op), 7) << 1;
+ m_opcycles++;
+ }
+}
+
+void avr8_base_device::op_bst(uint16_t op)
+{
+ if (BIT(m_r[RD5(op)], RR3(op)))
+ m_r[SREG] |= SREG_MASK_T;
+ else
+ m_r[SREG] &= ~SREG_MASK_T;
+}
+
+void avr8_base_device::op_bld(uint16_t op)
+{
+ if (m_r[SREG] & SREG_MASK_T)
+ m_r[RD5(op)] |= (1 << RR3(op));
+ else
+ m_r[RD5(op)] &= ~(1 << RR3(op));
+}
+
+void avr8_base_device::op_sbrs(uint16_t op)
+{
+ if (BIT(m_r[RD5(op)], RR3(op)))
+ {
+ const uint16_t data = (uint32_t)m_program->read_word(m_pc + 2);
+ m_opcycles += is_long_opcode(data) ? 2 : 1;
+ m_pc += is_long_opcode(data) ? 4 : 2;
+ }
+}
+
+void avr8_base_device::op_sbrc(uint16_t op)
+{
+ if (!BIT(m_r[RD5(op)], RR3(op)))
+ {
+ const uint16_t data = (uint32_t)m_program->read_word(m_pc + 2);
+ m_opcycles += is_long_opcode(data) ? 2 : 1;
+ m_pc += is_long_opcode(data) ? 4 : 2;
+ }
+}
+
+void avr8_base_device::op_unimpl(uint16_t op)
+{
+ unimplemented_opcode(op);
+}