summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/saturn/saturn.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/saturn/saturn.c')
-rw-r--r--trunk/src/emu/cpu/saturn/saturn.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/saturn/saturn.c b/trunk/src/emu/cpu/saturn/saturn.c
new file mode 100644
index 00000000000..b03c4260923
--- /dev/null
+++ b/trunk/src/emu/cpu/saturn/saturn.c
@@ -0,0 +1,412 @@
+/*****************************************************************************
+ *
+ * saturn.c
+ * portable saturn emulator interface
+ * (hp calculators)
+ *
+ * Copyright Peter Trauner, all rights reserved.
+ *
+ * Modified by Antoine Mine'
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * peter.trauner@jk.uni-linz.ac.at
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+
+#include "saturn.h"
+
+#define R0 0
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define A 5
+#define B 6
+#define C 7
+#define D 8
+#define I 9 // invalid
+
+typedef UINT32 SaturnAdr; // 20 bit, packed
+typedef UINT8 SaturnNib; // 4 bit
+
+// 64 bit, unpacked (one nibble per byte)
+typedef SaturnNib Saturn64[16];
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+/****************************************************************************
+ * The SATURN registers.
+ ****************************************************************************/
+typedef struct _saturn_state saturn_state;
+struct _saturn_state
+{
+ saturn_cpu_core *config;
+
+ Saturn64 reg[9]; //r0,r1,r2,r3,r4,a,b,c,d
+
+ SaturnAdr d[2], pc, oldpc, rstk[8]; // 20 bit addresses
+
+ SaturnNib p; // 4 bit pointer
+
+ UINT16 out; // 12 bit (packed)
+ UINT8 carry, decimal;
+ UINT16 st; // status 16 bit
+
+ SaturnNib hst; // hardware status 4 bit
+#define XM 1 // external Modules missing
+#define SB 2 // Sticky bit
+#define SR 4 // Service Request
+#define MP 8 // Module Pulled
+
+ UINT8 nmi_state;
+ UINT8 irq_state;
+ UINT8 irq_enable; /* INTON / INTOFF */
+ UINT8 in_irq; /* already servicing IRQ */
+ UINT8 pending_irq; /* IRQ is pending */
+ UINT8 sleeping; /* low-consumption state */
+ int monitor_id;
+ int monitor_in;
+ device_irq_callback irq_callback;
+ legacy_cpu_device *device;
+ address_space *program;
+ direct_read_data *direct;
+ int icount;
+};
+
+INLINE saturn_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SATURN);
+ return (saturn_state *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+
+#include "satops.c"
+#include "sattable.c"
+
+/*****************************************************************************
+ *
+ * Saturn CPU interface functions
+ *
+ *****************************************************************************/
+
+static CPU_INIT( saturn )
+{
+ saturn_state *cpustate = get_safe_token(device);
+
+ cpustate->config = (saturn_cpu_core *) device->static_config();
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+
+ device->save_item(NAME(cpustate->reg[R0]));
+ device->save_item(NAME(cpustate->reg[R1]));
+ device->save_item(NAME(cpustate->reg[R2]));
+ device->save_item(NAME(cpustate->reg[R3]));
+ device->save_item(NAME(cpustate->reg[R4]));
+ device->save_item(NAME(cpustate->reg[A]));
+ device->save_item(NAME(cpustate->reg[B]));
+ device->save_item(NAME(cpustate->reg[C]));
+ device->save_item(NAME(cpustate->reg[D]));
+ device->save_item(NAME(cpustate->d));
+ device->save_item(NAME(cpustate->pc));
+ device->save_item(NAME(cpustate->oldpc));
+ device->save_item(NAME(cpustate->rstk));
+ device->save_item(NAME(cpustate->out));
+ device->save_item(NAME(cpustate->carry));
+ device->save_item(NAME(cpustate->st));
+ device->save_item(NAME(cpustate->hst));
+ device->save_item(NAME(cpustate->nmi_state));
+ device->save_item(NAME(cpustate->irq_state));
+ device->save_item(NAME(cpustate->irq_enable));
+ device->save_item(NAME(cpustate->in_irq));
+ device->save_item(NAME(cpustate->pending_irq));
+ device->save_item(NAME(cpustate->sleeping));
+}
+
+static CPU_RESET( saturn )
+{
+ saturn_state *cpustate = get_safe_token(device);
+
+ cpustate->pc=0;
+ cpustate->sleeping = 0;
+ cpustate->irq_enable = 0;
+ cpustate->in_irq = 0;
+}
+
+
+INLINE void saturn_take_irq(saturn_state *cpustate)
+{
+ cpustate->in_irq = 1; /* reset by software, using RTI */
+ cpustate->pending_irq = 0;
+ cpustate->icount -= 7;
+ saturn_push(cpustate, cpustate->pc);
+ cpustate->pc=IRQ_ADDRESS;
+
+ LOG(("Saturn '%s' takes IRQ ($%04x)\n", cpustate->device->tag(), cpustate->pc));
+
+ if (cpustate->irq_callback) (*cpustate->irq_callback)(cpustate->device, SATURN_IRQ_LINE);
+}
+
+static CPU_EXECUTE( saturn )
+{
+ saturn_state *cpustate = get_safe_token(device);
+
+ do
+ {
+ cpustate->oldpc = cpustate->pc;
+
+ debugger_instruction_hook(device, cpustate->pc);
+
+ if ( cpustate->sleeping )
+ {
+ /* advance time when sleeping */
+ cpustate->icount -= 100;
+ }
+ else
+ {
+ /* takes irq */
+ if ( cpustate->pending_irq && (!cpustate->in_irq) )
+ saturn_take_irq(cpustate);
+
+ /* execute one instruction */
+ saturn_instruction(cpustate);
+ }
+
+ } while (cpustate->icount > 0);
+}
+
+
+static void saturn_set_nmi_line(saturn_state *cpustate, int state)
+{
+ if ( state == cpustate->nmi_state ) return;
+ cpustate->nmi_state = state;
+ if ( state != CLEAR_LINE )
+ {
+ LOG(( "SATURN '%s' set_nmi_line(ASSERT)\n", cpustate->device->tag()));
+ cpustate->pending_irq = 1;
+ }
+}
+
+static void saturn_set_irq_line(saturn_state *cpustate, int state)
+{
+ if ( state == cpustate->irq_state ) return;
+ cpustate->irq_state = state;
+ if ( state != CLEAR_LINE && cpustate->irq_enable )
+ {
+ LOG(( "SATURN '%s' set_irq_line(ASSERT)\n", cpustate->device->tag()));
+ cpustate->pending_irq = 1;
+ }
+}
+
+static void saturn_set_wakeup_line(saturn_state *cpustate, int state)
+{
+ if (cpustate->sleeping && state==1)
+ {
+ LOG(( "SATURN '%s' set_wakeup_line(ASSERT)\n", cpustate->device->tag()));
+ if (cpustate->irq_callback) (*cpustate->irq_callback)(cpustate->device, SATURN_WAKEUP_LINE);
+ cpustate->sleeping = 0;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void IntReg64(Saturn64 r, INT64 d)
+{
+ int i;
+ for (i=0; i<16; i++)
+ r[i] = (d >> (4*i)) & 0xf;
+}
+
+
+static CPU_SET_INFO( saturn )
+{
+ saturn_state *cpustate = get_safe_token(device);
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SATURN_NMI_LINE: saturn_set_nmi_line(cpustate, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SATURN_IRQ_LINE: saturn_set_irq_line(cpustate, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SATURN_WAKEUP_LINE: saturn_set_wakeup_line(cpustate, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SATURN_PC: cpustate->pc = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_D0: cpustate->d[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_D1: cpustate->d[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_A: IntReg64(cpustate->reg[A], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_B: IntReg64(cpustate->reg[B], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_C: IntReg64(cpustate->reg[C], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_D: IntReg64(cpustate->reg[D], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_R0: IntReg64(cpustate->reg[R0], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_R1: IntReg64(cpustate->reg[R1], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_R2: IntReg64(cpustate->reg[R2], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_R3: IntReg64(cpustate->reg[R3], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_R4: IntReg64(cpustate->reg[R4], info->i); break;
+ case CPUINFO_INT_REGISTER + SATURN_P: cpustate->p = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_OUT: cpustate->out = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_CARRY: cpustate->carry = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_ST: cpustate->st = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_HST: cpustate->hst = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK0: cpustate->rstk[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK1: cpustate->rstk[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK2: cpustate->rstk[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK3: cpustate->rstk[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK4: cpustate->rstk[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK5: cpustate->rstk[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK6: cpustate->rstk[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK7: cpustate->rstk[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SATURN_SLEEPING: cpustate->sleeping = info->i;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+#define Reg64Data(s) s[15],s[14],s[13],s[12],s[11],s[10],s[9],s[8],s[7],s[6],s[5],s[4],s[3],s[2],s[1],s[0]
+#define Reg64Format "%x %x%x%x%x%x%x%x %x%x%x %x%x%x%x%x"
+
+static INT64 Reg64Int(Saturn64 r)
+{
+ INT64 x = 0;
+ int i;
+ for (i=0; i<16; i++)
+ x |= (INT64) r[i] << (4*i);
+ return x;
+}
+
+CPU_GET_INFO( saturn )
+{
+ saturn_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(saturn_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; 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 = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 20; /* 20 nibbles max */ break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 21; break;
+
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 20; 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 + SATURN_NMI_LINE: info->i = cpustate->nmi_state; break;
+ case CPUINFO_INT_INPUT_STATE + SATURN_IRQ_LINE: info->i = cpustate->irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = cpustate->oldpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SATURN_PC: info->i = cpustate->pc; break;
+ case CPUINFO_INT_REGISTER + SATURN_D0: info->i = cpustate->d[0]; break;
+ case CPUINFO_INT_REGISTER + SATURN_D1: info->i = cpustate->d[1]; break;
+
+ case CPUINFO_INT_REGISTER + SATURN_A: info->i = Reg64Int(cpustate->reg[A]); break;
+ case CPUINFO_INT_REGISTER + SATURN_B: info->i = Reg64Int(cpustate->reg[B]); break;
+ case CPUINFO_INT_REGISTER + SATURN_C: info->i = Reg64Int(cpustate->reg[C]); break;
+ case CPUINFO_INT_REGISTER + SATURN_D: info->i = Reg64Int(cpustate->reg[D]); break;
+ case CPUINFO_INT_REGISTER + SATURN_R0: info->i = Reg64Int(cpustate->reg[R0]); break;
+ case CPUINFO_INT_REGISTER + SATURN_R1: info->i = Reg64Int(cpustate->reg[R1]); break;
+ case CPUINFO_INT_REGISTER + SATURN_R2: info->i = Reg64Int(cpustate->reg[R2]); break;
+ case CPUINFO_INT_REGISTER + SATURN_R3: info->i = Reg64Int(cpustate->reg[R3]); break;
+ case CPUINFO_INT_REGISTER + SATURN_R4: info->i = Reg64Int(cpustate->reg[R4]); break;
+
+ case CPUINFO_INT_REGISTER + SATURN_P: info->i = cpustate->p; break;
+ case CPUINFO_INT_REGISTER + SATURN_OUT: info->i = cpustate->out; break;
+ case CPUINFO_INT_REGISTER + SATURN_CARRY: info->i = cpustate->carry; break;
+ case CPUINFO_INT_REGISTER + SATURN_ST: info->i = cpustate->st; break;
+ case CPUINFO_INT_REGISTER + SATURN_HST: info->i = cpustate->hst; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK0: info->i = cpustate->rstk[0]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK1: info->i = cpustate->rstk[1]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK2: info->i = cpustate->rstk[2]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK3: info->i = cpustate->rstk[3]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK4: info->i = cpustate->rstk[4]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK5: info->i = cpustate->rstk[5]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK6: info->i = cpustate->rstk[6]; break;
+ case CPUINFO_INT_REGISTER + SATURN_RSTK7: info->i = cpustate->rstk[7]; break;
+ case CPUINFO_INT_REGISTER + SATURN_SLEEPING: info->i = cpustate->sleeping;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(saturn); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(saturn); break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(saturn); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(saturn); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(saturn); 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, "Saturn"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Saturn"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0alpha"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Peter Trauner, all rights reserved."); break;
+
+ case CPUINFO_STR_REGISTER + SATURN_PC: sprintf(info->s, "PC: %.5x", cpustate->pc);break;
+ case CPUINFO_STR_REGISTER + SATURN_D0: sprintf(info->s, "D0: %.5x", cpustate->d[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_D1: sprintf(info->s, "D1: %.5x", cpustate->d[1]);break;
+ case CPUINFO_STR_REGISTER + SATURN_A: sprintf(info->s, "A: " Reg64Format, Reg64Data(cpustate->reg[A]));break;
+ case CPUINFO_STR_REGISTER + SATURN_B: sprintf(info->s, "B: " Reg64Format, Reg64Data(cpustate->reg[B]));break;
+ case CPUINFO_STR_REGISTER + SATURN_C: sprintf(info->s, "C: " Reg64Format, Reg64Data(cpustate->reg[C]));break;
+ case CPUINFO_STR_REGISTER + SATURN_D: sprintf(info->s, "D: " Reg64Format, Reg64Data(cpustate->reg[D]));break;
+ case CPUINFO_STR_REGISTER + SATURN_R0: sprintf(info->s, "R0: " Reg64Format, Reg64Data(cpustate->reg[R0]));break;
+ case CPUINFO_STR_REGISTER + SATURN_R1: sprintf(info->s, "R1: " Reg64Format, Reg64Data(cpustate->reg[R1]));break;
+ case CPUINFO_STR_REGISTER + SATURN_R2: sprintf(info->s, "R2: " Reg64Format, Reg64Data(cpustate->reg[R2]));break;
+ case CPUINFO_STR_REGISTER + SATURN_R3: sprintf(info->s, "R3: " Reg64Format, Reg64Data(cpustate->reg[R3]));break;
+ case CPUINFO_STR_REGISTER + SATURN_R4: sprintf(info->s, "R4: " Reg64Format, Reg64Data(cpustate->reg[R4]));break;
+ case CPUINFO_STR_REGISTER + SATURN_P: sprintf(info->s, "P:%x", cpustate->p);break;
+ case CPUINFO_STR_REGISTER + SATURN_OUT: sprintf(info->s, "OUT:%.3x", cpustate->out);break;
+ case CPUINFO_STR_REGISTER + SATURN_CARRY: sprintf(info->s, "Carry: %d", cpustate->carry);break;
+ case CPUINFO_STR_REGISTER + SATURN_ST: sprintf(info->s, "ST:%.4x", cpustate->st);break;
+ case CPUINFO_STR_REGISTER + SATURN_HST: sprintf(info->s, "HST:%x", cpustate->hst);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK0: sprintf(info->s, "RSTK0:%.5x", cpustate->rstk[0]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK1: sprintf(info->s, "RSTK1:%.5x", cpustate->rstk[1]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK2: sprintf(info->s, "RSTK2:%.5x", cpustate->rstk[2]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK3: sprintf(info->s, "RSTK3:%.5x", cpustate->rstk[3]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK4: sprintf(info->s, "RSTK4:%.5x", cpustate->rstk[4]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK5: sprintf(info->s, "RSTK5:%.5x", cpustate->rstk[5]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK6: sprintf(info->s, "RSTK6:%.5x", cpustate->rstk[6]);break;
+ case CPUINFO_STR_REGISTER + SATURN_RSTK7: sprintf(info->s, "RSTK7:%.5x", cpustate->rstk[7]);break;
+ case CPUINFO_STR_REGISTER + SATURN_IRQ_STATE: sprintf(info->s, "IRQ:%c%c%c%i", cpustate->in_irq?'S':'.', cpustate->irq_enable?'e':'.', cpustate->pending_irq?'p':'.', cpustate->irq_state); break;
+ case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c", cpustate->decimal?'D':'.', cpustate->carry ? 'C':'.'); break;
+ case CPUINFO_STR_REGISTER + SATURN_SLEEPING: sprintf(info->s, "sleep:%c", cpustate->sleeping?'S':'.'); break;
+ }
+}
+
+DEFINE_LEGACY_CPU_DEVICE(SATURN, saturn);