summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/mc68hc11/mc68hc11.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/mc68hc11/mc68hc11.c')
-rw-r--r--src/emu/cpu/mc68hc11/mc68hc11.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/src/emu/cpu/mc68hc11/mc68hc11.c b/src/emu/cpu/mc68hc11/mc68hc11.c
new file mode 100644
index 00000000000..4fd2528c364
--- /dev/null
+++ b/src/emu/cpu/mc68hc11/mc68hc11.c
@@ -0,0 +1,494 @@
+/*
+ Motorola MC68HC11 emulator
+
+ Written by Ville Linde
+ */
+
+#include "debugger.h"
+#include "mc68hc11.h"
+
+enum {
+ HC11_PC = 1,
+ HC11_SP,
+ HC11_A,
+ HC11_B,
+ HC11_IX,
+ HC11_IY
+};
+
+#define CC_S 0x80
+#define CC_X 0x40
+#define CC_H 0x20
+#define CC_I 0x10
+#define CC_N 0x08
+#define CC_Z 0x04
+#define CC_V 0x02
+#define CC_C 0x01
+
+typedef struct
+{
+ union {
+ struct {
+#ifdef LSB_FIRST
+ UINT8 b;
+ UINT8 a;
+#else
+ UINT8 a;
+ UINT8 b;
+#endif
+ } d8;
+ UINT16 d16;
+ } d;
+
+ UINT16 ix;
+ UINT16 iy;
+ UINT16 sp;
+ UINT16 pc;
+ UINT16 ppc;
+ UINT8 ccr;
+
+ UINT8 adctl;
+ int ad_channel;
+
+ int (*irq_callback)(int irqline);
+ int icount;
+ int ram_position;
+ int reg_position;
+} HC11_REGS;
+
+static HC11_REGS hc11;
+static UINT8 *internal_ram;
+static int internal_ram_size;
+
+#define HC11OP(XX) hc11_##XX
+
+/*****************************************************************************/
+/* Internal registers */
+
+static UINT8 hc11_regs_r(UINT32 address)
+{
+ int reg = address & 0xff;
+
+ switch(reg)
+ {
+ case 0x00: /* PORTA */
+ return io_read_byte(MC68HC11_IO_PORTA);
+ case 0x01: /* DDRA */
+ return 0;
+ case 0x09: /* DDRD */
+ return 0;
+ case 0x28: /* SPCR1 */
+ return 0;
+ case 0x30: /* ADCTL */
+ return 0x80;
+ case 0x31: /* ADR1 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD0);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x32: /* ADR2 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD1);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x33: /* ADR3 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD2);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x34: /* ADR4 */
+ {
+ if (hc11.adctl & 0x10)
+ {
+ return io_read_byte((hc11.adctl & 0x4) + MC68HC11_IO_AD3);
+ }
+ else
+ {
+ return io_read_byte((hc11.adctl & 0x7) + MC68HC11_IO_AD0);
+ }
+ break;
+ }
+ case 0x38: /* OPT2 */
+ return 0;
+ case 0x70: /* SCBDH */
+ return 0;
+ case 0x71: /* SCBDL */
+ return 0;
+ case 0x72: /* SCCR1 */
+ return 0;
+ case 0x73: /* SCCR2 */
+ return 0;
+ case 0x74: /* SCSR1 */
+ return 0x40;
+ case 0x7c: /* PORTH */
+ return io_read_byte(MC68HC11_IO_PORTH);
+ case 0x7e: /* PORTG */
+ return io_read_byte(MC68HC11_IO_PORTG);
+ case 0x7f: /* DDRG */
+ return 0;
+
+ case 0x88: /* SPCR2 */
+ return 0;
+ case 0x89: /* SPSR2 */
+ return 0x80;
+ case 0x8a: /* SPDR2 */
+ return io_read_byte(MC68HC11_IO_SPI2_DATA);
+
+ case 0x8b: /* OPT4 */
+ return 0;
+ }
+
+ fatalerror("HC11: regs_r %02X", reg);
+ return 0; // Dummy
+}
+
+static void hc11_regs_w(UINT32 address, UINT8 value)
+{
+ int reg = address & 0xff;
+
+ switch(reg)
+ {
+ case 0x00: /* PORTA */
+ io_write_byte(MC68HC11_IO_PORTA, value);
+ return;
+ case 0x01: /* DDRA */
+ //mame_printf_debug("HC11: ddra = %02X\n", value);
+ return;
+ case 0x08: /* PORTD */
+ io_write_byte(MC68HC11_IO_PORTD, value);
+ return;
+ case 0x09: /* DDRD */
+ //mame_printf_debug("HC11: ddrd = %02X\n", value);
+ return;
+ case 0x22: /* TMSK1 */
+ return;
+ case 0x24: /* TMSK2 */
+ return;
+ case 0x28: /* SPCR1 */
+ return;
+ case 0x30: /* ADCTL */
+ hc11.adctl = value;
+ return;
+ case 0x38: /* OPT2 */
+ return;
+ case 0x39: /* OPTION */
+ return;
+
+ case 0x3d: /* INIT */
+ {
+ int reg_page = value & 0xf;
+ int ram_page = (value >> 4) & 0xf;
+
+ if (reg_page == ram_page) {
+ hc11.reg_position = reg_page << 12;
+ hc11.ram_position = (ram_page << 12) + 0x100;
+ } else {
+ hc11.reg_position = reg_page << 12;
+ hc11.ram_position = ram_page << 12;
+ }
+ return;
+ }
+
+ case 0x3f: /* CONFIG */
+ return;
+
+ case 0x70: /* SCBDH */
+ return;
+ case 0x71: /* SCBDL */
+ return;
+ case 0x72: /* SCCR1 */
+ return;
+ case 0x73: /* SCCR2 */
+ return;
+ case 0x77: /* SCDRL */
+ return;
+ case 0x7c: /* PORTH */
+ io_write_byte(MC68HC11_IO_PORTH, value);
+ return;
+ case 0x7d: /* DDRH */
+ //mame_printf_debug("HC11: ddrh = %02X at %04X\n", value, hc11.pc);
+ return;
+ case 0x7e: /* PORTG */
+ io_write_byte(MC68HC11_IO_PORTG, value);
+ return;
+ case 0x7f: /* DDRG */
+ //mame_printf_debug("HC11: ddrg = %02X at %04X\n", value, hc11.pc);
+ return;
+
+ case 0x88: /* SPCR2 */
+ return;
+ case 0x89: /* SPSR2 */
+ return;
+ case 0x8a: /* SPDR2 */
+ io_write_byte(MC68HC11_IO_SPI2_DATA, value);
+ return;
+
+ case 0x8b: /* OPT4 */
+ return;
+
+ }
+ fatalerror("HC11: regs_w %02X, %02X", reg, value);
+}
+
+/*****************************************************************************/
+
+INLINE UINT8 FETCH(void)
+{
+ return cpu_readop(hc11.pc++);
+}
+
+INLINE UINT16 FETCH16(void)
+{
+ UINT16 w;
+ w = (cpu_readop(hc11.pc) << 8) | (cpu_readop(hc11.pc+1));
+ hc11.pc += 2;
+ return w;
+}
+
+INLINE UINT8 READ8(UINT32 address)
+{
+ if(address >= hc11.reg_position && address < hc11.reg_position+0x100)
+ {
+ return hc11_regs_r(address);
+ }
+ else if(address >= hc11.ram_position && address < hc11.ram_position+internal_ram_size)
+ {
+ return internal_ram[address-hc11.ram_position];
+ }
+ return program_read_byte(address);
+}
+
+INLINE void WRITE8(UINT32 address, UINT8 value)
+{
+ if(address >= hc11.reg_position && address < hc11.reg_position+0x100)
+ {
+ hc11_regs_w(address, value);
+ return;
+ }
+ else if(address >= hc11.ram_position && address < hc11.ram_position+internal_ram_size)
+ {
+ internal_ram[address-hc11.ram_position] = value;
+ return;
+ }
+ program_write_byte(address, value);
+}
+
+INLINE UINT16 READ16(UINT32 address)
+{
+ return (READ8(address) << 8) | (READ8(address+1));
+}
+
+INLINE void WRITE16(UINT32 address, UINT16 value)
+{
+ WRITE8(address+0, (value >> 8) & 0xff);
+ WRITE8(address+1, (value >> 0) & 0xff);
+}
+
+/*****************************************************************************/
+
+static void (*hc11_optable[256])(void);
+static void (*hc11_optable_page2[256])(void);
+static void (*hc11_optable_page3[256])(void);
+static void (*hc11_optable_page4[256])(void);
+
+#include "hc11ops.c"
+#include "hc11ops.h"
+
+static void hc11_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ int i;
+
+ /* clear the opcode tables */
+ for(i=0; i < 256; i++) {
+ hc11_optable[i] = HC11OP(invalid);
+ hc11_optable_page2[i] = HC11OP(invalid);
+ hc11_optable_page3[i] = HC11OP(invalid);
+ hc11_optable_page4[i] = HC11OP(invalid);
+ }
+ /* fill the opcode tables */
+ for(i=0; i < sizeof(hc11_opcode_list)/sizeof(HC11_OPCODE_LIST); i++)
+ {
+ switch(hc11_opcode_list[i].page)
+ {
+ case 0x00:
+ hc11_optable[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0x18:
+ hc11_optable_page2[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0x1A:
+ hc11_optable_page3[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ case 0xCD:
+ hc11_optable_page4[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler;
+ break;
+ }
+ }
+
+ internal_ram_size = 1280; /* FIXME: this is for MC68HC11M0 */
+ internal_ram = auto_malloc(internal_ram_size);
+
+ hc11.reg_position = 0;
+ hc11.ram_position = 0x100;
+ hc11.irq_callback = irqcallback;
+}
+
+static void hc11_reset(void)
+{
+ hc11.pc = READ16(0xfffe);
+}
+
+static void hc11_exit(void)
+{
+
+}
+
+static void hc11_get_context(void *dst)
+{
+ if (dst) {
+ *(HC11_REGS*)dst = hc11;
+ }
+}
+
+static void hc11_set_context(void *src)
+{
+ if (src) {
+ hc11 = *(HC11_REGS*)src;
+ }
+ change_pc(hc11.pc);
+}
+
+static int hc11_execute(int cycles)
+{
+ hc11.icount = cycles;
+
+ while(hc11.icount > 0)
+ {
+ UINT8 op;
+
+ hc11.ppc = hc11.pc;
+ CALL_MAME_DEBUG;
+
+ op = FETCH();
+ hc11_optable[op]();
+ }
+
+ return cycles-hc11.icount;
+}
+
+/*****************************************************************************/
+
+static void mc68hc11_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC: hc11.pc = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_PC: hc11.pc = info->i; change_pc(hc11.pc); break;
+ case CPUINFO_INT_REGISTER + HC11_SP: hc11.sp = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_A: hc11.d.d8.a = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_B: hc11.d.d8.b = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_IX: hc11.ix = info->i; break;
+ case CPUINFO_INT_REGISTER + HC11_IY: hc11.iy = info->i; break;
+ }
+}
+
+void mc68hc11_get_info(UINT32 state, cpuinfo *info)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(hc11); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 41; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break;
+
+ case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
+
+ case CPUINFO_INT_PC: /* intentional fallthrough */
+ case CPUINFO_INT_REGISTER + HC11_PC: info->i = hc11.pc; break;
+ case CPUINFO_INT_REGISTER + HC11_SP: info->i = hc11.sp; break;
+ case CPUINFO_INT_REGISTER + HC11_A: info->i = hc11.d.d8.a; break;
+ case CPUINFO_INT_REGISTER + HC11_B: info->i = hc11.d.d8.b; break;
+ case CPUINFO_INT_REGISTER + HC11_IX: info->i = hc11.ix; break;
+ case CPUINFO_INT_REGISTER + HC11_IY: info->i = hc11.iy; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = mc68hc11_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = hc11_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = hc11_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = hc11_init; break;
+ case CPUINFO_PTR_RESET: info->reset = hc11_reset; break;
+ case CPUINFO_PTR_EXIT: info->exit = hc11_exit; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = hc11_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = hc11_disasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &hc11.icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "MC68HC11"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Motorola MC68HC11"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (C) 2004 Ville Linde"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ (hc11.ccr & CC_S) ? 'S' : '.',
+ (hc11.ccr & CC_X) ? 'X' : '.',
+ (hc11.ccr & CC_H) ? 'H' : '.',
+ (hc11.ccr & CC_I) ? 'I' : '.',
+ (hc11.ccr & CC_N) ? 'N' : '.',
+ (hc11.ccr & CC_Z) ? 'Z' : '.',
+ (hc11.ccr & CC_V) ? 'V' : '.',
+ (hc11.ccr & CC_C) ? 'C' : '.');
+ break;
+
+ case CPUINFO_STR_REGISTER + HC11_PC: sprintf(info->s, "PC: %04X", hc11.pc); break;
+ case CPUINFO_STR_REGISTER + HC11_SP: sprintf(info->s, "SP: %04X", hc11.sp); break;
+ case CPUINFO_STR_REGISTER + HC11_A: sprintf(info->s, "A: %02X", hc11.d.d8.a); break;
+ case CPUINFO_STR_REGISTER + HC11_B: sprintf(info->s, "B: %02X", hc11.d.d8.b); break;
+ case CPUINFO_STR_REGISTER + HC11_IX: sprintf(info->s, "IX: %04X", hc11.ix); break;
+ case CPUINFO_STR_REGISTER + HC11_IY: sprintf(info->s, "IY: %04X", hc11.iy); break;
+ }
+}