summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatarGravatar Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-07-14 07:26:41 +0200
committerGravatarGravatar Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-07-14 07:27:28 +0200
commite04f490e4b0a7bc5ed9c212663facaf8195c96f4 (patch)
tree6d21ead0db392df77748f245157a4434dd3d4770
parent735752cea8c83134f3dc0046af2457d3305442ce (diff)
downloadmame-e04f490e4b0a7bc5ed9c212663facaf8195c96f4.tar.xz
mame-e04f490e4b0a7bc5ed9c212663facaf8195c96f4.zip
-avr8: Fixed assorted Timer 0 and Timer 1 bugs. [Ryan Holtz]
-avr8dasm: Fixed erroneous disassembly of CBI, SBI, SBIS, and SBIC opcodes. [Ryan Holtz] New working machines -------------------- Power Ninja Action Challenge [Ryan Holtz]
-rw-r--r--src/devices/cpu/avr8/avr8.cpp134
-rw-r--r--src/devices/cpu/avr8/avr8dasm.cpp1027
-rw-r--r--src/mame/drivers/craft.cpp246
-rw-r--r--src/mame/mame.lst1
4 files changed, 740 insertions, 668 deletions
diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp
index 69096da7059..013ac8db6f6 100644
--- a/src/devices/cpu/avr8/avr8.cpp
+++ b/src/devices/cpu/avr8/avr8.cpp
@@ -92,7 +92,7 @@
#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_TIMER_TICKS | 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)
+ | LOG_OSC | LOG_PINCHG | LOG_EXTMEM | LOG_ADC | LOG_DIGINPUT | LOG_ASYNC | LOG_TWI | LOG_UART)
#define VERBOSE (0)
#include "logmacro.h"
@@ -870,6 +870,7 @@ void avr8_device::device_start()
// Misc.
save_item(NAME(m_addr_mask));
save_item(NAME(m_interrupt_pending));
+ save_item(NAME(m_opcycles));
// set our instruction counter
set_icountptr(m_icount);
@@ -1040,7 +1041,6 @@ inline uint8_t avr8_device::pop()
void avr8_device::set_irq_line(uint16_t vector, int state)
{
- // Horrible hack, not accurate
if (state)
{
if (SREG_R(AVR8_SREG_I))
@@ -1058,17 +1058,16 @@ void avr8_device::set_irq_line(uint16_t vector, int state)
}
}
-class CInterruptCondition
+struct interrupt_condition
{
- public:
- uint8_t m_intindex;
- uint8_t m_intreg;
- uint8_t m_intmask;
- uint8_t m_regindex;
- uint8_t m_regmask;
+ uint8_t m_intindex;
+ uint8_t m_intreg;
+ uint8_t m_intmask;
+ uint8_t m_regindex;
+ uint8_t m_regmask;
};
-static const CInterruptCondition s_int_conditions[AVR8_INTIDX_COUNT] =
+static const interrupt_condition 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 },
@@ -1085,7 +1084,7 @@ static const CInterruptCondition s_int_conditions[AVR8_INTIDX_COUNT] =
void avr8_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)
@@ -1101,7 +1100,7 @@ void avr8_device::update_interrupt(int source)
void atmega328_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)
@@ -1115,7 +1114,7 @@ void atmega328_device::update_interrupt(int source)
}
}
-static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
+static const interrupt_condition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
{
{ ATMEGA644_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK },
{ ATMEGA644_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK },
@@ -1132,7 +1131,7 @@ static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
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)
@@ -1149,7 +1148,7 @@ 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)
@@ -1166,7 +1165,7 @@ 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)
@@ -1224,20 +1223,17 @@ void avr8_device::timer_tick()
}
}
-// 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 };
-
-#define LOG_TIMER_0 0
-#define LOG_TIMER_5 0
// Timer 0 Handling
void avr8_device::timer0_tick()
{
+ static const uint8_t s_ocf0[2] = { (1 << AVR8_TIFR0_OCF0A_SHIFT), (1 << AVR8_TIFR0_OCF0B_SHIFT) };
+ static const uint8_t s_int0[2] = { AVR8_INTIDX_OCF0A, AVR8_INTIDX_OCF0B };
+
LOGMASKED(LOG_TIMER0_TICK, "%s: AVR8_WGM0: %d\n", machine().describe_context(), AVR8_WGM0);
LOGMASKED(LOG_TIMER0_TICK, "%s: AVR8_TCCR0A_COM0B: %d\n", machine().describe_context(), AVR8_TCCR0A_COM0B);
uint8_t count = m_r[AVR8_REGIDX_TCNT0];
- int32_t increment = m_timer_increment[0];
+ count++;
switch (AVR8_WGM0)
{
@@ -1253,10 +1249,16 @@ void avr8_device::timer0_tick()
switch (AVR8_TCCR0A_COM0B)
{
case 0: /* Normal Operation */
- if (count == m_timer_top[0])
+ if (count == AVR8_OCR0A)
{
- LOGMASKED(LOG_TIMER0, "%s: timer0: Set normal OC0B behavior\n", machine().describe_context());
- m_timer_top[0] = 0;
+ m_r[AVR8_REGIDX_TIFR0] |= s_ocf0[AVR8_REG_A];
+ update_interrupt(s_int0[AVR8_REG_A]);
+ count = 0;
+ }
+ else if (count == AVR8_OCR0B)
+ {
+ m_r[AVR8_REGIDX_TIFR0] |= s_ocf0[AVR8_REG_B];
+ update_interrupt(s_int0[AVR8_REG_B]);
}
break;
@@ -1290,26 +1292,23 @@ void avr8_device::timer0_tick()
break;
case WGM02_FAST_PWM:
- LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
- break;
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ break;
case WGM02_PWM_PC_CMP:
- LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_PWM_PC_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
- break;
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_PWM_PC_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ break;
case WGM02_FAST_PWM_CMP:
- LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
- break;
+ LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: WGM02_FAST_PWM_CMP: Unimplemented timer0 waveform generation mode\n", machine().describe_context());
+ break;
default:
LOGMASKED(LOG_TIMER0 | LOG_UNKNOWN, "%s: update_timer0_compare_mode: Unknown waveform generation mode: %02x\n", machine().describe_context(), AVR8_WGM0);
break;
}
- count = count & 0xff;
-
- count += increment;
- m_r[AVR8_REGIDX_TCNT0] = count & 0xff;
+ m_r[AVR8_REGIDX_TCNT0] = count;
}
void avr8_device::changed_tccr0a(uint8_t data)
@@ -1379,11 +1378,15 @@ inline void avr8_device::timer1_tick()
static const uint8_t s_int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B };
int32_t increment = m_timer_increment[1];
+ LOGMASKED(LOG_TIMER1_TICK, "%s: AVR8_WGM1: %d\n", machine().describe_context(), AVR8_WGM1);
+
for (int32_t reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++)
{
switch (m_wgm1)
{
case WGM1_CTC_OCR:
+ LOGMASKED(LOG_TIMER1_TICK, "%s: timer1_count: %04x\n", machine().describe_context(), m_timer1_count);
+ LOGMASKED(LOG_TIMER1_TICK, "%s: OCR1%c: %04x\n", machine().describe_context(), reg ? 'A' : 'B', m_ocr1[reg]);
if (m_timer1_count == 0xffff)
{
m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK;
@@ -1409,9 +1412,6 @@ inline void avr8_device::timer1_tick()
m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK;
update_interrupt(AVR8_INTIDX_TOV1);
}
-
- m_r[AVR8_REGIDX_TIFR1] &= ~s_ocf1[reg];
- update_interrupt(s_int1[reg]);
}
break;
@@ -1882,7 +1882,7 @@ void avr8_device::update_timer_clock_source(uint8_t t, uint8_t clock_select)
};
m_timer_prescale[t] = s_prescale_values[(t == 2) ? 1 : 0][clock_select];
- LOGMASKED((LOG_TIMER0 + t), "%s: update_timer_clock_source: t = %d, cs = %d\n", t, machine().describe_context(), clock_select);
+ LOGMASKED((LOG_TIMER0 + t), "%s: update_timer_clock_source: t = %d, cs = %d\n", machine().describe_context(), t, clock_select);
if (m_timer_prescale[t] == 0xffff)
{
@@ -2250,56 +2250,67 @@ void avr8_device::regs_w(offs_t offset, uint8_t data)
break;
case AVR8_REGIDX_PORTA:
+ LOGMASKED(LOG_GPIO, "%s: PORTA Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTA, data);
m_r[AVR8_REGIDX_PORTA] = data;
break;
case AVR8_REGIDX_PORTB:
+ LOGMASKED(LOG_GPIO, "%s: PORTB Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTB, data);
m_r[AVR8_REGIDX_PORTB] = data;
break;
case AVR8_REGIDX_PORTC:
+ LOGMASKED(LOG_GPIO, "%s: PORTC Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTC, data);
m_r[AVR8_REGIDX_PORTC] = data;
break;
case AVR8_REGIDX_PORTD:
+ LOGMASKED(LOG_GPIO, "%s: PORTD Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTD, data);
m_r[AVR8_REGIDX_PORTD] = data;
break;
case AVR8_REGIDX_PORTE:
+ LOGMASKED(LOG_GPIO, "%s: PORTE Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTE, data);
m_r[AVR8_REGIDX_PORTE] = data;
break;
case AVR8_REGIDX_PORTF:
+ LOGMASKED(LOG_GPIO, "%s: PORTF Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTF, data);
m_r[AVR8_REGIDX_PORTF] = data;
break;
case AVR8_REGIDX_PORTG:
+ LOGMASKED(LOG_GPIO, "%s: PORTG Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTG, data);
m_r[AVR8_REGIDX_PORTG] = data;
break;
case AVR8_REGIDX_PORTH:
+ LOGMASKED(LOG_GPIO, "%s: PORTH Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTH, data);
m_r[AVR8_REGIDX_PORTH] = data;
break;
case AVR8_REGIDX_PORTJ:
+ LOGMASKED(LOG_GPIO, "%s: PORTJ Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTJ, data);
m_r[AVR8_REGIDX_PORTJ] = data;
break;
case AVR8_REGIDX_PORTK:
+ LOGMASKED(LOG_GPIO, "%s: PORTK Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTK, data);
m_r[AVR8_REGIDX_PORTK] = data;
break;
case AVR8_REGIDX_PORTL:
+ LOGMASKED(LOG_GPIO, "%s: PORTL Write: %02x\n", machine().describe_context(), data);
m_io->write_byte(AVR8_IO_PORTL, data);
m_r[AVR8_REGIDX_PORTL] = data;
break;
@@ -2327,12 +2338,12 @@ void avr8_device::regs_w(offs_t offset, uint8_t data)
case AVR8_REGIDX_OCR0A:
LOGMASKED(LOG_TIMER0, "%s: OCR0A = %02x\n", machine().describe_context(), data);
- update_ocr0(AVR8_OCR0A, AVR8_REG_A);
+ update_ocr0(data, AVR8_REG_A);
break;
case AVR8_REGIDX_OCR0B:
LOGMASKED(LOG_TIMER0, "%s: OCR0B = %02x\n", machine().describe_context(), data);
- update_ocr0(AVR8_OCR0B, AVR8_REG_B);
+ update_ocr0(data, AVR8_REG_B);
break;
case AVR8_REGIDX_TIFR0:
@@ -2408,7 +2419,12 @@ void avr8_device::regs_w(offs_t offset, uint8_t data)
break;
case AVR8_REGIDX_GPIOR1:
+ LOGMASKED(LOG_GPIO, "%s: GPIOR1 Write: %02x\n", machine().describe_context(), data);
+ m_r[offset] = data;
+ break;
+
case AVR8_REGIDX_GPIOR2:
+ LOGMASKED(LOG_GPIO, "%s: GPIOR2 Write: %02x\n", machine().describe_context(), data);
m_r[offset] = data;
break;
@@ -2813,6 +2829,8 @@ void avr8_device::regs_w(offs_t offset, uint8_t data)
uint8_t avr8_device::regs_r(offs_t offset)
{
+ uint8_t data = m_r[offset];
+
switch (offset)
{
case AVR8_REGIDX_R0:
@@ -2847,7 +2865,7 @@ uint8_t avr8_device::regs_r(offs_t offset)
case AVR8_REGIDX_R29:
case AVR8_REGIDX_R30:
case AVR8_REGIDX_R31:
- return m_r[offset];
+ return data;
case AVR8_REGIDX_PINA:
// TODO: account for DDRA
@@ -2904,7 +2922,7 @@ uint8_t avr8_device::regs_r(offs_t offset)
case AVR8_REGIDX_PORTJ:
case AVR8_REGIDX_PORTK:
case AVR8_REGIDX_PORTL:
- return m_r[offset];
+ return data;
case AVR8_REGIDX_DDRA:
case AVR8_REGIDX_DDRB:
@@ -2917,19 +2935,25 @@ uint8_t avr8_device::regs_r(offs_t offset)
case AVR8_REGIDX_DDRJ:
case AVR8_REGIDX_DDRK:
case AVR8_REGIDX_DDRL:
- return m_r[offset];
+ return data;
// EEPROM registers
case AVR8_REGIDX_EECR:
case AVR8_REGIDX_EEDR:
- return m_r[offset];
+ return data;
// Miscellaneous registers
// TODO: Implement readback for all applicable registers.
case AVR8_REGIDX_GPIOR0:
+ LOGMASKED(LOG_GPIO, "%s: GPIOR0 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_GPIOR1:
+ LOGMASKED(LOG_GPIO, "%s: GPIOR1 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_GPIOR2:
+ LOGMASKED(LOG_GPIO, "%s: GPIOR2 Read: %02x\n", machine().describe_context(), data);
+ return data;
// 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
@@ -2939,12 +2963,26 @@ uint8_t avr8_device::regs_r(offs_t offset)
case AVR8_REGIDX_SPH:
case AVR8_REGIDX_SREG:
case AVR8_REGIDX_TIMSK0:
+ LOGMASKED(LOG_TIMER0, "%s: TIMSK0 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_TIMSK1:
+ LOGMASKED(LOG_TIMER1, "%s: TIMSK1 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_TIMSK2:
-// case AVR8_REGIDX_TIMSK3: // TODO: needed for Replicator 1
+ LOGMASKED(LOG_TIMER2, "%s: TIMSK2 Read: %02x\n", machine().describe_context(), data);
+ return data;
+ case AVR8_REGIDX_TIMSK3:
+ LOGMASKED(LOG_TIMER3, "%s: TIMSK3 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_TIMSK4:
+ LOGMASKED(LOG_TIMER4, "%s: TIMSK4 Read: %02x\n", machine().describe_context(), data);
+ return data;
case AVR8_REGIDX_TIMSK5:
- return m_r[offset];
+ LOGMASKED(LOG_TIMER5, "%s: TIMSK5 Read: %02x\n", machine().describe_context(), data);
+ return data;
+ case AVR8_REGIDX_TIFR1:
+ //LOGMASKED(LOG_TIMER0, "%s: TIFR1 Read: %02x\n", machine().describe_context(), data);
+ return data;
// Two-wire registers
case AVR8_REGIDX_TWCR:
diff --git a/src/devices/cpu/avr8/avr8dasm.cpp b/src/devices/cpu/avr8/avr8dasm.cpp
index 5f47198c425..3fed61c55fa 100644
--- a/src/devices/cpu/avr8/avr8dasm.cpp
+++ b/src/devices/cpu/avr8/avr8dasm.cpp
@@ -106,572 +106,539 @@ offs_t avr8_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat
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));
+ 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);
+ 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");
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");
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");
+ 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 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)]);
+ 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)]);
+ 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));
+ 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;
+ }
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;
}
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;
+ }
+ break;
}
return (pc - base_pc) | SUPPORTED;
diff --git a/src/mame/drivers/craft.cpp b/src/mame/drivers/craft.cpp
index 81bd2b7eed9..3481f58d231 100644
--- a/src/mame/drivers/craft.cpp
+++ b/src/mame/drivers/craft.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Ryan Holtz
/**********************************************************************
- "Craft" demo platform by Linus Akesson
+ ATmega88-based demo platforms by Linus Åkesson
**********************************************************************/
@@ -14,8 +14,6 @@
#include "emupal.h"
#include "speaker.h"
-#define MASTER_CLOCK 20000000
-
#define VISIBLE_CYCLES 480
#define HSYNC_CYCLES 155
#define LINE_CYCLES (VISIBLE_CYCLES + HSYNC_CYCLES)
@@ -25,15 +23,72 @@
#define CYCLES_PER_FRAME (LINES_PER_FRAME * LINE_CYCLES)
#define PIXELS_PER_FRAME (CYCLES_PER_FRAME)
-class craft_state : public driver_device
+class lft_state : public driver_device
{
public:
- craft_state(const machine_config &mconfig, device_type type, const char *tag)
+ lft_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
+ , m_dac(*this, "dac")
+ {
+ }
+
+ void base_config(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ virtual uint32_t master_clock() const = 0;
+
+ void prg_map(address_map &map);
+ void data_map(address_map &map);
+ void io_map(address_map &map);
+
+ uint8_t port_r(offs_t offset);
+ void port_w(offs_t offset, uint8_t data);
+
+ virtual void port_update(const offs_t offset, const uint8_t old, const uint8_t data) = 0;
+
+ required_device<avr8_device> m_maincpu;
+ required_device<dac_byte_interface> m_dac;
+
+ enum port : uint8_t
+ {
+ PORT_A,
+ PORT_B,
+ PORT_C,
+ PORT_D,
+
+ PORT_COUNT
+ };
+
+ uint8_t m_ports[PORT_COUNT];
+};
+
+class powernin_state : public lft_state
+{
+public:
+ powernin_state(const machine_config &mconfig, device_type type, const char *tag)
+ : lft_state(mconfig, type, tag)
+ {
+ }
+
+ void powernin(machine_config &config);
+
+private:
+ virtual uint32_t master_clock() const override { return 8000000; }
+
+ virtual void port_update(const offs_t offset, const uint8_t old, const uint8_t data) override;
+};
+
+class craft_state : public lft_state
+{
+public:
+ craft_state(const machine_config &mconfig, device_type type, const char *tag)
+ : lft_state(mconfig, type, tag)
, m_screen(*this, "screen")
, m_palette(*this, "palette")
- , m_dac(*this, "dac")
{
}
@@ -43,29 +98,20 @@ private:
virtual void machine_start() override;
virtual void machine_reset() override;
- void craft_prg_map(address_map &map);
- void craft_data_map(address_map &map);
- void craft_io_map(address_map &map);
+ virtual uint32_t master_clock() const override { return 20000000; }
- uint8_t port_r(offs_t offset);
- void port_w(offs_t offset, uint8_t data);
+ virtual void port_update(const offs_t offset, const uint8_t old, const uint8_t data) override;
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;
uint64_t m_frame_start_cycle;
- uint8_t m_port_b;
- uint8_t m_port_c;
- uint8_t m_port_d;
-
uint8_t m_latched_color;
std::unique_ptr<uint8_t[]> m_pixels;
};
@@ -74,79 +120,73 @@ private:
// GPIO
//**************************************************************************
-uint8_t craft_state::port_r(offs_t offset)
+uint8_t lft_state::port_r(offs_t offset)
{
- switch (offset)
- {
- case 0x00: // Port A
- break;
- case 0x01: // Port B
- return m_port_b;
- case 0x02: // Port C
- return m_port_c;
- case 0x03: // Port D
- return m_port_d;
- }
+ return m_ports[offset];
+}
- return 0;
+void lft_state::port_w(offs_t offset, uint8_t data)
+{
+ const uint8_t old = m_ports[offset];
+ m_ports[offset] = data;
+ port_update(offset, old, data);
}
-void craft_state::port_w(offs_t offset, uint8_t data)
+void craft_state::port_update(const offs_t offset, const uint8_t old, const uint8_t data)
{
+ const uint8_t changed = data ^ old;
switch (offset)
{
- case AVR8_IO_PORTA:
- break;
+ case AVR8_IO_PORTA:
+ break;
- case AVR8_IO_PORTB:
+ case AVR8_IO_PORTB:
+ if (BIT(changed, 1) && BIT(data, 1))
{
- uint8_t old_port_b = m_port_b;
- uint8_t pins = data;
- uint8_t changed = pins ^ old_port_b;
- if (BIT(changed, 1) && BIT(data, 1))
- {
- m_frame_start_cycle = machine().time().as_ticks(MASTER_CLOCK);
- video_update();
- }
- if (BIT(changed, 3))
- {
- video_update();
- m_latched_color = (pins & 0x08) ? (m_port_c & 0x3f) : 0x3f;
- }
- m_port_b = data;
- break;
+ m_frame_start_cycle = machine().time().as_ticks(master_clock());
+ video_update();
}
-
- case AVR8_IO_PORTC:
+ if (BIT(changed, 3))
+ {
video_update();
- m_port_c = data;
- m_latched_color = m_port_c;
- break;
-
- case AVR8_IO_PORTD:
- m_port_d = data;
- m_dac->write((data & 0x02) | ((data & 0xf4) >> 2));
- break;
+ m_latched_color = (data & 0x08) ? (m_ports[PORT_C] & 0x3f) : 0x3f;
+ }
+ break;
+
+ case AVR8_IO_PORTC:
+ video_update();
+ m_latched_color = data;
+ break;
+
+ case AVR8_IO_PORTD:
+ m_dac->write((data & 0x02) | ((data & 0xf4) >> 2));
+ break;
}
}
+void powernin_state::port_update(const offs_t offset, const uint8_t old, const uint8_t data)
+{
+ if (offset == AVR8_IO_PORTD)
+ m_dac->write(data);
+}
+
//**************************************************************************
// MEMORY
//**************************************************************************
-void craft_state::craft_prg_map(address_map &map)
+void lft_state::prg_map(address_map &map)
{
map(0x0000, 0x1fff).rom();
}
-void craft_state::craft_data_map(address_map &map)
+void lft_state::data_map(address_map &map)
{
map(0x0100, 0x04ff).ram();
}
-void craft_state::craft_io_map(address_map &map)
+void lft_state::io_map(address_map &map)
{
- map(AVR8_IO_PORTA, AVR8_IO_PORTD).rw(FUNC(craft_state::port_r), FUNC(craft_state::port_w));
+ map(AVR8_IO_PORTA, AVR8_IO_PORTD).rw(FUNC(lft_state::port_r), FUNC(lft_state::port_w));
}
//**************************************************************************
@@ -166,7 +206,7 @@ void craft_state::init_palette(palette_device &palette) const
void craft_state::video_update()
{
- uint64_t cycles = machine().time().as_ticks(MASTER_CLOCK);
+ uint64_t cycles = machine().time().as_ticks(master_clock());
uint32_t frame_cycles = (uint32_t)(cycles - m_frame_start_cycle);
if (m_last_cycles < frame_cycles)
@@ -214,67 +254,93 @@ uint32_t craft_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
// MACHINE
//**************************************************************************
-static INPUT_PORTS_START( craft )
+static INPUT_PORTS_START( empty_input )
INPUT_PORTS_END
+void lft_state::machine_start()
+{
+ save_item(NAME(m_ports));
+}
+
+void lft_state::machine_reset()
+{
+ memset(m_ports, 0, PORT_COUNT);
+}
+
void craft_state::machine_start()
{
+ lft_state::machine_start();
+
m_pixels = std::make_unique<uint8_t[]>(PIXELS_PER_FRAME);
save_item(NAME(m_last_cycles));
save_item(NAME(m_frame_start_cycle));
- save_item(NAME(m_port_b));
- save_item(NAME(m_port_c));
- save_item(NAME(m_port_d));
-
save_item(NAME(m_latched_color));
save_pointer(NAME(m_pixels), PIXELS_PER_FRAME);
}
void craft_state::machine_reset()
{
+ lft_state::machine_reset();
+
m_frame_start_cycle = 0;
m_last_cycles = 0;
- m_port_b = 0;
- m_port_c = 0;
- m_port_d = 0;
-
m_latched_color = 0;
memset(&m_pixels[0], 0, PIXELS_PER_FRAME);
}
-void craft_state::craft(machine_config &config)
+void lft_state::base_config(machine_config &config)
{
/* basic machine hardware */
- ATMEGA88(config, m_maincpu, MASTER_CLOCK);
- m_maincpu->set_addrmap(AS_PROGRAM, &craft_state::craft_prg_map);
- m_maincpu->set_addrmap(AS_DATA, &craft_state::craft_data_map);
- m_maincpu->set_addrmap(AS_IO, &craft_state::craft_io_map);
+ ATMEGA88(config, m_maincpu, master_clock());
+ m_maincpu->set_addrmap(AS_PROGRAM, &lft_state::prg_map);
+ m_maincpu->set_addrmap(AS_DATA, &lft_state::data_map);
+ m_maincpu->set_addrmap(AS_IO, &lft_state::io_map);
m_maincpu->set_eeprom_tag("eeprom");
- /* video hardware */
+ /* sound hardware */
+ SPEAKER(config, "avr8").front_center();
+ voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref", 0));
+ vref.add_route(0, m_dac, 1.0, DAC_VREF_POS_INPUT);
+ vref.add_route(0, m_dac, -1.0, DAC_VREF_NEG_INPUT);
+}
+
+void craft_state::craft(machine_config &config)
+{
+ base_config(config);
+
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
- m_screen->set_raw(MASTER_CLOCK, 635, 47, 527, 525, 36, 516);
+ 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)
- voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref", 0));
- vref.add_route(0, "dac", 1.0, DAC_VREF_POS_INPUT);
- vref.add_route(0, "dac", -1.0, DAC_VREF_NEG_INPUT);
+ DAC_6BIT_R2R(config, m_dac, 0).add_route(0, "avr8", 0.25); // pd1/pd2/pd4/pd5/pd6/pd7 + 2k(x7) + 1k(x5)
+}
+
+void powernin_state::powernin(machine_config &config)
+{
+ base_config(config);
+
+ DAC_8BIT_R2R(config, m_dac, 0).add_route(0, "avr8", 0.9);
}
ROM_START( craft )
- ROM_REGION( 0x2000, "maincpu", 0 ) /* Main program store */
+ ROM_REGION( 0x2000, "maincpu", 0 )
ROM_LOAD( "craft.bin", 0x0000, 0x2000, CRC(2e6f9ad2) SHA1(75e495bf18395d74289ca7ee2649622fc4010457) )
- ROM_REGION( 0x200, "eeprom", 0 ) /* on-die eeprom */
+ ROM_REGION( 0x200, "eeprom", 0 )
ROM_LOAD( "eeprom.raw", 0x0000, 0x0200, CRC(e18a2af9) SHA1(81fc6f2d391edfd3244870214fac37929af0ac0c) )
ROM_END
-/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
-CONS(2008, craft, 0, 0, craft, craft, craft_state, empty_init, "Linus Akesson", "Craft", MACHINE_IMPERFECT_GRAPHICS)
+ROM_START( powernin )
+ ROM_REGION( 0x2000, "maincpu", 0 )
+ ROM_LOAD( "powernin.bin", 0x0000, 0x2000, CRC(67458936) SHA1(26a86846a24dd974723a66bea6c22baf51c7bec9) )
+ ROM_REGION( 0x200, "eeprom", 0 )
+ ROM_LOAD( "eeprom.raw", 0x0000, 0x0200, CRC(bd7bc39f) SHA1(9d0ac37bb3ec8c95990fd37a962a17a95ce97aa0) )
+ROM_END
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
+CONS(2008, craft, 0, 0, craft, empty_input, craft_state, empty_init, "Linus Åkesson", "Craft", MACHINE_IMPERFECT_GRAPHICS)
+CONS(2009, powernin, 0, 0, powernin, empty_input, powernin_state, empty_init, "Linus Åkesson", "Power Ninja Action Challenge", 0)
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index ae8a7de2392..0c6e81ff4ef 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -11263,6 +11263,7 @@ cpzodiacj //
@source:craft.cpp
craft // Craft, by [lft]
+powernin // Power Ninja Action Challenge, by [lft]
@source:crazybal.cpp
crazybal // EGS