diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/avr8/avr8.cpp | 1058 | ||||
-rw-r--r-- | src/devices/cpu/avr8/avr8.h | 125 | ||||
-rw-r--r-- | src/devices/cpu/avr8/avr8ops.hxx | 1357 | ||||
-rw-r--r-- | src/mame/drivers/craft.cpp | 27 |
4 files changed, 1588 insertions, 979 deletions
diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp index da035832847..024fead2789 100644 --- a/src/devices/cpu/avr8/avr8.cpp +++ b/src/devices/cpu/avr8/avr8.cpp @@ -110,7 +110,16 @@ enum AVR8_SREG_S, AVR8_SREG_H, AVR8_SREG_T, - AVR8_SREG_I + AVR8_SREG_I, + + AVR8_SREG_MASK_C = 0x01, + AVR8_SREG_MASK_Z = 0x02, + AVR8_SREG_MASK_N = 0x04, + AVR8_SREG_MASK_V = 0x08, + AVR8_SREG_MASK_S = 0x10, + AVR8_SREG_MASK_H = 0x20, + AVR8_SREG_MASK_T = 0x40, + AVR8_SREG_MASK_I = 0x80 }; // I/O Enums @@ -188,8 +197,9 @@ enum 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 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 SREG m_r[AVR8_REGIDX_SREG] #define NOT(x) (1 - (x)) // Opcode-Parsing Defines @@ -622,7 +632,7 @@ void attiny15_device::attiny15_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)) + : avr8_device(mconfig, tag, owner, clock, ATMEGA88, 0x0fff, address_map_constructor(FUNC(atmega88_device::atmega88_internal_map), this), 3) { } @@ -631,7 +641,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)) + : avr8_device(mconfig, tag, owner, clock, ATMEGA644, 0xffff, address_map_constructor(FUNC(atmega644_device::atmega644_internal_map), this), 3) { } @@ -640,7 +650,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)) + : avr8_device(mconfig, tag, owner, clock, ATMEGA1280, 0x1ffff, address_map_constructor(FUNC(atmega1280_device::atmega1280_internal_map), this), 6) { } @@ -649,7 +659,7 @@ 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)) + : avr8_device(mconfig, tag, owner, clock, ATMEGA2560, 0x1ffff, address_map_constructor(FUNC(atmega2560_device::atmega2560_internal_map), this), 6) { } @@ -658,7 +668,7 @@ atmega2560_device::atmega2560_device(const machine_config &mconfig, const char * //------------------------------------------------- attiny15_device::attiny15_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : avr8_device(mconfig, tag, owner, clock, ATTINY15, 0x03ff, address_map_constructor(FUNC(attiny15_device::attiny15_internal_map), this)) + : avr8_device(mconfig, tag, owner, clock, ATTINY15, 0x03ff, address_map_constructor(FUNC(attiny15_device::attiny15_internal_map), this), 2) { } @@ -666,7 +676,7 @@ attiny15_device::attiny15_device(const machine_config &mconfig, const char *tag, // avr8_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) +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, int32_t num_timers) : cpu_device(mconfig, type, tag, owner, clock) , m_shifted_pc(0) , m_program_config("program", ENDIANNESS_LITTLE, 8, 22) @@ -678,6 +688,7 @@ avr8_device::avr8_device(const machine_config &mconfig, const char *tag, device_ , m_efuses(0xff) , m_lock_bits(0xff) , m_pc(0) + , m_num_timers(num_timers) , m_spi_active(false) , m_spi_prescale(0) , m_spi_prescale_count(0) @@ -830,6 +841,10 @@ void avr8_device::device_start() 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_wgm1)); + save_item(NAME(m_timer1_compare_mode)); + save_item(NAME(m_ocr1)); + save_item(NAME(m_timer1_count)); // SPI save_item(NAME(m_spi_active)); @@ -843,6 +858,21 @@ void avr8_device::device_start() // 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(); } //------------------------------------------------- @@ -883,7 +913,7 @@ void avr8_device::device_reset() m_spi_prescale = 0; m_spi_prescale_count = 0; - for (int t = 0; t <= 5; t++) + for (int t = 0; t < m_num_timers; t++) { m_timer_top[t] = 0; m_timer_increment[t] = 1; @@ -891,6 +921,15 @@ void avr8_device::device_reset() m_timer_prescale_count[t] = 0; } + m_wgm1 = 0; + m_timer1_compare_mode[0] = 0; + m_timer1_compare_mode[1] = 0; + for (int reg = AVR8_REG_A; reg <= AVR8_REG_C; reg++) + { + m_ocr1[reg] = 0; + } + m_timer1_count = 0; + m_ocr2_not_reached_yet = true; m_interrupt_pending = false; } @@ -1097,9 +1136,9 @@ void atmega2560_device::update_interrupt(int source) //************************************************************************** // REGISTER HANDLING //************************************************************************** -void avr8_device::timer_tick(int cycles) +void avr8_device::timer_tick() { - for (int count = 0; count < cycles; count++) + for (int count = 0; count < m_opcycles; count++) { if (m_spi_active && m_spi_prescale > 0 && m_spi_prescale_countdown >= 0) { @@ -1114,7 +1153,7 @@ void avr8_device::timer_tick(int cycles) } } - for (int t = 0; t <= 5; t++) + for (int t = 0; t < m_num_timers; t++) { if (m_timer_prescale[t] != 0) { @@ -1284,46 +1323,38 @@ void avr8_device::update_ocr0(uint8_t newval, uint8_t reg) // Timer 1 Handling -void avr8_device::timer1_tick() +inline void avr8_device::timer1_tick() { /* TODO: Handle comparison, setting OC1A pin, detection of BOTTOM and TOP */ - 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); - - const 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]) }; - static const uint8_t s_com_mask[2] = { AVR8_TCCR1A_COM1A_MASK, AVR8_TCCR1A_COM1B_MASK }; - static const uint8_t s_com_shift[2] = { AVR8_TCCR1A_COM1A_SHIFT, AVR8_TCCR1A_COM1B_SHIFT }; static const uint8_t s_ocf1[2] = { (1 << AVR8_TIFR1_OCF1A_SHIFT), (1 << AVR8_TIFR1_OCF1B_SHIFT) }; static const uint8_t s_int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B }; int32_t increment = m_timer_increment[1]; for (int32_t reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++) { - switch (wgm1) + switch (m_wgm1) { case WGM1_CTC_OCR: - if (count == 0xffff) + if (m_timer1_count == 0xffff) { m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK; update_interrupt(AVR8_INTIDX_TOV1); - count = 0; + m_timer1_count = 0; increment = 0; } - if (count == ocr1[reg]) + if (m_timer1_count == m_ocr1[reg]) { if (reg == 0) { - count = 0; + m_timer1_count = 0; increment = 0; } m_r[AVR8_REGIDX_TIFR1] |= s_ocf1[reg]; update_interrupt(s_int1[reg]); } - else if (count == 0) + else if (m_timer1_count == 0) { if (reg == 0) { @@ -1337,18 +1368,17 @@ void avr8_device::timer1_tick() break; case WGM1_FAST_PWM_OCR: - if (count == ocr1[reg]) + if (m_timer1_count == m_ocr1[reg]) { if (reg == 0) { m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK; update_interrupt(AVR8_INTIDX_TOV1); - count = 0; + m_timer1_count = 0; increment = 0; } - const int32_t compare_mode = (m_r[AVR8_REGIDX_TCCR1A] & s_com_mask[reg]) >> s_com_shift[reg]; - switch (compare_mode) + switch (m_timer1_compare_mode[reg] & 3) { case 0: /* Normal Operation; OC1A/B disconnected */ break; @@ -1375,7 +1405,7 @@ void avr8_device::timer1_tick() m_r[AVR8_REGIDX_TIFR1] |= s_ocf1[reg]; update_interrupt(s_int1[reg]); } - else if (count == 0) + else if (m_timer1_count == 0) { if (reg == 0) { @@ -1383,8 +1413,7 @@ void avr8_device::timer1_tick() update_interrupt(AVR8_INTIDX_TOV1); } - const int32_t compare_mode = (m_r[AVR8_REGIDX_TCCR1A] & s_com_mask[reg]) >> s_com_shift[reg]; - switch (compare_mode) + switch (m_timer1_compare_mode[reg] & 3) { case 0: /* Normal Operation; OC1A/B disconnected */ break; @@ -1414,14 +1443,12 @@ void avr8_device::timer1_tick() break; default: - LOGMASKED(LOG_TIMER1 | LOG_UNKNOWN, "%s: timer1_tick: Unknown waveform generation mode: %02x\n", machine().describe_context(), wgm1); + LOGMASKED(LOG_TIMER1 | LOG_UNKNOWN, "%s: timer1_tick: Unknown waveform generation mode: %02x\n", machine().describe_context(), m_wgm1); break; } } - count += increment; - m_r[AVR8_REGIDX_TCNT1H] = (count >> 8) & 0xff; - m_r[AVR8_REGIDX_TCNT1L] = count & 0xff; + m_timer1_count += increment; } void avr8_device::update_timer_waveform_gen_mode(uint8_t t, uint8_t mode) @@ -1483,6 +1510,10 @@ void avr8_device::update_timer_waveform_gen_mode(uint8_t t, uint8_t mode) break; } + if (t == 1) + { + m_wgm1 = ((m_r[AVR8_REGIDX_TCCR1B] & AVR8_TCCR1B_WGM1_32_MASK) >> 1) | (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_WGM1_10_MASK); + } if (m_timer_top[t] == -1) { m_timer_top[t] = 0; @@ -1502,6 +1533,9 @@ void avr8_device::changed_tccr1a(uint8_t data) { update_timer_waveform_gen_mode(1, AVR8_WGM1); } + + m_timer1_compare_mode[AVR8_REG_A] = (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT; + m_timer1_compare_mode[AVR8_REG_B] = (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT; } void avr8_device::update_timer1_input_noise_canceler() @@ -1547,12 +1581,11 @@ void avr8_device::changed_tccr1b(uint8_t data) void avr8_device::update_ocr1(uint16_t newval, uint8_t reg) { - 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 + static const int32_t s_high_indices[3] = { AVR8_REGIDX_OCR1AH, AVR8_REGIDX_OCR1BH, AVR8_REGIDX_OCR1CH }; + static const int32_t s_low_indices[3] = { AVR8_REGIDX_OCR1AL, AVR8_REGIDX_OCR1BL, AVR8_REGIDX_OCR1CL }; + m_r[s_high_indices[reg]] = (uint8_t)(newval >> 8); + m_r[s_low_indices[reg]] = (uint8_t)newval; + m_ocr1[reg] = newval; } // Timer 2 Handling @@ -2488,11 +2521,11 @@ WRITE8_MEMBER(avr8_device::regs_w) break; case AVR8_REGIDX_TCNT1L: - AVR8_TCNT1L = data; + m_timer1_count = (m_timer1_count & 0xff00) | data; break; case AVR8_REGIDX_TCNT1H: - AVR8_TCNT1H = data; + m_timer1_count = (m_timer1_count & 0x00ff) | (data << 8); break; case AVR8_REGIDX_ICR1L: @@ -2870,7 +2903,9 @@ READ8_MEMBER(avr8_device::regs_r) case AVR8_REGIDX_TCNT1L: + return (uint8_t)m_timer1_count; case AVR8_REGIDX_TCNT1H: + return (uint8_t)(m_timer1_count >> 8); case AVR8_REGIDX_TCNT2: case AVR8_REGIDX_UCSR0A: return m_r[offset]; @@ -2923,6 +2958,7 @@ void avr8_device::execute_set_input(int inputnum, int state) { } +#include "avr8ops.hxx" //------------------------------------------------- // execute_run - execute a timeslice's worth of @@ -2931,940 +2967,22 @@ void avr8_device::execute_set_input(int inputnum, int state) void avr8_device::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_shifted_pc); - op = (uint32_t)m_program->read_word(m_shifted_pc); - - switch (op & 0xf000) - { - case 0x0000: - switch (op & 0x0f00) - { - case 0x0000: // NOP - break; - case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd - m_r[(RD4(op) << 1) + 1] = m_r[(RR4(op) << 1) + 1]; - m_r[RD4(op) << 1] = m_r[RR4(op) << 1]; - break; - case 0x0200: // MULS Rd,Rr - sd = (int8_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: // Multiplication - 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) - { - 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); - 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); - 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: - 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); - 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 - m_pc--; - opcycles = 1; - //unimplemented_opcode(op); - break; - case 0x0090: // BREAK - unimplemented_opcode(op); - break; - case 0x00a0: // WDR - LOGMASKED(LOG_WDOG, "%s: Watchdog reset opcode\n", machine().describe_context()); - opcycles = 1; - break; - case 0x00c0: // LPM - m_r[0] = m_program->read_byte(ZREG); - opcycles = 3; - break; - case 0x00d0: // ELPM - unimplemented_opcode(op); - break; - case 0x00e0: // SPM - unimplemented_opcode(op); - break; - case 0x00f0: // SPM Z+ - unimplemented_opcode(op); - break; - default: - unimplemented_opcode(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 - unimplemented_opcode(op); - break; - default: - 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 - //op <<= 8; - //op |= oprom[pos++]; - //op <<= 8; - //op |= oprom[pos++]; - unimplemented_opcode(op); - break; - case 0x000e: - case 0x000f: // CALL k - //op <<= 8; - //op |= oprom[pos++]; - //op <<= 8; - //op |= oprom[pos++]; - 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 - 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 (!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; - } - break; - case 0xb000: - if (op & 0x0800) // OUT A,Rr - { - m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]); - } - else // IN Rd,A - { - m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op)); - } - break; - case 0xc000: // RJMP k - offs = (int32_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) - { - 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 (!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; - } - break; - } - + const uint16_t op = (uint32_t)m_program->read_word(m_shifted_pc); + m_opcycles = m_op_cycles[op]; + ((this)->*(m_op_funcs[op]))(op); m_pc++; m_shifted_pc = m_pc << 1; - m_icount -= opcycles; + m_icount -= m_opcycles; - timer_tick(opcycles); + timer_tick(); } } diff --git a/src/devices/cpu/avr8/avr8.h b/src/devices/cpu/avr8/avr8.h index 49b061c86c7..ba89e3b00a7 100644 --- a/src/devices/cpu/avr8/avr8.h +++ b/src/devices/cpu/avr8/avr8.h @@ -73,7 +73,19 @@ public: uint32_t m_shifted_pc; 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); + 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, int32_t num_timers); + + typedef void (avr8_device::*op_func) (uint16_t op); + + 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; @@ -115,10 +127,15 @@ protected: uint8_t m_r[0x200]; // internal timers + int32_t m_num_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]; + int32_t m_wgm1; + int32_t m_timer1_compare_mode[2]; + uint16_t m_ocr1[3]; + uint16_t m_timer1_count; bool m_ocr2_not_reached_yet; // SPI @@ -154,7 +171,7 @@ protected: void set_irq_line(uint16_t vector, int state); // timers - void timer_tick(int cycles); + void timer_tick(); void update_timer_clock_source(uint8_t timer, uint8_t selection); void update_timer_waveform_gen_mode(uint8_t timer, uint8_t mode); @@ -166,7 +183,7 @@ protected: void timer0_force_output_compare(int reg); // timer 1 - void timer1_tick(); + inline void timer1_tick(); void changed_tccr1a(uint8_t data); void changed_tccr1b(uint8_t data); void update_timer1_input_noise_canceler(); @@ -203,6 +220,108 @@ protected: // void update_ocr5(uint8_t newval, uint8_t reg); // void timer5_force_output_compare(int reg); + // 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; diff --git a/src/devices/cpu/avr8/avr8ops.hxx b/src/devices/cpu/avr8/avr8ops.hxx new file mode 100644 index 00000000000..4c465230d21 --- /dev/null +++ b/src/devices/cpu/avr8/avr8ops.hxx @@ -0,0 +1,1357 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Sandro Ronco, Felipe Sanches +/*************************************************************************** + + Atmel 8-bit AVR simulator + + Opcode implementations + +***************************************************************************/ + +void avr8_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_device::op_nop; + break; + case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd + m_op_funcs[op] = &avr8_device::op_movw; + break; + case 0x0200: // MULS Rd,Rr + m_op_funcs[op] = &avr8_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_device::op_mulsu; + m_op_cycles[op] = 2; + break; + case 0x0001: // FMUL Rd,Rr + m_op_funcs[op] = &avr8_device::op_fmul; + m_op_cycles[op] = 2; + break; + case 0x0002: // FMULS Rd,Rr + m_op_funcs[op] = &avr8_device::op_fmuls; + m_op_cycles[op] = 2; + break; + case 0x0003: // FMULSU Rd,Rr + m_op_funcs[op] = &avr8_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_device::op_cpc; + break; + case 0x0800: + case 0x0900: + case 0x0a00: + case 0x0b00: // SBC Rd,Rr + m_op_funcs[op] = &avr8_device::op_sbc; + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: // ADD Rd,Rr + m_op_funcs[op] = &avr8_device::op_add; + break; + } + break; + case 0x1000: + switch (op & 0x0c00) + { + case 0x0000: // CPSE Rd,Rr + m_op_funcs[op] = &avr8_device::op_cpse; + break; + case 0x0400: // CP Rd,Rr + m_op_funcs[op] = &avr8_device::op_cp; + break; + case 0x0800: // SUB Rd,Rr + m_op_funcs[op] = &avr8_device::op_sub; + break; + case 0x0c00: // ADC Rd,Rr + m_op_funcs[op] = &avr8_device::op_adc; + break; + } + break; + case 0x2000: + switch (op & 0x0c00) + { + case 0x0000: // AND Rd,Rr + m_op_funcs[op] = &avr8_device::op_and; + break; + case 0x0400: // EOR Rd,Rr + m_op_funcs[op] = &avr8_device::op_eor; + break; + case 0x0800: // OR Rd,Rr + m_op_funcs[op] = &avr8_device::op_or; + break; + case 0x0c00: // MOV Rd,Rr + m_op_funcs[op] = &avr8_device::op_mov; + break; + } + break; + case 0x3000: // CPI Rd,K + m_op_funcs[op] = &avr8_device::op_cpi; + break; + case 0x4000: // SBCI Rd,K + m_op_funcs[op] = &avr8_device::op_sbci; + break; + case 0x5000: // SUBI Rd,K + m_op_funcs[op] = &avr8_device::op_subi; + break; + case 0x6000: // ORI Rd,K + m_op_funcs[op] = &avr8_device::op_ori; + break; + case 0x7000: // ANDI Rd,K + m_op_funcs[op] = &avr8_device::op_andi; + break; + case 0x8000: + case 0xa000: + switch (op & 0x0208) + { + case 0x0000: // LDD Rd,Z+q + m_op_funcs[op] = &avr8_device::op_lddz; + m_op_cycles[op] = 2; + break; + case 0x0008: // LDD Rd,Y+q + m_op_funcs[op] = &avr8_device::op_lddy; + m_op_cycles[op] = 2; + break; + case 0x0200: // STD Z+q,Rr + m_op_funcs[op] = &avr8_device::op_stdz; + m_op_cycles[op] = 2; + break; + case 0x0208: // STD Y+q,Rr + m_op_funcs[op] = &avr8_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_device::op_lds; + m_op_cycles[op] = 2; + break; + case 0x0001: // LD Rd,Z+ + m_op_funcs[op] = &avr8_device::op_ldzi; + m_op_cycles[op] = 2; + break; + case 0x0002: // LD Rd,-Z + m_op_funcs[op] = &avr8_device::op_ldzd; + m_op_cycles[op] = 2; + break; + case 0x0004: // LPM Rd,Z + m_op_funcs[op] = &avr8_device::op_lpmz; + m_op_cycles[op] = 3; + break; + case 0x0005: // LPM Rd,Z+ + m_op_funcs[op] = &avr8_device::op_lpmzi; + m_op_cycles[op] = 3; + break; + case 0x0006: // ELPM Rd,Z + m_op_funcs[op] = &avr8_device::op_elpmz; + m_op_cycles[op] = 3; + break; + case 0x0007: // ELPM Rd,Z+ + m_op_funcs[op] = &avr8_device::op_elpmzi; + m_op_cycles[op] = 3; + break; + case 0x0009: // LD Rd,Y+ + m_op_funcs[op] = &avr8_device::op_ldyi; + m_op_cycles[op] = 2; + break; + case 0x000a: // LD Rd,-Y + m_op_funcs[op] = &avr8_device::op_ldyd; + m_op_cycles[op] = 2; + break; + case 0x000c: // LD Rd,X + m_op_funcs[op] = &avr8_device::op_ldx; + m_op_cycles[op] = 2; + break; + case 0x000d: // LD Rd,X+ + m_op_funcs[op] = &avr8_device::op_ldxi; + m_op_cycles[op] = 2; + break; + case 0x000e: // LD Rd,-X + m_op_funcs[op] = &avr8_device::op_ldxd; + m_op_cycles[op] = 2; + break; + case 0x000f: // POP Rd + m_op_funcs[op] = &avr8_device::op_pop; + m_op_cycles[op] = 2; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x0200: + case 0x0300: + switch (op & 0x000f) + { + case 0x0000: // STS k,Rr + m_op_funcs[op] = &avr8_device::op_sts; + m_op_cycles[op] = 2; + break; + case 0x0001: // ST Z+,Rd + m_op_funcs[op] = &avr8_device::op_stzi; + m_op_cycles[op] = 2; + break; + case 0x0002: // ST -Z,Rd + m_op_funcs[op] = &avr8_device::op_stzd; + m_op_cycles[op] = 2; + break; + case 0x0009: // ST Y+,Rd + m_op_funcs[op] = &avr8_device::op_styi; + m_op_cycles[op] = 2; + break; + case 0x000a: // ST -Y,Rd + m_op_funcs[op] = &avr8_device::op_styd; + m_op_cycles[op] = 2; + break; + case 0x000c: // ST X,Rd + m_op_funcs[op] = &avr8_device::op_stx; + break; + case 0x000d: // ST X+,Rd + m_op_funcs[op] = &avr8_device::op_stxi; + m_op_cycles[op] = 2; + break; + case 0x000e: // ST -X,Rd + m_op_funcs[op] = &avr8_device::op_stxd; + m_op_cycles[op] = 2; + break; + case 0x000f: // PUSH Rd + m_op_funcs[op] = &avr8_device::op_push; + m_op_cycles[op] = 2; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x0400: + switch (op & 0x000f) + { + case 0x0000: // COM Rd + m_op_funcs[op] = &avr8_device::op_com; + break; + case 0x0001: // NEG Rd + m_op_funcs[op] = &avr8_device::op_neg; + break; + case 0x0002: // SWAP Rd + m_op_funcs[op] = &avr8_device::op_swap; + break; + case 0x0003: // INC Rd + m_op_funcs[op] = &avr8_device::op_inc; + break; + case 0x0005: // ASR Rd + m_op_funcs[op] = &avr8_device::op_asr; + break; + case 0x0006: // LSR Rd + m_op_funcs[op] = &avr8_device::op_lsr; + break; + case 0x0007: // ROR Rd + m_op_funcs[op] = &avr8_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_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_device::op_clrf; + break; + } + break; + case 0x0009: + switch (op & 0x00f0) + { + case 0x0000: // IJMP + m_op_funcs[op] = &avr8_device::op_ijmp; + m_op_cycles[op] = 2; + break; + case 0x0010: // EIJMP + m_op_funcs[op] = &avr8_device::op_eijmp; + m_op_cycles[op] = 2; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x000a: // DEC Rd + m_op_funcs[op] = &avr8_device::op_dec; + break; + case 0x000c: + case 0x000d: // JMP k + m_op_funcs[op] = &avr8_device::op_jmp; + m_op_cycles[op] = 3; + break; + case 0x000e: // CALL k + case 0x000f: + m_op_funcs[op] = &avr8_device::op_call; + m_op_cycles[op] = 4; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x0500: + switch (op & 0x000f) + { + case 0x0000: // COM Rd + m_op_funcs[op] = &avr8_device::op_com; + break; + case 0x0001: // NEG Rd + m_op_funcs[op] = &avr8_device::op_neg; + break; + case 0x0002: // SWAP Rd + m_op_funcs[op] = &avr8_device::op_swap; + break; + case 0x0003: // INC Rd + m_op_funcs[op] = &avr8_device::op_inc; + break; + case 0x0005: // ASR Rd + m_op_funcs[op] = &avr8_device::op_asr; + break; + case 0x0006: // LSR Rd + m_op_funcs[op] = &avr8_device::op_lsr; + break; + case 0x0007: // ROR Rd + m_op_funcs[op] = &avr8_device::op_ror; + break; + case 0x0008: + switch (op & 0x00f0) + { + case 0x0000: // RET + m_op_funcs[op] = &avr8_device::op_ret; + m_op_cycles[op] = 4; + break; + case 0x0010: // RETI + m_op_funcs[op] = &avr8_device::op_reti; + m_op_cycles[op] = 4; + break; + case 0x0080: // SLEEP + m_op_funcs[op] = &avr8_device::op_sleep; + m_op_cycles[op] = 1; + break; + case 0x0090: // BREAK + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + case 0x00a0: // WDR + m_op_funcs[op] = &avr8_device::op_wdr; + break; + case 0x00c0: // LPM + m_op_funcs[op] = &avr8_device::op_lpm; + m_op_cycles[op] = 3; + break; + case 0x00d0: // ELPM + m_op_funcs[op] = &avr8_device::op_elpm; + break; + case 0x00e0: // SPM + m_op_funcs[op] = &avr8_device::op_spm; + break; + case 0x00f0: // SPM Z+ + m_op_funcs[op] = &avr8_device::op_spmzi; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x0009: + switch (op & 0x00f0) + { + case 0x0000: // ICALL + m_op_funcs[op] = &avr8_device::op_icall; + m_op_cycles[op] = 3; + break; + case 0x0010: // EICALL + m_op_funcs[op] = &avr8_device::op_eicall; + break; + default: + m_op_funcs[op] = &avr8_device::op_unimpl; + break; + } + break; + case 0x000a: // DEC Rd + m_op_funcs[op] = &avr8_device::op_dec; + break; + case 0x000c: + case 0x000d: // JMP k + m_op_funcs[op] = &avr8_device::op_jmp; + m_op_cycles[op] = 3; + break; + case 0x000e: + case 0x000f: // CALL k + m_op_funcs[op] = &avr8_device::op_call; + m_op_cycles[op] = 4; + break; + } + break; + case 0x0600: // ADIW Rd+1:Rd,K + m_op_funcs[op] = &avr8_device::op_adiw; + m_op_cycles[op] = 2; + break; + case 0x0700: // SBIW Rd+1:Rd,K + m_op_funcs[op] = &avr8_device::op_sbiw; + m_op_cycles[op] = 2; + break; + case 0x0800: // CBI A,b + m_op_funcs[op] = &avr8_device::op_cbi; + m_op_cycles[op] = 2; + break; + case 0x0900: // SBIC A,b + m_op_funcs[op] = &avr8_device::op_sbic; + break; + case 0x0a00: // SBI A,b + m_op_funcs[op] = &avr8_device::op_sbi; + m_op_cycles[op] = 2; + break; + case 0x0b00: // SBIS A,b + m_op_funcs[op] = &avr8_device::op_sbis; + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: // MUL Rd,Rr + m_op_funcs[op] = &avr8_device::op_mul; + m_op_cycles[op] = 2; + break; + } + break; + case 0xb000: + if (op & 0x0800) // OUT A,Rr + { + m_op_funcs[op] = &avr8_device::op_out; + } + else // IN Rd,A + { + m_op_funcs[op] = &avr8_device::op_in; + } + break; + case 0xc000: // RJMP k + m_op_funcs[op] = &avr8_device::op_rjmp; + m_op_cycles[op] = 2; + break; + case 0xd000: // RCALL k + m_op_funcs[op] = &avr8_device::op_rcall; + m_op_cycles[op] = 3; + break; + case 0xe000: // LDI Rd,K + m_op_funcs[op] = &avr8_device::op_ldi; + break; + case 0xf000: + switch (op & 0x0c00) + { + case 0x0000: // BRLO through BRIE + m_op_funcs[op] = &avr8_device::op_brset; + break; + case 0x0400: // BRSH through BRID + m_op_funcs[op] = &avr8_device::op_brclr; + break; + case 0x0800: + if (op & 0x0200) // BST Rd, b + { + m_op_funcs[op] = &avr8_device::op_bst; + } + else // BLD Rd, b + { + m_op_funcs[op] = &avr8_device::op_bld; + } + break; + case 0x0c00: + if (op & 0x0200) // SBRS Rd, b + { + m_op_funcs[op] = &avr8_device::op_sbrs; + } + else // SBRC Rd, b + { + m_op_funcs[op] = &avr8_device::op_sbrc; + } + break; + } + break; + } + } +} + +void avr8_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))) ? AVR8_SREG_MASK_H : 0; + flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) | (!(rd & 0x80) & !(rr & 0x80) & (res & 0x80))) ? AVR8_SREG_MASK_V : 0; + flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; + flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? AVR8_SREG_MASK_C : 0; + m_add_flag_cache[(rd << 8) | rr] = flags; + } + } +} + +void avr8_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))) ? AVR8_SREG_MASK_H : 0; + flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) | (!(rd & 0x80) & !(rr & 0x80) & (res & 0x80))) ? AVR8_SREG_MASK_V : 0; + flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; + flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? AVR8_SREG_MASK_C : 0; + m_adc_flag_cache[(c << 16) | (rd << 8) | rr] = flags; + } + } + } +} + +void avr8_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))) ? AVR8_SREG_MASK_H : 0; + flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? AVR8_SREG_MASK_V : 0; + flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; + flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? AVR8_SREG_MASK_C : 0; + m_sub_flag_cache[(rd << 8) | rr] = flags; + } + } +} + +void avr8_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))) ? AVR8_SREG_MASK_H : 0; + flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? AVR8_SREG_MASK_V : 0; + flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (res == 0) ? (z ? AVR8_SREG_MASK_Z : 0) : 0; + flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? AVR8_SREG_MASK_C : 0; + m_sbc_flag_cache[(z << 17) | (c << 16) | (rd << 8) | rr] = flags; + } + } + } + } +} + +void avr8_device::populate_bool_flag_cache() +{ + for (uint16_t res = 0; res < 0x100; res++) + { + uint8_t flags = 0; + flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; + m_bool_flag_cache[res] = flags; + } +} + +void avr8_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) ? AVR8_SREG_MASK_C : 0; + flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; + flags |= (rd & 0x80) ? AVR8_SREG_MASK_N : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_C)) ? AVR8_SREG_MASK_V : 0; + flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + m_shift_flag_cache[(rd << 8) | res] = flags; + } + } +} + +void avr8_device::op_nop(uint16_t op) +{ +} + +void avr8_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_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_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 = SREG & AVR8_SREG_MASK_C; + const uint8_t z = (SREG & AVR8_SREG_MASK_Z) ? (1 << 17) : 0; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr]; +} + +void avr8_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 = SREG & AVR8_SREG_MASK_C; + const uint8_t res = rd - (rr + c); + m_r[RD5(op)] = res; + const uint8_t z = (SREG & AVR8_SREG_MASK_Z) ? (1 << 17) : 0; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr]; +} + +void avr8_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; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_add_flag_cache[(rd << 8) | rr]; +} + +void avr8_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_shifted_pc + 2); + m_opcycles += is_long_opcode(data) ? 2 : 1; + m_pc += is_long_opcode(data) ? 2 : 1; + } +} + +void avr8_device::op_cp(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t rr = m_r[RR5(op)]; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sub_flag_cache[(rd << 8) | rr]; +} + +void avr8_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; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sub_flag_cache[(rd << 8) | rr]; +} + +void avr8_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 = SREG & AVR8_SREG_MASK_C; + const uint8_t res = rd + rr + c; + m_r[RD5(op)] = res; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_adc_flag_cache[(c << 16) | (rd << 8) | rr]; +} + +void avr8_device::op_and(uint16_t op) +{ + const uint8_t res = m_r[RD5(op)] & m_r[RR5(op)]; + m_r[RD5(op)] = res; + SREG &= ~(AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z); + SREG |= m_bool_flag_cache[res]; +} + +void avr8_device::op_eor(uint16_t op) +{ + const uint8_t res = m_r[RD5(op)] ^ m_r[RR5(op)]; + m_r[RD5(op)] = res; + SREG &= ~(AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z); + SREG |= m_bool_flag_cache[res]; +} + +void avr8_device::op_or(uint16_t op) +{ + const uint8_t res = m_r[RD5(op)] | m_r[RR5(op)]; + m_r[RD5(op)] = res; + SREG &= ~(AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z); + SREG |= m_bool_flag_cache[res]; +} + +void avr8_device::op_mov(uint16_t op) +{ + m_r[RD5(op)] = m_r[RR5(op)]; +} + +void avr8_device::op_cpi(uint16_t op) +{ + const uint8_t rd = m_r[16 + RD4(op)]; + const uint8_t rr = KCONST8(op); + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sub_flag_cache[(rd << 8) | rr]; +} + +void avr8_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 = SREG & AVR8_SREG_MASK_C; + const uint8_t res = rd - (rr + c); + m_r[16 + RD4(op)] = res; + const uint8_t z = (SREG & AVR8_SREG_MASK_Z) ? (1 << 17) : 0; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sbc_flag_cache[z | (c << 16) | (rd << 8) | rr]; +} + +void avr8_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; + SREG &= ~(AVR8_SREG_MASK_H | AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_C); + SREG |= m_sub_flag_cache[(rd << 8) | rr]; +} + +void avr8_device::op_ori(uint16_t op) +{ + const uint8_t res = m_r[16 + RD4(op)] | KCONST8(op); + m_r[16 + RD4(op)] = res; + SREG &= ~(AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z); + SREG |= m_bool_flag_cache[res]; +} + +void avr8_device::op_andi(uint16_t op) +{ + const uint8_t res = m_r[16 + RD4(op)] & KCONST8(op); + m_r[16 + RD4(op)] = res; + SREG &= ~(AVR8_SREG_MASK_V | AVR8_SREG_MASK_N | AVR8_SREG_MASK_S | AVR8_SREG_MASK_Z); + SREG |= m_bool_flag_cache[res]; +} + +void avr8_device::op_lddz(uint16_t op) +{ + m_r[RD5(op)] = m_data->read_byte(ZREG + QCONST6(op)); +} + +void avr8_device::op_lddy(uint16_t op) +{ + m_r[RD5(op)] = m_data->read_byte(YREG + QCONST6(op)); +} + +void avr8_device::op_stdz(uint16_t op) +{ + m_data->write_byte(ZREG + QCONST6(op), m_r[RD5(op)]); +} + +void avr8_device::op_stdy(uint16_t op) +{ + m_data->write_byte(YREG + QCONST6(op), m_r[RD5(op)]); +} + +void avr8_device::op_lds(uint16_t op) +{ + m_pc++; + m_shifted_pc += 2; + const uint16_t addr = m_program->read_word(m_shifted_pc); + m_r[RD5(op)] = m_data->read_byte(addr); +} + +void avr8_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_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_device::op_lpmz(uint16_t op) +{ + m_r[RD5(op)] = m_program->read_byte(ZREG); +} + +void avr8_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_device::op_elpmz(uint16_t op) +{ + m_r[RD5(op)] = m_program->read_byte((m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG); +} + +void avr8_device::op_elpmzi(uint16_t op) +{ + uint32_t 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; +} + +void avr8_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_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_device::op_ldx(uint16_t op) +{ + m_r[RD5(op)] = m_data->read_byte(XREG); +} + +void avr8_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_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_device::op_pop(uint16_t op) +{ + m_r[RD5(op)] = pop(); +} + +void avr8_device::op_sts(uint16_t op) +{ + m_pc++; + m_shifted_pc += 2; + const uint16_t addr = m_program->read_word(m_shifted_pc); + m_data->write_byte(addr, m_r[RD5(op)]); +} + +void avr8_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_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_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_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_device::op_stx(uint16_t op) +{ + m_data->write_byte(XREG, m_r[RD5(op)]); +} + +void avr8_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_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_device::op_push(uint16_t op) +{ + push(m_r[RD5(op)]); +} + +void avr8_device::op_com(uint16_t op) +{ + const uint8_t res = ~m_r[RD5(op)]; + 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; +} + +void avr8_device::op_neg(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t 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; +} + +void avr8_device::op_swap(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + m_r[RD5(op)] = (rd >> 4) | (rd << 4); +} + +void avr8_device::op_inc(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t 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; +} + +void avr8_device::op_asr(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t res = (rd & 0x80) | (rd >> 1); + SREG &= ~(AVR8_SREG_MASK_C | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_N | AVR8_SREG_MASK_V | AVR8_SREG_MASK_S); + SREG |= m_shift_flag_cache[(rd << 8) | res]; + m_r[RD5(op)] = res; +} + +void avr8_device::op_lsr(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t res = rd >> 1; + SREG &= ~(AVR8_SREG_MASK_C | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_N | AVR8_SREG_MASK_V | AVR8_SREG_MASK_S); + SREG |= m_shift_flag_cache[(rd << 8) | res]; + m_r[RD5(op)] = res; +} + +void avr8_device::op_ror(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t res = (rd >> 1) | (SREG_R(AVR8_SREG_C) << 7); + SREG &= ~(AVR8_SREG_MASK_C | AVR8_SREG_MASK_Z | AVR8_SREG_MASK_N | AVR8_SREG_MASK_V | AVR8_SREG_MASK_S); + SREG |= m_shift_flag_cache[(rd << 8) | res]; + m_r[RD5(op)] = res; +} + +void avr8_device::op_setf(uint16_t op) +{ + SREG_W((op >> 4) & 0x07, 1); +} + +void avr8_device::op_clrf(uint16_t op) +{ + SREG_W((op >> 4) & 0x07, 0); +} + +void avr8_device::op_ijmp(uint16_t op) +{ + m_pc = ZREG - 1; +} + +void avr8_device::op_eijmp(uint16_t op) +{ + m_pc = (m_r[AVR8_REGIDX_EIND] << 16 | ZREG) - 1; +} + +void avr8_device::op_dec(uint16_t op) +{ + const uint8_t rd = m_r[RD5(op)]; + const uint8_t 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; +} + +void avr8_device::op_jmp(uint16_t op) +{ + uint32_t offs = KCONST22(op) << 16; + m_pc++; + m_shifted_pc += 2; + offs |= m_program->read_word(m_shifted_pc); + m_pc = offs; + m_pc--; +} + +void avr8_device::op_call(uint16_t op) +{ + push((m_pc + 2) & 0x00ff); + push(((m_pc + 2) >> 8) & 0x00ff); + uint32_t offs = KCONST22(op) << 16; + m_pc++; + m_shifted_pc += 2; + offs |= m_program->read_word(m_shifted_pc); + m_pc = offs; + m_pc--; +} + +void avr8_device::op_ret(uint16_t op) +{ + m_pc = pop() << 8; + m_pc |= pop(); + m_pc--; +} + +void avr8_device::op_reti(uint16_t op) +{ + m_pc = pop() << 8; + m_pc |= pop(); + m_pc--; + SREG_W(AVR8_SREG_I, 1); +} + +void avr8_device::op_sleep(uint16_t op) +{ + m_pc--; +} + +void avr8_device::op_break(uint16_t op) +{ + op_unimpl(op); +} + +void avr8_device::op_wdr(uint16_t op) +{ + LOGMASKED(LOG_WDOG, "%s: Watchdog reset opcode\n", machine().describe_context()); + op_unimpl(op); +} + +void avr8_device::op_lpm(uint16_t op) +{ + m_r[0] = m_program->read_byte(ZREG); +} + +void avr8_device::op_elpm(uint16_t op) +{ + op_unimpl(op); +} + +void avr8_device::op_spm(uint16_t op) +{ + op_unimpl(op); +} + +void avr8_device::op_spmzi(uint16_t op) +{ + op_unimpl(op); +} + +void avr8_device::op_icall(uint16_t op) +{ + push((m_pc + 1) & 0x00ff); + push(((m_pc + 1) >> 8) & 0x00ff); + m_pc = ZREG; + m_pc--; +} + +void avr8_device::op_eicall(uint16_t op) +{ + op_unimpl(op); +} + +void avr8_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); + 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; +} + +void avr8_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); + 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; +} + +void avr8_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_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_shifted_pc + 2); + m_opcycles += is_long_opcode(data) ? 2 : 1; + m_pc += is_long_opcode(data) ? 2 : 1; + } +} + +void avr8_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_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_shifted_pc + 2); + m_opcycles += is_long_opcode(data) ? 2 : 1; + m_pc += is_long_opcode(data) ? 2 : 1; + } +} + +void avr8_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; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); +} + +void avr8_device::op_out(uint16_t op) +{ + m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]); +} + +void avr8_device::op_in(uint16_t op) +{ + m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op)); +} + +void avr8_device::op_rjmp(uint16_t op) +{ + m_pc += (int32_t)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); +} + +void avr8_device::op_rcall(uint16_t op) +{ + const int32_t offs = (int32_t)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); + push((m_pc + 1) & 0x00ff); + push(((m_pc + 1) >> 8) & 0x00ff); + m_pc += offs; +} + +void avr8_device::op_ldi(uint16_t op) +{ + m_r[16 + RD4(op)] = KCONST8(op); +} + +void avr8_device::op_brset(uint16_t op) +{ + if (SREG_R(op & 0x0007)) + { + m_pc += (((int32_t)(KCONST7(op)) << 25) >> 25); + m_opcycles++; + } +} + +void avr8_device::op_brclr(uint16_t op) +{ + if (SREG_R(op & 0x0007) == 0) + { + m_pc += (((int32_t)(KCONST7(op)) << 25) >> 25); + m_opcycles++; + } +} + +void avr8_device::op_bst(uint16_t op) +{ + SREG_W(AVR8_SREG_T, (BIT(m_r[RD5(op)], RR3(op))) ? 1 : 0); +} + +void avr8_device::op_bld(uint16_t op) +{ + if (SREG_R(AVR8_SREG_T)) + { + m_r[RD5(op)] |= (1 << RR3(op)); + } + else + { + m_r[RD5(op)] &= ~(1 << RR3(op)); + } +} + +void avr8_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_shifted_pc + 2); + m_opcycles += is_long_opcode(data) ? 2 : 1; + m_pc += is_long_opcode(data) ? 2 : 1; + } +} + +void avr8_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_shifted_pc + 2); + m_opcycles += is_long_opcode(data) ? 2 : 1; + m_pc += is_long_opcode(data) ? 2 : 1; + } +} + +void avr8_device::op_unimpl(uint16_t op) +{ + unimplemented_opcode(op); +} diff --git a/src/mame/drivers/craft.cpp b/src/mame/drivers/craft.cpp index 973de68b04d..d13abd1981e 100644 --- a/src/mame/drivers/craft.cpp +++ b/src/mame/drivers/craft.cpp @@ -11,6 +11,7 @@ #include "sound/dac.h" #include "sound/volt_reg.h" #include "screen.h" +#include "emupal.h" #include "speaker.h" #define MASTER_CLOCK 20000000 @@ -31,6 +32,7 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_screen(*this, "screen") + , m_palette(*this, "palette") , m_dac(*this, "dac") { } @@ -48,11 +50,13 @@ private: DECLARE_READ8_MEMBER(port_r); DECLARE_WRITE8_MEMBER(port_w); + void init_palette(palette_device &palette) const; void video_update(); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); required_device<avr8_device> m_maincpu; required_device<screen_device> m_screen; + required_device<palette_device> m_palette; required_device<dac_byte_interface> m_dac; uint32_t m_last_cycles; @@ -149,6 +153,17 @@ void craft_state::craft_io_map(address_map &map) // VIDEO //************************************************************************** +void craft_state::init_palette(palette_device &palette) const +{ + for (int i = 0; i < 0x40; i++) + { + uint8_t r = 0x55 * ((i & 0x30) >> 4); + uint8_t g = 0x55 * ((i & 0x0c) >> 2); + uint8_t b = 0x55 * (i & 0x03); + palette.set_pen_color(i, rgb_t(r, g, b)); + } +} + void craft_state::video_update() { uint64_t cycles = machine().time().as_ticks(MASTER_CLOCK); @@ -182,16 +197,14 @@ void craft_state::video_update() uint32_t craft_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { + const pen_t *pens = m_palette->pens(); for(int y = 0; y < LINES_PER_FRAME; y++) { - uint32_t *line = &bitmap.pix32(y); + uint32_t *dst = &bitmap.pix32(y); + uint8_t *src = &m_pixels[y * LINE_CYCLES]; for(int x = 0; x < LINE_CYCLES; x++) { - uint8_t pixel = m_pixels[y * LINE_CYCLES + x]; - uint8_t r = 0x55 * ((pixel & 0x30) >> 4); - uint8_t g = 0x55 * ((pixel & 0x0c) >> 2); - uint8_t b = 0x55 * (pixel & 0x03); - line[x] = 0xff000000 | (r << 16) | (g << 8) | b; + *dst++ = pens[*src++]; } } return 0; @@ -246,6 +259,8 @@ void craft_state::craft(machine_config &config) m_screen->set_raw(MASTER_CLOCK, 635, 47, 527, 525, 36, 516); m_screen->set_screen_update(FUNC(craft_state::screen_update)); + PALETTE(config, m_palette, FUNC(craft_state::init_palette), 64); + /* sound hardware */ SPEAKER(config, "avr8").front_center(); DAC_6BIT_R2R(config, "dac", 0).add_route(0, "avr8", 0.25); // pd1/pd2/pd4/pd5/pd6/pd7 + 2k(x7) + 1k(x5) |