diff options
Diffstat (limited to 'trunk/src/emu/cpu/avr8/avr8.c')
-rw-r--r-- | trunk/src/emu/cpu/avr8/avr8.c | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/avr8/avr8.c b/trunk/src/emu/cpu/avr8/avr8.c new file mode 100644 index 00000000000..045a46c9d00 --- /dev/null +++ b/trunk/src/emu/cpu/avr8/avr8.c @@ -0,0 +1,1205 @@ +/* + Atmel 8-bit AVR emulator + + (Skeleton) + + DONE: + - Disassembler + - [lft]'s "Craft" depends on on-chip device support now instead of opcodes (it requires unusually few in order to boot) + + TODO: + - Everything else + * Finish opcode implementation + * Add proper cycle timing + * Add Interrupts + * Add on-chip hardware (machine driver) + + Written by MooglyGuy +*/ + +#include "emu.h" +#include "debugger.h" +#include "avr8.h" + +typedef struct _avr8_state avr8_state; +struct _avr8_state +{ + UINT32 pc; + + legacy_cpu_device *device; + address_space *program; + address_space *io; + int icount; + UINT32 addr_mask; +}; + +enum +{ + AVR8_SREG_C = 0, + AVR8_SREG_Z, + AVR8_SREG_N, + AVR8_SREG_V, + AVR8_SREG_S, + AVR8_SREG_H, + AVR8_SREG_T, + AVR8_SREG_I, +}; + +enum +{ + AVR8_IO_SPL = 0x5d, + AVR8_IO_SPH = 0x5e, + AVR8_IO_SREG = 0x5f, +}; + +#define SREG_R(b) ((READ_IO_8(cpustate, AVR8_IO_SREG) & (1 << (b))) >> (b)) +#define SREG_W(b,v) WRITE_IO_8(cpustate, AVR8_IO_SREG, (READ_IO_8(cpustate, AVR8_IO_SREG) &~ (1 << (b))) | (((v) ? 1 : 0) << (b))) +#define NOT(x) (1 - (x)) + +#define RD2(op) (((op) >> 4) & 0x0003) +#define RD3(op) (((op) >> 4) & 0x0007) +#define RD4(op) (((op) >> 4) & 0x000f) +#define RD5(op) (((op) >> 4) & 0x001f) +#define RR3(op) ((op) & 0x0007) +#define RR4(op) ((op) & 0x000f) +#define RR5(op) ((((op) >> 5) & 0x0010) | ((op) & 0x000f)) +#define KCONST6(op) ((((op) >> 2) & 0x0030) | ((op) & 0x000f)) +#define KCONST7(op) (((op) >> 3) & 0x007f) +#define KCONST8(op) ((((op) >> 4) & 0x00f0) | ((op) & 0x000f)) +#define KCONST22(op) (((((UINT32)(op) >> 3) & 0x003e) | ((UINT32)(op) & 0x0001)) << 16) +#define QCONST6(op) ((((op) >> 8) & 0x0020) | (((op) >> 7) & 0x0018) | ((op) & 0x0007)) +#define ACONST5(op) (((op) >> 3) & 0x001f) +#define ACONST6(op) ((((op) >> 5) & 0x0030) | ((op) & 0x000f)) + +#define XREG ((READ_IO_8(cpustate, 27) << 8) | READ_IO_8(cpustate, 26)) +#define YREG ((READ_IO_8(cpustate, 29) << 8) | READ_IO_8(cpustate, 28)) +#define ZREG ((READ_IO_8(cpustate, 31) << 8) | READ_IO_8(cpustate, 30)) +#define SPREG ((READ_IO_8(cpustate, AVR8_IO_SPH) << 8) | READ_IO_8(cpustate, AVR8_IO_SPL)) + +INLINE avr8_state *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == ATMEGA88 || device->type() == ATMEGA644); + return (avr8_state *)downcast<legacy_cpu_device *>(device)->token(); +} + +/*****************************************************************************/ + +static void unimplemented_opcode(avr8_state *cpustate, UINT32 op) +{ + fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, cpustate->pc); +} + +/*****************************************************************************/ + +INLINE bool avr8_is_long_opcode(UINT16 op) +{ + if((op & 0xf000) == 0x9000) + { + if((op & 0x0f00) < 0x0400) + { + if((op & 0x000f) == 0x0000) + { + return true; + } + } + else if((op & 0x0f00) < 0x0600) + { + if((op & 0x000f) >= 0x000c) + { + return true; + } + } + } + return false; +} + +INLINE UINT8 READ_PRG_8(avr8_state *cpustate, UINT32 address) +{ + return cpustate->program->read_byte(address); +} + +INLINE UINT16 READ_PRG_16(avr8_state *cpustate, UINT32 address) +{ + return cpustate->program->read_word(address << 1); +} + +INLINE void WRITE_PRG_8(avr8_state *cpustate, UINT32 address, UINT8 data) +{ + cpustate->program->write_byte(address, data); +} + +INLINE void WRITE_PRG_16(avr8_state *cpustate, UINT32 address, UINT16 data) +{ + cpustate->program->write_word(address, data); +} + +INLINE UINT8 READ_IO_8(avr8_state *cpustate, UINT16 address) +{ + return cpustate->io->read_byte(address); +} + +INLINE void WRITE_IO_8(avr8_state *cpustate, UINT16 address, UINT8 data) +{ + cpustate->io->write_byte(address, data); +} + +INLINE void PUSH(avr8_state *cpustate, UINT8 val) +{ + UINT16 sp = SPREG; + WRITE_IO_8(cpustate, sp, val); + sp--; + //printf( "PUSH %02x, new SP = %04x\n", val, sp ); + WRITE_IO_8(cpustate, AVR8_IO_SPH, (sp >> 8) & 0x00ff); + WRITE_IO_8(cpustate, AVR8_IO_SPL, sp & 0x00ff); +} + +INLINE UINT8 POP(avr8_state *cpustate) +{ + UINT16 sp = SPREG; + sp++; + WRITE_IO_8(cpustate, AVR8_IO_SPH, (sp >> 8) & 0x00ff); + WRITE_IO_8(cpustate, AVR8_IO_SPL, sp & 0x00ff); + //printf( "POP %02x, new SP = %04x\n", READ_IO_8(cpustate, sp), sp ); + return READ_IO_8(cpustate, sp); +} + +static void avr8_set_irq_line(avr8_state *cpustate, UINT16 vector, int state) +{ + //printf( "OMFG SETTING IRQ LINE\n" ); + // Horrible hack, not accurate + if(state) + { + if(SREG_R(AVR8_SREG_I)) + { + SREG_W(AVR8_SREG_I, 0); + PUSH(cpustate, (cpustate->pc >> 8) & 0x00ff); + PUSH(cpustate, cpustate->pc & 0x00ff); + cpustate->pc = vector; + } + } +} + +/*****************************************************************************/ + +static CPU_INIT( avr8 ) +{ + avr8_state *cpustate = get_safe_token(device); + + cpustate->pc = 0; + + cpustate->device = device; + cpustate->program = device->space(AS_PROGRAM); + cpustate->io = device->space(AS_IO); + + WRITE_IO_8(cpustate, AVR8_IO_SREG, 0); + + device->save_item(NAME(cpustate->pc)); +} + +static CPU_EXIT( avr8 ) +{ +} + +static CPU_RESET( avr8 ) +{ + avr8_state *cpustate = get_safe_token(device); + + WRITE_IO_8(cpustate, AVR8_IO_SREG, 0); + cpustate->pc = 0; +} + +static CPU_EXECUTE( avr8 ) +{ + UINT32 op = 0; + INT32 offs = 0; + UINT8 rd = 0; + UINT8 rr = 0; + UINT8 res = 0; + UINT16 pd = 0; + INT16 sd = 0; + INT32 opcycles = 1; + //UINT16 pr = 0; + avr8_state *cpustate = get_safe_token(device); + + while (cpustate->icount > 0) + { + cpustate->pc &= cpustate->addr_mask; + + debugger_instruction_hook(device, cpustate->pc << 1); + + op = (UINT32)READ_PRG_16(cpustate, cpustate->pc); + + switch(op & 0xf000) + { + case 0x0000: + switch(op & 0x0f00) + { + case 0x0000: // NOP + break; + case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd + WRITE_IO_8(cpustate, (RD4(op) << 1)+1, READ_IO_8(cpustate, (RR4(op) << 1)+1)); + WRITE_IO_8(cpustate, RD4(op) << 1, READ_IO_8(cpustate, RR4(op) << 1)); + break; + case 0x0200: // MULS Rd,Rr + //output += sprintf( output, "MULS R%d, R%d", 16+RD4(op), 16+RR4(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0300: // MULSU Rd,Rr + sd = (INT8)READ_IO_8(cpustate, 16+RD4(op)) * (UINT8)READ_IO_8(cpustate, 16+RR4(op)); + WRITE_IO_8(cpustate, 1, (sd >> 8) & 0x00ff); + WRITE_IO_8(cpustate, 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 0x0400: + case 0x0500: + case 0x0600: + case 0x0700: // CPC Rd,Rr + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, 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) ? 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: + case 0x0900: + case 0x0a00: + case 0x0b00: // SBC Rd,Rr + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + res = rd - (rr + SREG_R(AVR8_SREG_C)); + WRITE_IO_8(cpustate, 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: + case 0x0d00: + case 0x0e00: + case 0x0f00: // ADD Rd,Rr + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + res = rd + rr; + WRITE_IO_8(cpustate, 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: // CPSR Rd,Rr + //output += sprintf( output, "CPSE R%d, R%d", RD5(op), RR5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0400: // CP Rd,Rr + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, 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 = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + res = rd - rr; + WRITE_IO_8(cpustate, 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 = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + res = rd + rr + SREG_R(AVR8_SREG_C); + WRITE_IO_8(cpustate, 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 + //output += sprintf( output, "AND R%d, R%d", RD5(op), RR5(op) ); + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + rd &= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, rd & 0x80); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + WRITE_IO_8(cpustate, RD5(op), rd); + break; + case 0x0400: // EOR Rd,Rr + rd = READ_IO_8(cpustate, RD5(op)); + rr = READ_IO_8(cpustate, RR5(op)); + rd ^= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, rd & 0x80); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + WRITE_IO_8(cpustate, RD5(op), rd); + break; + case 0x0800: // OR Rd,Rr + //output += sprintf( output, "OR R%d, R%d", RD5(op), RR5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0c00: // MOV Rd,Rr + WRITE_IO_8(cpustate, RD5(op), READ_IO_8(cpustate, RR5(op))); + break; + } + break; + case 0x3000: // CPI Rd,K + rd = READ_IO_8(cpustate, 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 + //output += sprintf( output, "SBCI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x5000: // SUBI Rd,K + rd = READ_IO_8(cpustate, 16+RD4(op)); + rr = KCONST8(op); + res = rd - rr; + WRITE_IO_8(cpustate, 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 + //output += sprintf( output, "ORI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x7000: // ANDI Rd,K + //output += sprintf( output, "ANDI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x8000: + case 0xa000: + switch(op & 0x0208) + { + case 0x0000: // LDD Rd,Z+q + //output += sprintf( output, "LD(D) R%d, Z+%02x", RD5(op), QCONST6(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0008: // LDD Rd,Y+q + WRITE_IO_8(cpustate, RD5(op), YREG + QCONST6(op)); + opcycles = 2; + break; + case 0x0200: // STD Z+q,Rr + //output += sprintf( output, "ST(D) Z+%02x, R%d", QCONST6(op), RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0208: // STD Y+q,Rr + WRITE_IO_8(cpustate, YREG + QCONST6(op), READ_IO_8(cpustate, 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; + cpustate->pc++; + op |= READ_PRG_16(cpustate, cpustate->pc); + WRITE_IO_8(cpustate, RD5(op >> 16), READ_IO_8(cpustate, op & 0x0000ffff)); + opcycles = 2; + break; + case 0x0001: // LD Rd,Z+ + unimplemented_opcode(cpustate, op); + break; + case 0x0002: // LD Rd,-Z + //output += sprintf( output, "LD R%d,-Z", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0004: // LPM Rd,Z + WRITE_IO_8(cpustate, RD5(op), READ_PRG_8(cpustate, ZREG)); + opcycles = 3; + break; + case 0x0005: // LPM Rd,Z+ + pd = ZREG; + WRITE_IO_8(cpustate, RD5(op), READ_PRG_8(cpustate, pd)); + pd++; + WRITE_IO_8(cpustate, 31, (pd >> 8) & 0x00ff); + WRITE_IO_8(cpustate, 30, pd & 0x00ff); + opcycles = 3; + break; + case 0x0006: // ELPM Rd,Z + //output += sprintf( output, "ELPM R%d, Z", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0007: // ELPM Rd,Z+ + //output += sprintf( output, "ELPM R%d, Z+", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0009: // LD Rd,Y+ + //output += sprintf( output, "LD R%d, Y+", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000a: // LD Rd,-Y + //output += sprintf( output, "LD R%d,-Y", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000c: // LD Rd,X + //output += sprintf( output, "LD R%d, X", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000d: // LD Rd,X+ + pd = XREG; + WRITE_IO_8(cpustate, RD5(op), READ_IO_8(cpustate, pd)); + pd++; + WRITE_IO_8(cpustate, 27, (pd >> 8) & 0x00ff); + WRITE_IO_8(cpustate, 26, pd & 0x00ff); + opcycles = 2; + break; + case 0x000e: // LD Rd,-X + //output += sprintf( output, "LD R%d,-X", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000f: // POP Rd + WRITE_IO_8(cpustate, RD5(op), POP(cpustate)); + opcycles = 2; + break; + default: + unimplemented_opcode(cpustate, op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0200: + case 0x0300: + switch(op & 0x000f) + { + case 0x0000: // STS k,Rr + op <<= 16; + cpustate->pc++; + op |= READ_PRG_16(cpustate, cpustate->pc); + WRITE_IO_8(cpustate, op & 0x0000ffff, READ_IO_8(cpustate, RD5(op >> 16))); + opcycles = 2; + break; + case 0x0001: // ST Z+,Rd + //output += sprintf( output, "ST Z+, R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0002: // ST -Z,Rd + //output += sprintf( output, "ST -Z , R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0009: // ST Y+,Rd + //output += sprintf( output, "ST Y+, R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000a: // ST -Z,Rd + //output += sprintf( output, "ST -Y , R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000c: // ST X,Rd + rd = READ_IO_8(cpustate, RD5(op)); + WRITE_IO_8(cpustate, XREG, rd); + opcycles = 2; + break; + case 0x000d: // ST X+,Rd + pd = XREG; + WRITE_IO_8(cpustate, pd, READ_IO_8(cpustate, RD5(op))); + pd++; + WRITE_IO_8(cpustate, 27, (pd >> 8) & 0x00ff); + WRITE_IO_8(cpustate, 26, pd & 0x00ff); + opcycles = 2; + break; + case 0x000e: // ST -X,Rd + //output += sprintf( output, "ST -X , R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000f: // PUSH Rd + PUSH(cpustate, READ_IO_8(cpustate, RD5(op))); + opcycles = 2; + break; + default: + unimplemented_opcode(cpustate, op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0400: + switch(op & 0x000f) + { + case 0x0000: // COM Rd + rd = READ_IO_8(cpustate, RD5(op)); + rd = ~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)); + break; + case 0x0001: // NEG Rd + rd = READ_IO_8(cpustate, 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)); + break; + case 0x0002: // SWAP Rd + //output += sprintf( output, "SWAP R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0003: // INC Rd + rd = READ_IO_8(cpustate, 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); + WRITE_IO_8(cpustate, RD5(op), res); + break; + case 0x0005: // ASR Rd + //output += sprintf( output, "ASR R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0006: // LSR Rd + rd = READ_IO_8(cpustate, RD5(op)); + res = rd >> 1; + SREG_W(AVR8_SREG_C, rd & 0x01); + 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)); + break; + case 0x0007: // ROR Rd + //output += sprintf( output, "ROR R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + 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 + cpustate->pc = ZREG - 1; + opcycles = 2; + break; + case 0x0010: // EIJMP + //output += sprintf( output, "EIJMP" ); + unimplemented_opcode(cpustate, op); + break; + default: + //output += sprintf( output, "Undefined (%04x)", op ); + unimplemented_opcode(cpustate, op); + break; + } + break; + case 0x000a: // DEC Rd + rd = READ_IO_8(cpustate, 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); + WRITE_IO_8(cpustate, RD5(op), res); + break; + case 0x000c: + case 0x000d: // JMP k + offs = KCONST22(op) << 16; + cpustate->pc++; + offs |= READ_PRG_16(cpustate, cpustate->pc); + cpustate->pc = offs; + cpustate->pc--; + opcycles = 4; + break; + case 0x000e: // CALL k + case 0x000f: + PUSH(cpustate, ((cpustate->pc + 1) >> 8) & 0x00ff); + PUSH(cpustate, (cpustate->pc + 1) & 0x00ff); + offs = KCONST22(op) << 16; + cpustate->pc++; + offs |= READ_PRG_16(cpustate, cpustate->pc); + cpustate->pc = offs; + cpustate->pc--; + break; + default: + unimplemented_opcode(cpustate, op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0500: + switch(op & 0x000f) + { + case 0x0000: // COM Rd + rd = READ_IO_8(cpustate, RD5(op)); + rd = ~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)); + break; + case 0x0001: // NEG Rd + rd = READ_IO_8(cpustate, RD5(op)); + res = 0 - rd; + WRITE_IO_8(cpustate, RD5(op), res); + 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)); + break; + case 0x0002: // SWAP Rd + //output += sprintf( output, "SWAP R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0003: // INC Rd + rd = READ_IO_8(cpustate, 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); + WRITE_IO_8(cpustate, RD5(op), res); + break; + case 0x0005: // ASR Rd + //output += sprintf( output, "ASR R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0006: // LSR Rd + rd = READ_IO_8(cpustate, RD5(op)); + res = rd >> 1; + SREG_W(AVR8_SREG_C, rd & 0x01); + 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)); + break; + case 0x0007: // ROR Rd + //output += sprintf( output, "ROR R%d", RD5(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0008: + switch(op & 0x00f0) + { + case 0x0000: // RET + cpustate->pc = POP(cpustate); + cpustate->pc |= POP(cpustate) << 8; + cpustate->pc--; + opcycles = 4; + break; + case 0x0010: // RETI + cpustate->pc = POP(cpustate); + cpustate->pc |= POP(cpustate) << 8; + cpustate->pc--; + SREG_W(AVR8_SREG_I, 1); + opcycles = 4; + break; + case 0x0080: // SLEEP + //output += sprintf( output, "SLEEP" ); + unimplemented_opcode(cpustate, op); + break; + case 0x0090: // BREAK + //output += sprintf( output, "BREAK" ); + unimplemented_opcode(cpustate, op); + break; + case 0x00a0: // WDR + //output += sprintf( output, "WDR" ); + unimplemented_opcode(cpustate, op); + break; + case 0x00c0: // LPM + WRITE_IO_8(cpustate, 0, READ_PRG_8(cpustate, ZREG)); + opcycles = 3; + break; + case 0x00d0: // ELPM + //output += sprintf( output, "ELPM" ); + unimplemented_opcode(cpustate, op); + break; + case 0x00e0: // SPM + //output += sprintf( output, "SPM" ); + unimplemented_opcode(cpustate, op); + break; + case 0x00f0: // SPM Z+ + //output += sprintf( output, "SPM Z+" ); + unimplemented_opcode(cpustate, op); + break; + default: + unimplemented_opcode(cpustate, op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0009: + switch(op & 0x00f0) + { + case 0x0000: // ICALL + //output += sprintf( output, "ICALL" ); + unimplemented_opcode(cpustate, op); + break; + case 0x0010: // EICALL + //output += sprintf( output, "EICALL" ); + unimplemented_opcode(cpustate, op); + break; + default: + unimplemented_opcode(cpustate, op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x000a: // DEC Rd + rd = READ_IO_8(cpustate, 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); + WRITE_IO_8(cpustate, RD5(op), res); + break; + case 0x000c: + case 0x000d: // JMP k + //op <<= 8; + //op |= oprom[pos++]; + //op <<= 8; + //op |= oprom[pos++]; + //output += sprintf( output, "JMP 0x%06x", KCONST22(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x000e: + case 0x000f: // CALL k + //op <<= 8; + //op |= oprom[pos++]; + //op <<= 8; + //op |= oprom[pos++]; + //output += sprintf( output, "CALL 0x%06x", KCONST22(op) ); + unimplemented_opcode(cpustate, op); + break; + } + break; + case 0x0600: // ADIW Rd+1:Rd,K + //output += sprintf( output, "ADIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0700: // SBIW Rd+1:Rd,K + //output += sprintf( output, "SBIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0800: // CBI A,b + //output += sprintf( output, "CBI 0x%02x, %d", ACONST5(op), RR3(op) ); + WRITE_IO_8(cpustate, ACONST5(op), READ_IO_8(cpustate, ACONST5(op)) &~ (1 << RR3(op))); + opcycles = 2; + break; + case 0x0900: // SBIC A,b + if(!(READ_IO_8(cpustate, ACONST5(op)) & (1 << RR3(op)))) + { + opcycles += avr8_is_long_opcode(op) ? 2 : 1; + cpustate->pc += avr8_is_long_opcode(op) ? 2 : 1; + } + break; + case 0x0a00: // SBI A,b + //output += sprintf( output, "SBI 0x%02x, %d", ACONST5(op), RR3(op) ); + WRITE_IO_8(cpustate, ACONST5(op), READ_IO_8(cpustate, ACONST5(op)) | (1 << RR3(op))); + opcycles = 2; + break; + case 0x0b00: // SBIS A,b + //output += sprintf( output, "SBIS 0x%02x, %d", ACONST5(op), RR3(op) ); + unimplemented_opcode(cpustate, op); + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: // MUL Rd,Rr + sd = (UINT8)READ_IO_8(cpustate, RD5(op)) * (UINT8)READ_IO_8(cpustate, RR5(op)); + WRITE_IO_8(cpustate, 1, (sd >> 8) & 0x00ff); + WRITE_IO_8(cpustate, 0, sd & 0x00ff); + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + //output += sprintf( output, "MUL R%d, R%d", RD5(op), RR5(op) ); + break; + } + break; + case 0xb000: + if(op & 0x0800) // OUT A,Rr + { + WRITE_IO_8(cpustate, 0x20 + ACONST6(op), READ_IO_8(cpustate, RD5(op))); + } + else // IN Rd,A + { + WRITE_IO_8(cpustate, RD5(op), READ_IO_8(cpustate, 0x20 + ACONST6(op))); + } + break; + case 0xc000: // RJMP k + offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); + cpustate->pc += offs; + opcycles = 2; + break; + case 0xd000: // RCALL k + offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); + PUSH(cpustate, ((cpustate->pc + 1) >> 8) & 0x00ff); + PUSH(cpustate, (cpustate->pc + 1) & 0x00ff); + cpustate->pc += offs; + opcycles = 3; + break; + case 0xe000: // LDI Rd,K + rd = KCONST8(op); + WRITE_IO_8(cpustate, 16 + RD4(op), rd); + break; + case 0xf000: + switch(op & 0x0c00) + { + case 0x0000: // BRLO through BRIE + if(SREG_R(op & 0x0007)) + { + offs = (INT32)(KCONST7(op)); + if(offs & 0x40) + { + offs |= 0xffffff80; + } + cpustate->pc += offs; + opcycles = 2; + } + break; + case 0x0400: // BRSH through BRID + if(SREG_R(op & 0x0007) == 0) + { + offs = (INT32)(KCONST7(op)); + if(offs & 0x40) + { + offs |= 0xffffff80; + } + cpustate->pc += offs; + opcycles = 2; + } + break; + case 0x0800: + if(op & 0x0200) // BST Rd, b + { + SREG_W(AVR8_SREG_T, (BIT(READ_IO_8(cpustate, RD5(op)),RR3(op))) ? 1 : 0); + } + else // BLD Rd, b + { + if(SREG_R(AVR8_SREG_T)) + { + WRITE_IO_8(cpustate, RD5(op), READ_IO_8(cpustate, RD5(op)) | (1 << RR3(op))); + } + else + { + WRITE_IO_8(cpustate, RD5(op), READ_IO_8(cpustate, RD5(op)) &~ (1 << RR3(op))); + } + } + break; + case 0x0c00: + if(op & 0x0200) // SBRS Rd, b + { + if(BIT(READ_IO_8(cpustate, RD5(op)),RR3(op))) + { + op = (UINT32)READ_PRG_16(cpustate, cpustate->pc++); + opcycles = 2; + if((op & 0xfe0c) == 0x940c || + (op & 0xfe0f) == 0xfe0f) + { + cpustate->pc++; + opcycles = 3; + } + } + } + else // SBRC Rd, b + { + if(!BIT(READ_IO_8(cpustate, RD5(op)),RR3(op))) + { + op = (UINT32)READ_PRG_16(cpustate, cpustate->pc++); + opcycles = 2; + if((op & 0xfe0c) == 0x940c || + (op & 0xfc0f) == 0x9000) + { + cpustate->pc++; + opcycles = 3; + } + } + } + break; + } + break; + } + + cpustate->pc++; + + cpustate->icount -= opcycles; + } +} + +/*****************************************************************************/ + +static CPU_SET_INFO( avr8 ) +{ + avr8_state *cpustate = get_safe_token(device); + + switch (state) + { + + /* interrupt lines/exceptions */ + case CPUINFO_INT_INPUT_STATE + AVR8_INT_RESET: avr8_set_irq_line(cpustate, AVR8_INT_RESET, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_INT0: avr8_set_irq_line(cpustate, AVR8_INT_INT0, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_INT1: avr8_set_irq_line(cpustate, AVR8_INT_INT1, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_PCINT0: avr8_set_irq_line(cpustate, AVR8_INT_PCINT0, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_PCINT1: avr8_set_irq_line(cpustate, AVR8_INT_PCINT1, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_PCINT2: avr8_set_irq_line(cpustate, AVR8_INT_PCINT2, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_WDT: avr8_set_irq_line(cpustate, AVR8_INT_WDT, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T2COMPA: avr8_set_irq_line(cpustate, AVR8_INT_T2COMPA, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T2COMPB: avr8_set_irq_line(cpustate, AVR8_INT_T2COMPB, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T2OVF: avr8_set_irq_line(cpustate, AVR8_INT_T2OVF, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T1CAPT: avr8_set_irq_line(cpustate, AVR8_INT_T1CAPT, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T1COMPA: avr8_set_irq_line(cpustate, AVR8_INT_T1COMPA, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T1COMPB: avr8_set_irq_line(cpustate, AVR8_INT_T1COMPB, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T1OVF: avr8_set_irq_line(cpustate, AVR8_INT_T1OVF, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T0COMPA: avr8_set_irq_line(cpustate, AVR8_INT_T0COMPA, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T0COMPB: avr8_set_irq_line(cpustate, AVR8_INT_T0COMPB, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_T0OVF: avr8_set_irq_line(cpustate, AVR8_INT_T0OVF, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_SPI_STC: avr8_set_irq_line(cpustate, AVR8_INT_SPI_STC, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_USART_RX: avr8_set_irq_line(cpustate, AVR8_INT_USART_RX, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_USART_UDRE: avr8_set_irq_line(cpustate, AVR8_INT_USART_UDRE, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_USART_TX: avr8_set_irq_line(cpustate, AVR8_INT_USART_TX, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_ADC: avr8_set_irq_line(cpustate, AVR8_INT_ADC, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_EE_RDY: avr8_set_irq_line(cpustate, AVR8_INT_EE_RDY, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_ANALOG_COMP: avr8_set_irq_line(cpustate, AVR8_INT_ANALOG_COMP, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_TWI: avr8_set_irq_line(cpustate, AVR8_INT_TWI, info->i); break; + case CPUINFO_INT_INPUT_STATE + AVR8_INT_SPM_RDY: avr8_set_irq_line(cpustate, AVR8_INT_SPM_RDY, info->i); break; + + /* --- the following bits of info are set as 64-bit signed integers --- */ + case CPUINFO_INT_PC: /* intentional fallthrough */ + case CPUINFO_INT_REGISTER + AVR8_PC: cpustate->pc = info->i; break; + case CPUINFO_INT_REGISTER + AVR8_SREG: WRITE_IO_8(cpustate, AVR8_IO_SREG, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R0: WRITE_IO_8(cpustate, 0, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R1: WRITE_IO_8(cpustate, 1, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R2: WRITE_IO_8(cpustate, 2, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R3: WRITE_IO_8(cpustate, 3, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R4: WRITE_IO_8(cpustate, 4, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R5: WRITE_IO_8(cpustate, 5, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R6: WRITE_IO_8(cpustate, 6, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R7: WRITE_IO_8(cpustate, 7, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R8: WRITE_IO_8(cpustate, 8, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R9: WRITE_IO_8(cpustate, 9, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R10: WRITE_IO_8(cpustate, 10, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R11: WRITE_IO_8(cpustate, 11, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R12: WRITE_IO_8(cpustate, 12, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R13: WRITE_IO_8(cpustate, 13, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R14: WRITE_IO_8(cpustate, 14, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R15: WRITE_IO_8(cpustate, 15, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R16: WRITE_IO_8(cpustate, 16, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R17: WRITE_IO_8(cpustate, 17, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R18: WRITE_IO_8(cpustate, 18, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R19: WRITE_IO_8(cpustate, 19, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R20: WRITE_IO_8(cpustate, 20, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R21: WRITE_IO_8(cpustate, 21, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R22: WRITE_IO_8(cpustate, 22, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R23: WRITE_IO_8(cpustate, 23, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R24: WRITE_IO_8(cpustate, 24, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R25: WRITE_IO_8(cpustate, 25, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R26: WRITE_IO_8(cpustate, 26, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R27: WRITE_IO_8(cpustate, 27, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R28: WRITE_IO_8(cpustate, 28, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R29: WRITE_IO_8(cpustate, 29, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R30: WRITE_IO_8(cpustate, 30, info->i); break; + case CPUINFO_INT_REGISTER + AVR8_R31: WRITE_IO_8(cpustate, 31, info->i); break; + } +} + +CPU_GET_INFO( avr8 ) +{ + avr8_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; + + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(avr8_state); break; + case CPUINFO_INT_INPUT_LINES: info->i = 0; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 4; break; + + case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 22; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; + case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; + case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 11; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; + + case CPUINFO_INT_PC: /* intentional fallthrough */ + case CPUINFO_INT_REGISTER + AVR8_PC: info->i = cpustate->pc << 1; break; + case CPUINFO_INT_REGISTER + AVR8_SREG: info->i = READ_IO_8(cpustate, AVR8_IO_SREG); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(avr8); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(avr8); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(avr8); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(avr8); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(avr8); break; + case CPUINFO_FCT_BURN: info->burn = NULL; break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(avr8); break; + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Atmel 8-bit AVR"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "AVR8"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + + case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; + + case CPUINFO_STR_REGISTER + AVR8_SREG: sprintf(info->s, "SREG: %c%c%c%c%c%c%c%c", (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x80) ? 'I' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x40) ? 'T' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x20) ? 'H' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x10) ? 'S' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x08) ? 'V' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x04) ? 'N' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x02) ? 'Z' : '-', (READ_IO_8(cpustate, AVR8_IO_SREG) & 0x01) ? 'C' : '-'); break; + case CPUINFO_STR_REGISTER + AVR8_R0: sprintf(info->s, "R0: %02x", READ_IO_8(cpustate, 0) ); break; + case CPUINFO_STR_REGISTER + AVR8_R1: sprintf(info->s, "R1: %02x", READ_IO_8(cpustate, 1) ); break; + case CPUINFO_STR_REGISTER + AVR8_R2: sprintf(info->s, "R2: %02x", READ_IO_8(cpustate, 2) ); break; + case CPUINFO_STR_REGISTER + AVR8_R3: sprintf(info->s, "R3: %02x", READ_IO_8(cpustate, 3) ); break; + case CPUINFO_STR_REGISTER + AVR8_R4: sprintf(info->s, "R4: %02x", READ_IO_8(cpustate, 4) ); break; + case CPUINFO_STR_REGISTER + AVR8_R5: sprintf(info->s, "R5: %02x", READ_IO_8(cpustate, 5) ); break; + case CPUINFO_STR_REGISTER + AVR8_R6: sprintf(info->s, "R6: %02x", READ_IO_8(cpustate, 6) ); break; + case CPUINFO_STR_REGISTER + AVR8_R7: sprintf(info->s, "R7: %02x", READ_IO_8(cpustate, 7) ); break; + case CPUINFO_STR_REGISTER + AVR8_R8: sprintf(info->s, "R8: %02x", READ_IO_8(cpustate, 8) ); break; + case CPUINFO_STR_REGISTER + AVR8_R9: sprintf(info->s, "R9: %02x", READ_IO_8(cpustate, 9) ); break; + case CPUINFO_STR_REGISTER + AVR8_R10: sprintf(info->s, "R10: %02x", READ_IO_8(cpustate, 10) ); break; + case CPUINFO_STR_REGISTER + AVR8_R11: sprintf(info->s, "R11: %02x", READ_IO_8(cpustate, 11) ); break; + case CPUINFO_STR_REGISTER + AVR8_R12: sprintf(info->s, "R12: %02x", READ_IO_8(cpustate, 12) ); break; + case CPUINFO_STR_REGISTER + AVR8_R13: sprintf(info->s, "R13: %02x", READ_IO_8(cpustate, 13) ); break; + case CPUINFO_STR_REGISTER + AVR8_R14: sprintf(info->s, "R14: %02x", READ_IO_8(cpustate, 14) ); break; + case CPUINFO_STR_REGISTER + AVR8_R15: sprintf(info->s, "R15: %02x", READ_IO_8(cpustate, 15) ); break; + case CPUINFO_STR_REGISTER + AVR8_R16: sprintf(info->s, "R16: %02x", READ_IO_8(cpustate, 16) ); break; + case CPUINFO_STR_REGISTER + AVR8_R17: sprintf(info->s, "R17: %02x", READ_IO_8(cpustate, 17) ); break; + case CPUINFO_STR_REGISTER + AVR8_R18: sprintf(info->s, "R18: %02x", READ_IO_8(cpustate, 18) ); break; + case CPUINFO_STR_REGISTER + AVR8_R19: sprintf(info->s, "R19: %02x", READ_IO_8(cpustate, 19) ); break; + case CPUINFO_STR_REGISTER + AVR8_R20: sprintf(info->s, "R20: %02x", READ_IO_8(cpustate, 20) ); break; + case CPUINFO_STR_REGISTER + AVR8_R21: sprintf(info->s, "R21: %02x", READ_IO_8(cpustate, 21) ); break; + case CPUINFO_STR_REGISTER + AVR8_R22: sprintf(info->s, "R22: %02x", READ_IO_8(cpustate, 22) ); break; + case CPUINFO_STR_REGISTER + AVR8_R23: sprintf(info->s, "R23: %02x", READ_IO_8(cpustate, 23) ); break; + case CPUINFO_STR_REGISTER + AVR8_R24: sprintf(info->s, "R24: %02x", READ_IO_8(cpustate, 24) ); break; + case CPUINFO_STR_REGISTER + AVR8_R25: sprintf(info->s, "R25: %02x", READ_IO_8(cpustate, 25) ); break; + case CPUINFO_STR_REGISTER + AVR8_R26: sprintf(info->s, "R26: %02x", READ_IO_8(cpustate, 26) ); break; + case CPUINFO_STR_REGISTER + AVR8_R27: sprintf(info->s, "R27: %02x", READ_IO_8(cpustate, 27) ); break; + case CPUINFO_STR_REGISTER + AVR8_R28: sprintf(info->s, "R28: %02x", READ_IO_8(cpustate, 28) ); break; + case CPUINFO_STR_REGISTER + AVR8_R29: sprintf(info->s, "R29: %02x", READ_IO_8(cpustate, 29) ); break; + case CPUINFO_STR_REGISTER + AVR8_R30: sprintf(info->s, "R30: %02x", READ_IO_8(cpustate, 30) ); break; + case CPUINFO_STR_REGISTER + AVR8_R31: sprintf(info->s, "R31: %02x", READ_IO_8(cpustate, 31) ); break; + case CPUINFO_STR_REGISTER + AVR8_X: sprintf(info->s, "X: %04x", XREG ); break; + case CPUINFO_STR_REGISTER + AVR8_Y: sprintf(info->s, "Y: %04x", YREG ); break; + case CPUINFO_STR_REGISTER + AVR8_Z: sprintf(info->s, "Z: %04x", ZREG ); break; + case CPUINFO_STR_REGISTER + AVR8_SP: sprintf(info->s, "SP: %04x", SPREG ); break; + } +} + +static CPU_INIT( atmega88 ) +{ + CPU_INIT_CALL(avr8); + avr8_state *cpustate = get_safe_token(device); + cpustate->addr_mask = 0x0fff; +} + +static CPU_INIT( atmega644 ) +{ + CPU_INIT_CALL(avr8); + avr8_state *cpustate = get_safe_token(device); + cpustate->addr_mask = 0xffff; +} + +CPU_GET_INFO( atmega88 ) +{ + switch (state) + { + /* --- the following bits of info are returned as pointers to functions --- */ + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(atmega88); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "ATmega88"); break; + + default: CPU_GET_INFO_CALL(avr8); break; + } +} + +CPU_GET_INFO( atmega644 ) +{ + switch (state) + { + /* --- the following bits of info are returned as pointers to functions --- */ + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(atmega644); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "ATmega644"); break; + + default: CPU_GET_INFO_CALL(avr8); break; + } +} + +DEFINE_LEGACY_CPU_DEVICE(ATMEGA88, atmega88); +DEFINE_LEGACY_CPU_DEVICE(ATMEGA644, atmega644); |