summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/saturn/saturn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/saturn/saturn.cpp')
-rw-r--r--src/devices/cpu/saturn/saturn.cpp410
1 files changed, 410 insertions, 0 deletions
diff --git a/src/devices/cpu/saturn/saturn.cpp b/src/devices/cpu/saturn/saturn.cpp
new file mode 100644
index 00000000000..1d94a3a9ceb
--- /dev/null
+++ b/src/devices/cpu/saturn/saturn.cpp
@@ -0,0 +1,410 @@
+// license:BSD-3-Clause
+// copyright-holders:Peter Trauner,Antoine Mine
+/*****************************************************************************
+ *
+ * saturn.c
+ * portable saturn emulator interface
+ * (hp calculators)
+ *
+ *
+ *****************************************************************************/
+
+#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
+
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+// Hardware status bits
+#define XM 1 // external Modules missing
+#define SB 2 // Sticky bit
+#define SR 4 // Service Request
+#define MP 8 // Module Pulled
+
+
+
+const device_type SATURN = &device_creator<saturn_device>;
+
+
+saturn_device::saturn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, SATURN, "HP Saturn", tag, owner, clock, "saturn_cpu", __FILE__)
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0)
+ , m_out_func(*this)
+ , m_in_func(*this)
+ , m_reset_func(*this)
+ , m_config_func(*this)
+ , m_unconfig_func(*this)
+ , m_id_func(*this)
+ , m_crc_func(*this)
+ , m_rsi_func(*this)
+{
+}
+
+
+offs_t saturn_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( saturn );
+ return CPU_DISASSEMBLE_NAME(saturn)(this, buffer, pc, oprom, opram, options);
+}
+
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+
+#include "satops.inc"
+#include "sattable.inc"
+
+/*****************************************************************************
+ *
+ * Saturn CPU interface functions
+ *
+ *****************************************************************************/
+
+void saturn_device::device_start()
+{
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+
+ m_out_func.resolve_safe();
+ m_in_func.resolve_safe(0);
+ m_reset_func.resolve_safe();
+ m_config_func.resolve_safe();
+ m_unconfig_func.resolve_safe();
+ m_id_func.resolve_safe(0);
+ m_crc_func.resolve_safe();
+ m_rsi_func.resolve_safe();
+
+ memset(m_reg, 0, sizeof(m_reg));
+ memset(m_d, 0, sizeof(m_d));
+ m_pc = 0;
+ m_oldpc = 0;
+ memset(m_rstk, 0, sizeof(m_rstk));
+ m_out = 0;
+ m_carry = 0;
+ m_decimal = 0;
+ m_st = 0;
+ m_hst = 0;
+ m_nmi_state = 0;
+ m_irq_state = 0;
+ m_irq_enable = 0;
+ m_in_irq = 0;
+ m_pending_irq = 0;
+ m_sleeping = 0;
+ m_p = 0;
+
+ save_item(NAME(m_reg[R0]));
+ save_item(NAME(m_reg[R1]));
+ save_item(NAME(m_reg[R2]));
+ save_item(NAME(m_reg[R3]));
+ save_item(NAME(m_reg[R4]));
+ save_item(NAME(m_reg[A]));
+ save_item(NAME(m_reg[B]));
+ save_item(NAME(m_reg[C]));
+ save_item(NAME(m_reg[D]));
+ save_item(NAME(m_d));
+ save_item(NAME(m_pc));
+ save_item(NAME(m_oldpc));
+ save_item(NAME(m_rstk));
+ save_item(NAME(m_out));
+ save_item(NAME(m_carry));
+ save_item(NAME(m_st));
+ save_item(NAME(m_hst));
+ save_item(NAME(m_nmi_state));
+ save_item(NAME(m_irq_state));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_in_irq));
+ save_item(NAME(m_pending_irq));
+ save_item(NAME(m_sleeping));
+
+ // TODO: Register state
+ state_add( SATURN_PC, "PC", m_pc ).formatstr("%5X");
+ state_add( SATURN_D0, "D0", m_d[0] ).formatstr("%5X");
+ state_add( SATURN_D1, "D1", m_d[1] ).formatstr("%5X");
+ state_add( SATURN_A, "A", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_B, "B", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_C, "C", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_D, "D", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_R0, "R0", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_R1, "R1", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_R2, "R2", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_R3, "R3", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_R4, "R4", m_debugger_temp ).formatstr("%19s");
+ state_add( SATURN_P, "P", m_p).formatstr("%1X");
+ state_add( SATURN_OUT, "OUTP", m_out).formatstr("%3X");
+ state_add( SATURN_CARRY, "Carry", m_carry).formatstr("%1X");
+ state_add( SATURN_ST, "ST", m_st).formatstr("%4X");
+ state_add( SATURN_HST, "HST", m_hst).formatstr("%1X");
+ state_add( SATURN_RSTK0, "RSTK0", m_rstk[0]).formatstr("%5X");
+ state_add( SATURN_RSTK1, "RSTK1", m_rstk[1]).formatstr("%5X");
+ state_add( SATURN_RSTK2, "RSTK2", m_rstk[2]).formatstr("%5X");
+ state_add( SATURN_RSTK3, "RSTK3", m_rstk[3]).formatstr("%5X");
+ state_add( SATURN_RSTK4, "RSTK4", m_rstk[4]).formatstr("%5X");
+ state_add( SATURN_RSTK5, "RSTK5", m_rstk[5]).formatstr("%5X");
+ state_add( SATURN_RSTK6, "RSTK6", m_rstk[6]).formatstr("%5X");
+ state_add( SATURN_RSTK7, "RSTK7", m_rstk[7]).formatstr("%5X");
+ state_add( SATURN_IRQ_STATE, "IRQ", m_debugger_temp).formatstr("%4s");
+ state_add( SATURN_SLEEPING, "sleep", m_sleeping).formatstr("%1X");
+
+ state_add( STATE_GENPC, "GENPC", m_pc ).noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%2s").noshow();
+
+ m_icountptr = &m_icount;
+}
+
+void saturn_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+#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"
+
+ switch (entry.index())
+ {
+ case SATURN_A:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[A]) );
+ break;
+
+ case SATURN_B:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[B]) );
+ break;
+
+ case SATURN_C:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[C]) );
+ break;
+
+ case SATURN_D:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[D]) );
+ break;
+
+ case SATURN_R0:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[R0]) );
+ break;
+
+ case SATURN_R1:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[R1]) );
+ break;
+
+ case SATURN_R2:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[R2]) );
+ break;
+
+ case SATURN_R3:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[R3]) );
+ break;
+
+ case SATURN_R4:
+ strprintf(str, Reg64Format, Reg64Data(m_reg[R4]) );
+ break;
+
+ case SATURN_IRQ_STATE:
+ strprintf(str, "%c%c%c%i", m_in_irq?'S':'.', m_irq_enable?'e':'.', m_pending_irq?'p':'.', m_irq_state );
+ break;
+
+ case STATE_GENFLAGS:
+ strprintf(str, "%c%c", m_decimal?'D':'.', m_carry ? 'C':'.' );
+ break;
+ }
+}
+
+
+void saturn_device::state_import(const device_state_entry &entry)
+{
+ switch (entry.index())
+ {
+ case SATURN_A:
+ IntReg64(m_reg[A], m_debugger_temp);
+ break;
+
+ case SATURN_B:
+ IntReg64(m_reg[B], m_debugger_temp);
+ break;
+
+ case SATURN_C:
+ IntReg64(m_reg[C], m_debugger_temp);
+ break;
+
+ case SATURN_D:
+ IntReg64(m_reg[D], m_debugger_temp);
+ break;
+
+ case SATURN_R0:
+ IntReg64(m_reg[R0], m_debugger_temp);
+ break;
+
+ case SATURN_R1:
+ IntReg64(m_reg[R1], m_debugger_temp);
+ break;
+
+ case SATURN_R2:
+ IntReg64(m_reg[R2], m_debugger_temp);
+ break;
+
+ case SATURN_R3:
+ IntReg64(m_reg[R3], m_debugger_temp);
+ break;
+
+ case SATURN_R4:
+ IntReg64(m_reg[R4], m_debugger_temp);
+ break;
+ }
+}
+
+void saturn_device::state_export(const device_state_entry &entry)
+{
+ switch (entry.index())
+ {
+ case SATURN_A:
+ m_debugger_temp = Reg64Int(m_reg[A]);
+ break;
+
+ case SATURN_B:
+ m_debugger_temp = Reg64Int(m_reg[B]);
+ break;
+
+ case SATURN_C:
+ m_debugger_temp = Reg64Int(m_reg[C]);
+ break;
+
+ case SATURN_D:
+ m_debugger_temp = Reg64Int(m_reg[D]);
+ break;
+
+ case SATURN_R0:
+ m_debugger_temp = Reg64Int(m_reg[R0]);
+ break;
+
+ case SATURN_R1:
+ m_debugger_temp = Reg64Int(m_reg[R1]);
+ break;
+
+ case SATURN_R2:
+ m_debugger_temp = Reg64Int(m_reg[R2]);
+ break;
+
+ case SATURN_R3:
+ m_debugger_temp = Reg64Int(m_reg[R3]);
+ break;
+
+ case SATURN_R4:
+ m_debugger_temp = Reg64Int(m_reg[R4]);
+ break;
+ }
+}
+
+
+void saturn_device::device_reset()
+{
+ m_pc=0;
+ m_sleeping = 0;
+ m_irq_enable = 0;
+ m_in_irq = 0;
+}
+
+
+void saturn_device::saturn_take_irq()
+{
+ m_in_irq = 1; /* reset by software, using RTI */
+ m_pending_irq = 0;
+ m_icount -= 7;
+ saturn_push(m_pc);
+ m_pc=IRQ_ADDRESS;
+
+ LOG(("Saturn '%s' takes IRQ ($%04x)\n", tag(), m_pc));
+
+ standard_irq_callback(SATURN_IRQ_LINE);
+}
+
+void saturn_device::execute_run()
+{
+ do
+ {
+ m_oldpc = m_pc;
+
+ debugger_instruction_hook(this, m_pc);
+
+ if ( m_sleeping )
+ {
+ /* advance time when sleeping */
+ m_icount -= 100;
+ }
+ else
+ {
+ /* takes irq */
+ if ( m_pending_irq && (!m_in_irq) )
+ saturn_take_irq();
+
+ /* execute one instruction */
+ saturn_instruction();
+ }
+
+ } while (m_icount > 0);
+}
+
+
+void saturn_device::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case SATURN_NMI_LINE:
+ if ( state == m_nmi_state ) return;
+ m_nmi_state = state;
+ if ( state != CLEAR_LINE )
+ {
+ LOG(( "SATURN '%s' set_nmi_line(ASSERT)\n", tag()));
+ m_pending_irq = 1;
+ }
+ break;
+
+ case SATURN_IRQ_LINE:
+ if ( state == m_irq_state ) return;
+ m_irq_state = state;
+ if ( state != CLEAR_LINE && m_irq_enable )
+ {
+ LOG(( "SATURN '%s' set_irq_line(ASSERT)\n", tag()));
+ m_pending_irq = 1;
+ }
+ break;
+
+ case SATURN_WAKEUP_LINE:
+ if (m_sleeping && state==1)
+ {
+ LOG(( "SATURN '%s' set_wakeup_line(ASSERT)\n", tag()));
+ standard_irq_callback(SATURN_WAKEUP_LINE);
+ m_sleeping = 0;
+ }
+ break;
+ }
+}
+
+
+void saturn_device::IntReg64(Saturn64 r, INT64 d)
+{
+ int i;
+ for (i=0; i<16; i++)
+ r[i] = (d >> (4*i)) & 0xf;
+}
+
+
+INT64 saturn_device::Reg64Int(Saturn64 r)
+{
+ INT64 x = 0;
+ int i;
+ for (i=0; i<16; i++)
+ x |= (INT64) r[i] << (4*i);
+ return x;
+}