summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/minx/minx.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/minx/minx.c')
-rw-r--r--trunk/src/emu/cpu/minx/minx.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/minx/minx.c b/trunk/src/emu/cpu/minx/minx.c
new file mode 100644
index 00000000000..ec1a92afdde
--- /dev/null
+++ b/trunk/src/emu/cpu/minx/minx.c
@@ -0,0 +1,397 @@
+/*
+ Implementation for the Nintendo Minx CPU.
+
+ Registers (mindX13.txt):
+ 8bit: A B H L FLAGS N U V
+ 16bit: BA
+ 24bit: HL, X1, X2, NN, SP
+
+
+ "sunlab":
+ 16bit:
+ V:PC if high bit set, extended to 23 bits, upper 8 bits V
+ SP
+ BA
+ I:HL
+ (XI:)X
+ (YI:)Y
+
+ 8bit:
+ A, B, H, L
+ U - delayed jump bank. When a jump occurs, V is set to this value
+ V
+ F - flags IDLBSOCZ
+ I - Interrupt branch
+ D - Interrupt disable
+ L - low mask mode enable
+ B - bcd decimal mode enable
+ S - sign flag
+ O - overflow flag
+ C - carry flag
+ Z - zero flag
+ E - exception register
+ I
+ N
+ XI - index/extension
+ YI - index/extension
+
+TODO:
+- Add support for O and C flags in NEG8 instruction
+- Verify MUL (CE D8) and DIV (CE D9)
+- Doublecheck behaviour of CMPN instructions ( CF 60 .. CF 63 )
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "minx.h"
+
+#define FLAG_I 0x80
+#define FLAG_D 0x40
+#define FLAG_L 0x20
+#define FLAG_B 0x10
+#define FLAG_S 0x08
+#define FLAG_O 0x04
+#define FLAG_C 0x02
+#define FLAG_Z 0x01
+
+#define EXEC_X0 0x80
+#define EXEC_X1 0x40
+#define EXEC_X2 0x20
+#define EXEC_DZ 0x10
+#define EXEC_EN 0x08
+#define EXEC_04 0x04
+#define EXEC_02 0x02
+#define EXEC_01 0x01
+
+
+typedef struct {
+// MINX_CONFIG config;
+ UINT16 PC;
+ UINT16 SP;
+ UINT16 BA;
+ UINT16 HL;
+ UINT16 X;
+ UINT16 Y;
+ UINT8 U;
+ UINT8 V;
+ UINT8 F;
+ UINT8 E;
+ UINT8 N;
+ UINT8 I;
+ UINT8 XI;
+ UINT8 YI;
+ UINT8 halted;
+ UINT8 interrupt_pending;
+ device_irq_acknowledge_callback irq_callback;
+ legacy_cpu_device *device;
+ address_space *program;
+ int icount;
+} minx_state;
+
+#define RD(offset) minx->program->read_byte( offset )
+#define WR(offset,data) minx->program->write_byte( offset, data )
+#define GET_MINX_PC ( ( minx->PC & 0x8000 ) ? ( minx->V << 15 ) | (minx->PC & 0x7FFF ) : minx->PC )
+
+INLINE minx_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MINX);
+
+ return (minx_state *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+INLINE UINT16 rd16( minx_state *minx, UINT32 offset )
+{
+ return RD( offset ) | ( RD( offset + 1 ) << 8 );
+}
+
+
+INLINE void wr16( minx_state *minx, UINT32 offset, UINT16 data )
+{
+ WR( offset, ( data & 0x00FF ) );
+ WR( offset + 1, ( data >> 8 ) );
+}
+
+
+static CPU_INIT( minx )
+{
+ minx_state *minx = get_safe_token(device);
+ minx->irq_callback = irqcallback;
+ minx->device = device;
+ minx->program = device->space(AS_PROGRAM);
+ if ( device->static_config() != NULL )
+ {
+ }
+ else
+ {
+ }
+}
+
+
+static CPU_RESET( minx )
+{
+ minx_state *minx = get_safe_token(device);
+ minx->SP = minx->BA = minx->HL = minx->X = minx->Y = 0;
+ minx->U = minx->V = minx->F = minx->E = minx->I = minx->XI = minx->YI = 0;
+ minx->halted = minx->interrupt_pending = 0;
+
+ minx->PC = rd16( minx, 0 );
+}
+
+
+static CPU_EXIT( minx )
+{
+}
+
+
+INLINE UINT8 rdop( minx_state *minx )
+{
+ UINT8 op = RD( GET_MINX_PC );
+ minx->PC++;
+ return op;
+}
+
+
+INLINE UINT16 rdop16( minx_state *minx )
+{
+ UINT16 op = rdop(minx);
+ op = op | ( rdop(minx) << 8 );
+ return op;
+}
+
+
+#include "minxfunc.h"
+#include "minxopce.h"
+#include "minxopcf.h"
+#include "minxops.h"
+
+
+static CPU_EXECUTE( minx )
+{
+// UINT32 oldpc;
+ UINT8 op;
+ minx_state *minx = get_safe_token(device);
+
+ do
+ {
+ debugger_instruction_hook(device, GET_MINX_PC);
+// oldpc = GET_MINX_PC;
+
+ if ( minx->interrupt_pending )
+ {
+ minx->halted = 0;
+ if ( ! ( minx->F & 0xc0 ) && minx->U == minx->V )
+ {
+ //logerror("minx_execute(): taking IRQ\n");
+ PUSH8( minx, minx->V );
+ PUSH16( minx, minx->PC );
+ PUSH8( minx, minx->F );
+
+ /* Set Interrupt Branch flag */
+ minx->F |= 0x80;
+ minx->V = 0;
+ minx->PC = rd16( minx, minx->irq_callback( minx->device, 0 ) << 1 );
+ minx->icount -= 28; /* This cycle count is a guess */
+ }
+ }
+
+ if ( minx->halted )
+ {
+ minx->icount -= insnminx_cycles_CE[0xAE];
+ }
+ else
+ {
+ op = rdop(minx);
+ insnminx[op](minx);
+ minx->icount -= insnminx_cycles[op];
+ }
+ } while ( minx->icount > 0 );
+}
+
+
+static CPU_BURN( minx )
+{
+ minx_state *minx = get_safe_token(device);
+ minx->icount = 0;
+}
+
+
+static unsigned minx_get_reg( minx_state *minx, int regnum )
+{
+ switch( regnum )
+ {
+ case STATE_GENPC: return GET_MINX_PC;
+ case MINX_PC: return minx->PC;
+ case STATE_GENSP:
+ case MINX_SP: return minx->SP;
+ case MINX_BA: return minx->BA;
+ case MINX_HL: return minx->HL;
+ case MINX_X: return minx->X;
+ case MINX_Y: return minx->Y;
+ case MINX_U: return minx->U;
+ case MINX_V: return minx->V;
+ case MINX_F: return minx->F;
+ case MINX_E: return minx->E;
+ case MINX_N: return minx->N;
+ case MINX_I: return minx->I;
+ case MINX_XI: return minx->XI;
+ case MINX_YI: return minx->YI;
+ }
+ return 0;
+}
+
+
+static void minx_set_reg( minx_state *minx, int regnum, unsigned val )
+{
+ switch( regnum )
+ {
+ case STATE_GENPC: break;
+ case MINX_PC: minx->PC = val; break;
+ case STATE_GENSP:
+ case MINX_SP: minx->SP = val; break;
+ case MINX_BA: minx->BA = val; break;
+ case MINX_HL: minx->HL = val; break;
+ case MINX_X: minx->X = val; break;
+ case MINX_Y: minx->Y = val; break;
+ case MINX_U: minx->U = val; break;
+ case MINX_V: minx->V = val; break;
+ case MINX_F: minx->F = val; break;
+ case MINX_E: minx->E = val; break;
+ case MINX_N: minx->N = val; break;
+ case MINX_I: minx->I = val; break;
+ case MINX_XI: minx->XI = val; break;
+ case MINX_YI: minx->YI = val; break;
+ }
+}
+
+
+static void minx_set_irq_line( minx_state *minx, int irqline, int state )
+{
+ if ( state == ASSERT_LINE )
+ {
+ minx->interrupt_pending = 1;
+ }
+ else
+ {
+ minx->interrupt_pending = 0;
+ }
+}
+
+
+static CPU_SET_INFO( minx )
+{
+ minx_state *minx = get_safe_token(device);
+ switch( state )
+ {
+ case CPUINFO_INT_INPUT_STATE + 0:
+ minx_set_irq_line( minx, state - CPUINFO_INT_INPUT_STATE, info->i ); break;
+
+ case CPUINFO_INT_REGISTER + MINX_PC:
+ case CPUINFO_INT_REGISTER + MINX_SP:
+ case CPUINFO_INT_REGISTER + MINX_BA:
+ case CPUINFO_INT_REGISTER + MINX_HL:
+ case CPUINFO_INT_REGISTER + MINX_X:
+ case CPUINFO_INT_REGISTER + MINX_Y:
+ case CPUINFO_INT_REGISTER + MINX_U:
+ case CPUINFO_INT_REGISTER + MINX_V:
+ case CPUINFO_INT_REGISTER + MINX_F:
+ case CPUINFO_INT_REGISTER + MINX_E:
+ case CPUINFO_INT_REGISTER + MINX_N:
+ case CPUINFO_INT_REGISTER + MINX_I:
+ case CPUINFO_INT_REGISTER + MINX_XI:
+ case CPUINFO_INT_REGISTER + MINX_YI:
+ minx_set_reg( minx, state - CPUINFO_INT_REGISTER, info->i ); break;
+ }
+}
+
+
+CPU_GET_INFO( minx )
+{
+ minx_state *minx = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
+ switch( state )
+ {
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(minx_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0x00; break;
+ case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; 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 = 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 = 4; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 24; 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 = 0; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
+ case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; break;
+ case CPUINFO_INT_REGISTER + STATE_GENPC: info->i = GET_MINX_PC; break;
+ case CPUINFO_INT_REGISTER + STATE_GENSP:
+ case CPUINFO_INT_REGISTER + MINX_PC:
+ case CPUINFO_INT_REGISTER + MINX_SP:
+ case CPUINFO_INT_REGISTER + MINX_BA:
+ case CPUINFO_INT_REGISTER + MINX_HL:
+ case CPUINFO_INT_REGISTER + MINX_X:
+ case CPUINFO_INT_REGISTER + MINX_Y:
+ case CPUINFO_INT_REGISTER + MINX_U:
+ case CPUINFO_INT_REGISTER + MINX_V:
+ case CPUINFO_INT_REGISTER + MINX_F:
+ case CPUINFO_INT_REGISTER + MINX_E:
+ case CPUINFO_INT_REGISTER + MINX_N:
+ case CPUINFO_INT_REGISTER + MINX_I:
+ case CPUINFO_INT_REGISTER + MINX_XI:
+ case CPUINFO_INT_REGISTER + MINX_YI: info->i = minx_get_reg( minx, state - CPUINFO_INT_REGISTER ); break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = 0x0000; break;
+ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(minx); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(minx); break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(minx); break;
+ case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(minx); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(minx); break;
+ case CPUINFO_FCT_BURN: info->burn = CPU_BURN_NAME(minx); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(minx); break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &minx->icount; break;
+ case DEVINFO_STR_NAME: strcpy( info->s, "Minx" ); break;
+ case DEVINFO_STR_FAMILY: strcpy( info->s, "Nintendo Minx" ); break;
+ case DEVINFO_STR_VERSION: strcpy( info->s, "0.1" ); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy( info->s, __FILE__ ); break;
+ case DEVINFO_STR_CREDITS: strcpy( info->s, "Copyright The MESS Team." ); break;
+ case CPUINFO_STR_FLAGS:
+ sprintf( info->s, "%c%c%c%c%c%c%c%c-%c%c%c%c%c",
+ minx->F & FLAG_I ? 'I' : '.',
+ minx->F & FLAG_D ? 'D' : '.',
+ minx->F & FLAG_L ? 'L' : '.',
+ minx->F & FLAG_B ? 'B' : '.',
+ minx->F & FLAG_S ? 'S' : '.',
+ minx->F & FLAG_O ? 'O' : '.',
+ minx->F & FLAG_C ? 'C' : '.',
+ minx->F & FLAG_Z ? 'Z' : '.',
+ minx->E & EXEC_X0 ? '0' : '.',
+ minx->E & EXEC_X1 ? '1' : '.',
+ minx->E & EXEC_X2 ? '2' : '.',
+ minx->E & EXEC_DZ ? 'z' : '.',
+ minx->E & EXEC_EN ? 'E' : '.' );
+ break;
+ case CPUINFO_STR_REGISTER + MINX_PC: sprintf( info->s, "PC:%04X", minx->PC ); break;
+ case CPUINFO_STR_REGISTER + MINX_SP: sprintf( info->s, "SP:%04X", minx->SP ); break;
+ case CPUINFO_STR_REGISTER + MINX_BA: sprintf( info->s, "BA:%04X", minx->BA ); break;
+ case CPUINFO_STR_REGISTER + MINX_HL: sprintf( info->s, "HL:%04X", minx->HL ); break;
+ case CPUINFO_STR_REGISTER + MINX_X: sprintf( info->s, "X:%04X", minx->X ); break;
+ case CPUINFO_STR_REGISTER + MINX_Y: sprintf( info->s, "Y:%04X", minx->Y ); break;
+ case CPUINFO_STR_REGISTER + MINX_U: sprintf( info->s, "U:%02X", minx->U ); break;
+ case CPUINFO_STR_REGISTER + MINX_V: sprintf( info->s, "V:%02X", minx->V ); break;
+ case CPUINFO_STR_REGISTER + MINX_F: sprintf( info->s, "F:%02X", minx->F ); break;
+ case CPUINFO_STR_REGISTER + MINX_E: sprintf( info->s, "E:%02X", minx->E ); break;
+ case CPUINFO_STR_REGISTER + MINX_N: sprintf( info->s, "N:%02X", minx->N ); break;
+ case CPUINFO_STR_REGISTER + MINX_I: sprintf( info->s, "I:%02X", minx->I ); break;
+ case CPUINFO_STR_REGISTER + MINX_XI: sprintf( info->s, "XI:%02X", minx->XI ); break;
+ case CPUINFO_STR_REGISTER + MINX_YI: sprintf( info->s, "YI:%02X", minx->YI ); break;
+ }
+}
+
+DEFINE_LEGACY_CPU_DEVICE(MINX, minx);