summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/lh5801/lh5801.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/lh5801/lh5801.c')
-rw-r--r--trunk/src/emu/cpu/lh5801/lh5801.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/lh5801/lh5801.c b/trunk/src/emu/cpu/lh5801/lh5801.c
new file mode 100644
index 00000000000..854e276f90a
--- /dev/null
+++ b/trunk/src/emu/cpu/lh5801/lh5801.c
@@ -0,0 +1,348 @@
+/*****************************************************************************
+ *
+ * Copyright Peter Trauner, all rights reserved.
+ *
+ * - 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.
+ *
+ *
+ * 02/2011 (Sandro Ronco)
+ * - Added IO_SPACE and updated all access in ME1 memory for use it.
+ * - Implemented interrupts.
+ * - Fixed the flags in the ROL/ROR/SHL/SHR opcodes.
+ * - Fixed decimal add/sub opcodes.
+ *
+ * based on info found on an artikel for the tandy trs80 pc2
+ * and on "PC1500 Technical reference manual"
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+
+#include "lh5801.h"
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+enum
+{
+ LH5801_T=1,
+ LH5801_P,
+ LH5801_S,
+ LH5801_U,
+ LH5801_X,
+ LH5801_Y,
+ LH5801_A,
+
+ LH5801_TM,
+ LH5801_IN,
+ LH5801_BF,
+ LH5801_PU,
+ LH5801_PV,
+ LH5801_DP,
+ LH5801_IRQ_STATE
+};
+
+typedef struct _lh5801_state lh5801_state;
+struct _lh5801_state
+{
+ const lh5801_cpu_core *config;
+ legacy_cpu_device *device;
+ address_space *program; //ME0
+ address_space *io; //ME1
+ direct_read_data *direct;
+
+ PAIR s, p, u, x, y;
+ int tm; //9 bit
+
+ UINT8 t, a;
+
+ int bf, dp, pu, pv;
+
+ UINT16 oldpc;
+
+ int irq_state;
+
+ UINT8 ir_flipflop[3]; //interrupt request flipflop: IR0, IR1, IR2
+ int lines_status[2]; //MI and NMI lines status
+
+ int idle;
+ int icount;
+};
+
+INLINE lh5801_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == LH5801);
+ return (lh5801_state *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+#define P cpustate->p.w.l
+#define S cpustate->s.w.l
+#define U cpustate->u.w.l
+#define UL cpustate->u.b.l
+#define UH cpustate->u.b.h
+#define X cpustate->x.w.l
+#define XL cpustate->x.b.l
+#define XH cpustate->x.b.h
+#define Y cpustate->y.w.l
+#define YL cpustate->y.b.l
+#define YH cpustate->y.b.h
+
+#define C 0x01
+#define IE 0x02
+#define Z 0x04
+#define V 0x08
+#define H 0x10
+
+/***************************************************************
+ * include the opcode macros, functions and tables
+ ***************************************************************/
+#include "5801tbl.c"
+
+static CPU_INIT( lh5801 )
+{
+ lh5801_state *cpustate = get_safe_token(device);
+
+ memset(cpustate, 0, sizeof(*cpustate));
+ cpustate->config = (const lh5801_cpu_core *) device->static_config();
+ cpustate->device = device;
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->io = device->space(AS_IO);
+ cpustate->direct = &cpustate->program->direct();
+}
+
+static CPU_RESET( lh5801 )
+{
+ lh5801_state *cpustate = get_safe_token(device);
+
+ P = (cpustate->program->read_byte(0xfffe)<<8) | cpustate->program->read_byte(0xffff);
+
+ cpustate->idle=0;
+
+ memset(cpustate->ir_flipflop, 0, sizeof(cpustate->ir_flipflop));
+ memset(cpustate->lines_status, 0, sizeof(cpustate->lines_status));
+}
+
+
+static void check_irq(device_t *device)
+{
+ lh5801_state *cpustate = get_safe_token(device);
+
+ if (cpustate->ir_flipflop[0])
+ {
+ //NMI interrupt
+ cpustate->ir_flipflop[0] = 0;
+ lh5801_push(cpustate,cpustate->t);
+ cpustate->t&=~IE;
+ lh5801_push_word(cpustate,P);
+ P = (cpustate->program->read_byte(0xfffc)<<8) | cpustate->program->read_byte(0xfffd);
+ }
+ else if (cpustate->ir_flipflop[1] && (cpustate->t & IE))
+ {
+ //counter interrupt (counter not yet implemented)
+ cpustate->ir_flipflop[1] = 0;
+ lh5801_push(cpustate,cpustate->t);
+ cpustate->t&=~IE;
+ lh5801_push_word(cpustate,P);
+ P = (cpustate->program->read_byte(0xfffa)<<8) | cpustate->program->read_byte(0xfffb);
+ }
+ else if (cpustate->ir_flipflop[2] && (cpustate->t & IE))
+ {
+ //MI interrupt
+ cpustate->ir_flipflop[2] = 0;
+ lh5801_push(cpustate, cpustate->t);
+ cpustate->t&=~IE;
+ lh5801_push_word(cpustate, P);
+ P = (cpustate->program->read_byte(0xfff8)<<8) | cpustate->program->read_byte(0xfff9);
+ }
+}
+
+
+static CPU_EXECUTE( lh5801 )
+{
+ lh5801_state *cpustate = get_safe_token(device);
+
+ do
+ {
+ check_irq(device);
+
+ if (cpustate->idle)
+ cpustate->icount = 0;
+ else
+ {
+ cpustate->oldpc = P;
+
+ debugger_instruction_hook(device, P);
+ lh5801_instruction(cpustate);
+ }
+
+ } while (cpustate->icount > 0);
+}
+
+static void set_irq_line(lh5801_state *cpustate, int irqline, int state)
+{
+ switch( irqline)
+ {
+ case LH5801_LINE_MI:
+ if (cpustate->lines_status[0] == CLEAR_LINE && state == ASSERT_LINE)
+ {
+ cpustate->idle = 0;
+ cpustate->ir_flipflop[2] = 1;
+ }
+
+ cpustate->lines_status[0] = state;
+ break;
+ case INPUT_LINE_NMI:
+ if (cpustate->lines_status[1] == CLEAR_LINE && state == ASSERT_LINE)
+ {
+ cpustate->idle = 0;
+ cpustate->ir_flipflop[0] = 1;
+ }
+
+ cpustate->lines_status[1] = state;
+ break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static CPU_SET_INFO( lh5801 )
+{
+ lh5801_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 + LH5801_LINE_MI: set_irq_line(cpustate, LH5801_LINE_MI, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(cpustate, INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + LH5801_P: P = info->i; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + LH5801_S: S = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_U: U = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_X: X = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_Y: Y = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_T: cpustate->t = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_TM: cpustate->tm = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_BF: cpustate->bf = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_PV: cpustate->pv = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_PU: cpustate->pu = info->i; break;
+ case CPUINFO_INT_REGISTER + LH5801_DP: cpustate->dp = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+CPU_GET_INFO( lh5801 )
+{
+ lh5801_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(lh5801_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; 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 = 5; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 2; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 19; break;
+
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16; 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 = 16; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE: info->i = cpustate->irq_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = cpustate->oldpc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + LH5801_P: info->i = P; break;
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + LH5801_S: info->i = S; break;
+ case CPUINFO_INT_REGISTER + LH5801_U: info->i = U; break;
+ case CPUINFO_INT_REGISTER + LH5801_X: info->i = X; break;
+ case CPUINFO_INT_REGISTER + LH5801_Y: info->i = Y; break;
+ case CPUINFO_INT_REGISTER + LH5801_T: info->i = cpustate->t; break;
+ case CPUINFO_INT_REGISTER + LH5801_TM: info->i = cpustate->tm; break;
+ case CPUINFO_INT_REGISTER + LH5801_IN: info->i = cpustate->config->in(device); break;
+ case CPUINFO_INT_REGISTER + LH5801_BF: info->i = cpustate->bf; break;
+ case CPUINFO_INT_REGISTER + LH5801_PV: info->i = cpustate->pv; break;
+ case CPUINFO_INT_REGISTER + LH5801_PU: info->i = cpustate->pu; break;
+ case CPUINFO_INT_REGISTER + LH5801_DP: info->i = cpustate->dp; 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(lh5801); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(lh5801); break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(lh5801); break;
+ case CPUINFO_FCT_EXIT: info->exit = NULL; break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(lh5801); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(lh5801); 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, "LH5801"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "LH5801"); 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_FLAGS:
+ sprintf(info->s, "%s%s%s%s%s%s%s%s",
+ cpustate->t&0x80?"1":"0",
+ cpustate->t&0x40?"1":"0",
+ cpustate->t&0x20?"1":"0",
+ cpustate->t&0x10?"H":".",
+ cpustate->t&8?"V":".",
+ cpustate->t&4?"Z":".",
+ cpustate->t&2?"I":".",
+ cpustate->t&1?"C":".");
+ break;
+
+ case CPUINFO_STR_REGISTER + LH5801_P: sprintf(info->s, "P:%04X", cpustate->p.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_S: sprintf(info->s, "S:%04X", cpustate->s.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_U: sprintf(info->s, "U:%04X", cpustate->u.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_X: sprintf(info->s, "X:%04X", cpustate->x.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_Y: sprintf(info->s, "Y:%04X", cpustate->y.w.l); break;
+ case CPUINFO_STR_REGISTER + LH5801_T: sprintf(info->s, "T:%02X", cpustate->t); break;
+ case CPUINFO_STR_REGISTER + LH5801_A: sprintf(info->s, "A:%02X", cpustate->a); break;
+ case CPUINFO_STR_REGISTER + LH5801_TM: sprintf(info->s, "TM:%03X", cpustate->tm); break;
+ case CPUINFO_STR_REGISTER + LH5801_IN: sprintf(info->s, "IN:%02X", cpustate->config->in(device)); break;
+ case CPUINFO_STR_REGISTER + LH5801_PV: sprintf(info->s, "PV:%04X", cpustate->pv); break;
+ case CPUINFO_STR_REGISTER + LH5801_PU: sprintf(info->s, "PU:%04X", cpustate->pu); break;
+ case CPUINFO_STR_REGISTER + LH5801_BF: sprintf(info->s, "BF:%04X", cpustate->bf); break;
+ case CPUINFO_STR_REGISTER + LH5801_DP: sprintf(info->s, "DP:%04X", cpustate->dp); break;
+ }
+}
+
+DEFINE_LEGACY_CPU_DEVICE(LH5801, lh5801);