summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/tms7000
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
commitf88cefad27a1737c76e09d99c9fb43e173506081 (patch)
tree2d8167d03579c46e226471747eb4407bd00ed6fa /src/devices/cpu/tms7000
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/devices/cpu/tms7000')
-rw-r--r--src/devices/cpu/tms7000/7000dasm.c448
-rw-r--r--src/devices/cpu/tms7000/tms7000.c950
-rw-r--r--src/devices/cpu/tms7000/tms7000.h366
-rw-r--r--src/devices/cpu/tms7000/tms70op.inc716
4 files changed, 2480 insertions, 0 deletions
diff --git a/src/devices/cpu/tms7000/7000dasm.c b/src/devices/cpu/tms7000/7000dasm.c
new file mode 100644
index 00000000000..e265ef1db7e
--- /dev/null
+++ b/src/devices/cpu/tms7000/7000dasm.c
@@ -0,0 +1,448 @@
+// license:BSD-3-Clause
+// copyright-holders:Tim Lindner
+/*
+
+ TMS7000 disassembler
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "tms7000.h"
+
+enum operandtype { DONE, NONE, UI8, I8, UI16, I16, PCREL, PCABS, TRAP };
+
+struct oprandinfo {
+ char opstr[4][12];
+ operandtype decode[4];
+};
+
+struct tms7000_opcodeinfo {
+ int opcode;
+ char name[8];
+ int operand;
+ UINT32 s_flag;
+};
+
+static const oprandinfo of[] = {
+/* 00 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 01 */ { {" R%u", ",A", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 02 */ { {" R%u", ",B", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 03 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+/* 04 */ { {" %%>%X", ",A", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 05 */ { {" %%>%X", ",B", "", ""}, {UI8, NONE, DONE, DONE} },
+/* 06 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+
+/* 07 */ { {" A", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} },
+/* 08 */ { {" B", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} },
+/* 09 */ { {" %%>%02X", ",P%u", "", ""}, {UI8,UI8,DONE,DONE} },
+
+/* 10 */ { {" @>%04X", "", "", ""}, {UI16,DONE,DONE,DONE} },
+/* 11 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 12 */ { {" @>%04X(B)","", "", ""}, {UI16, DONE, DONE, DONE} },
+
+/* 13 */ { {" B,A", ",%s", "", ""}, {NONE, PCREL, DONE, DONE} },
+/* 14 */ { {" R%u,A", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 15 */ { {" R%u,B", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 16 */ { {" R%u", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} },
+/* 17 */ { {" %%>%X", ",A,%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 18 */ { {" %%>%X", ",B,%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 19 */ { {" %%>%X", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} },
+
+/* 20 */ { {" A,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 21 */ { {" B,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+/* 22 */ { {" %%>%02X", ",P%u", ",%s" ""}, {UI8, UI8, PCREL, DONE} },
+
+/* 23 */ { {"", "", "", ""}, {DONE, DONE, DONE, DONE} },
+/* 24 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+
+/* 25 */ { {" A,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+/* 26 */ { {" B,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+/* 27 */ { {" R%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} },
+
+/* 28 */ { {" %s", "", "", ""}, {PCREL, DONE, DONE, DONE} },
+
+/* 29 */ { {" A,B", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 30 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} },
+/* 31 */ { {" A,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 32 */ { {" B,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 33 */ { {" R%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 34 */ { {" R%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 35 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+/* 36 */ { {" %%>%X,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 37 */ { {" %%>%X,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 38 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} },
+
+/* 39 */ { {" %%>%04X",",R%u", "", ""}, {UI16, UI8, DONE, DONE} },
+/* 40 */ { {" %%>%04X(B)",",R%u", "", ""}, {UI16, UI8, DONE, DONE} },
+
+/* 41 */ { {" P%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 42 */ { {" P%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} },
+/* 43 */ { {" %s", "", "", ""}, {PCABS, DONE, DONE, DONE} },
+/* 44 */ { {"", "", "", ""}, {TRAP, DONE, DONE, DONE} }, /* Only For TRAP */
+
+/* 45 */ { {" *R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }
+};
+
+static const tms7000_opcodeinfo opcodes[] = {
+ {0x69, "ADC", 0, 0 },
+ {0x19, "ADC", 1, 0 },
+ {0x39, "ADC", 2, 0 },
+ {0x49, "ADC", 3, 0 },
+ {0x29, "ADC", 4, 0 },
+ {0x59, "ADC", 5, 0 },
+ {0x79, "ADC", 6, 0 },
+
+ {0x68, "ADD", 0, 0 },
+ {0x18, "ADD", 1, 0 },
+ {0x38, "ADD", 2, 0 },
+ {0x48, "ADD", 3, 0 },
+ {0x28, "ADD", 4, 0 },
+ {0x58, "ADD", 5, 0 },
+ {0x78, "ADD", 6, 0 },
+
+ {0x63, "AND", 0, 0 },
+ {0x13, "AND", 1, 0 },
+ {0x33, "AND", 2, 0 },
+ {0x43, "AND", 3, 0 },
+ {0x23, "AND", 4, 0 },
+ {0x53, "AND", 5, 0 },
+ {0x73, "AND", 6, 0 },
+
+ {0x83, "ANDP", 7, 0 },
+ {0x93, "ANDP", 8, 0 },
+ {0xA3, "ANDP", 9, 0 },
+
+ {0x8C, "BR", 43, 0 },
+ {0x9C, "BR", 45, 0 },
+ {0xAC, "BR", 12, 0 },
+
+ {0x66, "BTJO", 13, 0 },
+ {0x16, "BTJO", 14, 0 },
+ {0x36, "BTJO", 15, 0 },
+ {0x46, "BTJO", 16, 0 },
+ {0x26, "BTJO", 17, 0 },
+ {0x56, "BTJO", 18, 0 },
+ {0x76, "BTJO", 19, 0 },
+
+ {0x86, "BTJOP", 20, 0 },
+ {0x96, "BTJOP", 21, 0 },
+ {0xA6, "BTJOP", 22, 0 },
+
+ {0x67, "BTJZ", 13, 0 },
+ {0x17, "BTJZ", 14, 0 },
+ {0x37, "BTJZ", 15, 0 },
+ {0x47, "BTJZ", 16, 0 },
+ {0x27, "BTJZ", 17, 0 },
+ {0x57, "BTJZ", 18, 0 },
+ {0x77, "BTJZ", 19, 0 },
+
+ {0x87, "BTJZP", 20, 0 },
+ {0x97, "BTJZP", 21, 0 },
+ {0xA7, "BTJZP", 22, 0 },
+
+ {0x8E, "CALL", 43, DASMFLAG_STEP_OVER },
+ {0x9E, "CALL", 45, DASMFLAG_STEP_OVER },
+ {0xAE, "CALL", 12, DASMFLAG_STEP_OVER },
+
+ {0xB5, "CLR A", 23, 0 },
+ {0xC5, "CLR B", 23, 0 },
+ {0xD5, "CLR", 24, 0 },
+
+ {0xB0, "CLRC", 23, 0 },
+
+ {0x6D, "CMP", 0, 0 },
+ {0x1D, "CMP", 1, 0 },
+ {0x3D, "CMP", 2, 0 },
+ {0x4D, "CMP", 3, 0 },
+ {0x2D, "CMP", 4, 0 },
+ {0x5D, "CMP", 5, 0 },
+ {0x7D, "CMP", 6, 0 },
+
+ {0x8D, "CMPA", 10, 0 },
+ {0x9D, "CMPA", 45, 0 },
+ {0xAD, "CMPA", 12, 0 },
+
+ {0x6E, "DAC", 0, 0 },
+ {0x1E, "DAC", 1, 0 },
+ {0x3E, "DAC", 2, 0 },
+ {0x4E, "DAC", 3, 0 },
+ {0x2E, "DAC", 4, 0 },
+ {0x5E, "DAC", 5, 0 },
+ {0x7E, "DAC", 6, 0 },
+
+ {0xB2, "DEC A", 23, 0 },
+ {0xC2, "DEC B", 23, 0 },
+ {0xD2, "DEC", 24, 0 },
+
+ {0xBB, "DECD A", 23, 0 },
+ {0xCB, "DECD B", 23, 0 },
+ {0xDB, "DECD", 24, 0 },
+
+ {0x06, "DINT", 23, 0 },
+
+ {0xBA, "DJNZ", 25, 0 },
+ {0xCA, "DJNZ", 26, 0 },
+ {0xDA, "DJNZ", 27, 0 },
+
+ {0x6F, "DSB", 0, 0 },
+ {0x1F, "DSB", 1, 0 },
+ {0x3F, "DSB", 2, 0 },
+ {0x4F, "DSB", 3, 0 },
+ {0x2F, "DSB", 4, 0 },
+ {0x5F, "DSB", 5, 0 },
+ {0x7F, "DSB", 6, 0 },
+
+ {0x05, "EINT", 23, 0 },
+
+ {0x01, "IDLE", 23, 0 },
+
+ {0xB3, "INC A", 23, 0 },
+ {0xC3, "INC B", 23, 0 },
+ {0xD3, "INC", 24, 0 },
+
+ {0xB4, "INV A", 23, 0 },
+ {0xC4, "INV B", 23, 0 },
+ {0xD4, "INV", 24, 0 },
+
+ {0xE2, "JEQ", 28, 0 },
+ {0xE3, "JHS", 28, 0 },
+ {0xE7, "JL", 28, 0 },
+ {0xE0, "JMP", 28, 0 },
+ {0xE1, "JN", 28, 0 },
+ {0xE6, "JNZ", 28, 0 },
+ {0xE4, "JP", 28, 0 },
+ {0xE5, "JPI", 28, 0 },
+
+ {0x8A, "LDA", 10, 0 },
+ {0x9A, "LDA", 45, 0 },
+ {0xAA, "LDA", 12, 0 },
+
+ {0x0D, "LDSP", 23, 0 },
+
+ {0xC0, "MOV", 29, 0 },
+ {0x62, "MOV", 30, 0 },
+ {0xD0, "MOV", 31, 0 },
+ {0xD1, "MOV", 32, 0 },
+ {0x12, "MOV", 33, 0 },
+ {0x32, "MOV", 34, 0 },
+ {0x42, "MOV", 35, 0 },
+ {0x22, "MOV", 36, 0 },
+ {0x52, "MOV", 37, 0 },
+ {0x72, "MOV", 38, 0 },
+
+ {0x88, "MOVD", 39, 0 },
+ {0x98, "MOVD", 35, 0 },
+ {0xA8, "MOVD", 40, 0 },
+
+ {0x82, "MOVP", 7, 0 },
+ {0x92, "MOVP", 8, 0 },
+ {0xA2, "MOVP", 9, 0 },
+ {0x80, "MOVP", 41, 0 },
+ {0x91, "MOVP", 42, 0 },
+
+ {0x6C, "MPY", 00, 0 },
+ {0x1C, "MPY", 01, 0 },
+ {0x3C, "MPY", 02, 0 },
+ {0x4C, "MPY", 03, 0 },
+ {0x2C, "MPY", 04, 0 },
+ {0x5C, "MPY", 05, 0 },
+ {0x7C, "MPY", 06, 0 },
+
+ {0x00, "NOP", 23, 0 },
+
+ {0x64, "OR", 00, 0 },
+ {0x14, "OR", 01, 0 },
+ {0x34, "OR", 02, 0 },
+ {0x44, "OR", 03, 0 },
+ {0x24, "OR", 04, 0 },
+ {0x54, "OR", 05, 0 },
+ {0x74, "OR", 06, 0 },
+
+ {0x84, "ORP", 7, 0 },
+ {0x94, "ORP", 8, 0 },
+ {0xA4, "ORP", 9, 0 },
+
+ {0xB9, "POP A", 23, 0 },
+ {0xC9, "POP B", 23, 0 },
+ {0xD9, "POP", 24, 0 },
+ {0x08, "POP ST", 23, 0 },
+
+ {0xB8, "PUSH A", 23, 0 },
+ {0xC8, "PUSH B", 23, 0 },
+ {0xD8, "PUSH", 24, 0 },
+ {0x0E, "PUSH ST", 23, 0 },
+
+ {0x0B, "RETI", 23, DASMFLAG_STEP_OUT },
+ {0x0A, "RETS", 23, DASMFLAG_STEP_OUT },
+
+ {0xBE, "RL A", 23, 0 },
+ {0xCE, "RL B", 23, 0 },
+ {0xDE, "RL", 11, 0 },
+
+ {0xBF, "RLC A", 23, 0 },
+ {0xCF, "RLC B", 23, 0 },
+ {0xDF, "RLC", 11, 0 },
+
+ {0xBC, "RR A", 23, 0 },
+ {0xCC, "RR B", 23, 0 },
+ {0xDC, "RR", 11, 0 },
+
+ {0xBD, "RRC A", 23, 0 },
+ {0xCD, "RRC B", 23, 0 },
+ {0xDD, "RRC", 11, 0 },
+
+ {0x6B, "SBB", 0, 0 },
+ {0x1B, "SBB", 1, 0 },
+ {0x3B, "SBB", 2, 0 },
+ {0x4B, "SBB", 3, 0 },
+ {0x2B, "SBB", 4, 0 },
+ {0x5B, "SBB", 5, 0 },
+ {0x7B, "SBB", 6, 0 },
+
+ {0x07, "SETC", 23, 0 },
+
+ {0x8B, "STA", 10, 0 },
+ {0x9B, "STA", 45, 0 },
+ {0xAB, "STA", 12, 0 },
+
+ {0x09, "STSP", 23, 0 },
+
+ {0x6A, "SUB", 0, 0 },
+ {0x1A, "SUB", 1, 0 },
+ {0x3A, "SUB", 2, 0 },
+ {0x4A, "SUB", 3, 0 },
+ {0x2A, "SUB", 4, 0 },
+ {0x5A, "SUB", 5, 0 },
+ {0x7A, "SUB", 6, 0 },
+
+ {0xFF, "TRAP 0", 44, DASMFLAG_STEP_OVER },
+ {0xFE, "TRAP 1", 44, DASMFLAG_STEP_OVER },
+ {0xFD, "TRAP 2", 44, DASMFLAG_STEP_OVER },
+ {0xFC, "TRAP 3", 44, DASMFLAG_STEP_OVER },
+ {0xFB, "TRAP 4", 44, DASMFLAG_STEP_OVER },
+ {0xFA, "TRAP 5", 44, DASMFLAG_STEP_OVER },
+ {0xF9, "TRAP 6", 44, DASMFLAG_STEP_OVER },
+ {0xF8, "TRAP 7", 44, DASMFLAG_STEP_OVER },
+ {0xF7, "TRAP 8", 44, DASMFLAG_STEP_OVER },
+ {0xF6, "TRAP 9", 44, DASMFLAG_STEP_OVER },
+ {0xF5, "TRAP 10", 44, DASMFLAG_STEP_OVER },
+ {0xF4, "TRAP 11", 44, DASMFLAG_STEP_OVER },
+ {0xF3, "TRAP 12", 44, DASMFLAG_STEP_OVER },
+ {0xF2, "TRAP 13", 44, DASMFLAG_STEP_OVER },
+ {0xF1, "TRAP 14", 44, DASMFLAG_STEP_OVER },
+ {0xF0, "TRAP 15", 44, DASMFLAG_STEP_OVER },
+ {0xEF, "TRAP 16", 44, DASMFLAG_STEP_OVER },
+ {0xEE, "TRAP 17", 44, DASMFLAG_STEP_OVER },
+ {0xED, "TRAP 18", 44, DASMFLAG_STEP_OVER },
+ {0xEC, "TRAP 19", 44, DASMFLAG_STEP_OVER },
+ {0xEB, "TRAP 20", 44, DASMFLAG_STEP_OVER },
+ {0xEA, "TRAP 21", 44, DASMFLAG_STEP_OVER },
+ {0xE9, "TRAP 22", 44, DASMFLAG_STEP_OVER },
+ {0xE8, "TRAP 23", 44, DASMFLAG_STEP_OVER },
+
+ {0xB7, "SWAP A", 23, 0 },
+ {0xC7, "SWAP B", 23, 0 },
+ {0xD7, "SWAP", 11, 0 },
+
+ {0xB0, "TSTA", 23, 0 },
+ {0xC1, "TSTB", 23, 0 },
+
+ {0xB6, "XCHB A", 23, 0 },
+ {0xC6, "XCHB B", 23, 0 },
+ {0xD6, "XCHB", 11, 0 },
+
+ {0x65, "XOR", 0, 0 },
+ {0x15, "XOR", 1, 0 },
+ {0x35, "XOR", 2, 0 },
+ {0x45, "XOR", 3, 0 },
+ {0x25, "XOR", 4, 0 },
+ {0x55, "XOR", 5, 0 },
+ {0x75, "XOR", 6, 0 },
+
+ {0x85, "XORP", 7, 0 },
+ {0x95, "XORP", 8, 0 },
+ {0xA5, "XORP", 9, 0 },
+
+ {0x00, "NOP", 23, 0 }
+};
+
+CPU_DISASSEMBLE( tms7000 )
+{
+ int opcode, i/*, size = 1*/;
+ int pos = 0;
+ char tmpbuf[32];
+
+ opcode = oprom[pos++];
+
+ for( i=0; i<sizeof(opcodes) / sizeof(tms7000_opcodeinfo); i++ )
+ {
+ if( opcode == opcodes[i].opcode )
+ {
+ /* We found a match */
+
+ int j,k,vector;
+ UINT8 a;
+ INT8 b;
+ UINT16 c;
+ INT16 d;
+
+ buffer += sprintf (buffer, "%s", opcodes[i].name);
+
+ j=opcodes[i].operand;
+
+ for( k=0; k<4; k++ )
+ {
+ switch( of[j].decode[k] )
+ {
+ case DONE:
+ break;
+ case NONE:
+ buffer += sprintf (buffer, "%s", of[j].opstr[k]);
+ break;
+ case UI8:
+ a = (UINT8)opram[pos++];
+ buffer += sprintf(buffer, of[j].opstr[k], (unsigned int)a);
+ break;
+ case I8:
+ b = (INT8)opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (INT8)b);
+ break;
+ case UI16:
+ c = (UINT16)opram[pos++];
+ c <<= 8;
+ c += opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (unsigned int)c);
+ break;
+ case I16:
+ d = (INT16)opram[pos++];
+ d <<= 8;
+ d += opram[pos++];
+ buffer += sprintf (buffer, of[j].opstr[k], (signed int)d);
+ break;
+ case PCREL:
+ b = (INT8)opram[pos++];
+ sprintf(tmpbuf, "$%04X", pc+2+k+b);
+ buffer += sprintf (buffer, of[j].opstr[k], tmpbuf);
+ break;
+ case PCABS:
+ c = (UINT16)opram[pos++];
+ c <<= 8;
+ c += opram[pos++];
+ sprintf(tmpbuf, "$%04X", c);
+ buffer += sprintf (buffer, of[j].opstr[k], tmpbuf);
+ break;
+ case TRAP:
+ vector = 0xffff - ((0xff - opcode) * 2);
+ c = vector;
+ break;
+ }
+ }
+ return pos | opcodes[i].s_flag | DASMFLAG_SUPPORTED;
+ }
+ }
+
+ /* No Match */
+ strcpy (buffer, "Illegal Opcode");
+ return pos | DASMFLAG_SUPPORTED;
+}
diff --git a/src/devices/cpu/tms7000/tms7000.c b/src/devices/cpu/tms7000/tms7000.c
new file mode 100644
index 00000000000..99451e30d6b
--- /dev/null
+++ b/src/devices/cpu/tms7000/tms7000.c
@@ -0,0 +1,950 @@
+// license:BSD-3-Clause
+// copyright-holders:hap, Tim Lindner
+/*****************************************************************************
+
+ Texas Instruments TMS7000
+
+ TODO:
+ - dump CROM and emulate cpu at microinstruction level
+ - memory modes with IOCNT0, currently always running in faked full expansion mode
+ - timer event counter mode (timer control register, bit 6)
+ - TMS70x1/2 serial port and timer 3
+ - TMS70C46 DOCK-BUS comms with external pins
+ - TMS70C46 external memory mode is via "E" bus instead of configuring IOCNT0
+ - TMS70C46 clock divider
+ - TMS70C46 INT3 on keypress
+ - when they're needed, add TMS70Cx2, TMS7742, TMS77C82, SE70xxx
+
+*****************************************************************************/
+
+#include "tms7000.h"
+
+// TMS7000 is the most basic one, 128 bytes internal RAM and no internal ROM.
+// TMS7020 and TMS7040 are same, but with 2KB and 4KB internal ROM respectively.
+const device_type TMS7000 = &device_creator<tms7000_device>;
+const device_type TMS7020 = &device_creator<tms7020_device>;
+const device_type TMS7040 = &device_creator<tms7040_device>;
+
+// Exelvision (spinoff of TI) TMS7020 added one custom opcode.
+const device_type TMS7020_EXL = &device_creator<tms7020_exl_device>;
+
+// CMOS devices biggest difference in a 'real world' setting is that the power
+// requirements are much lower. This obviously has no use in software emulation.
+const device_type TMS70C00 = &device_creator<tms70c00_device>;
+const device_type TMS70C20 = &device_creator<tms70c20_device>;
+const device_type TMS70C40 = &device_creator<tms70c40_device>;
+
+// TMS70x1 features more peripheral I/O, the main addition being a serial port.
+// TMS70x2 is the same, just with twice more RAM (256 bytes)
+const device_type TMS7001 = &device_creator<tms7001_device>;
+const device_type TMS7041 = &device_creator<tms7041_device>;
+const device_type TMS7002 = &device_creator<tms7002_device>;
+const device_type TMS7042 = &device_creator<tms7042_device>;
+
+// TMS70C46 is literally a shell around a TMS70C40, with support for external
+// memory bus, auto external clock divider on slow memory, and wake-up on keypress.
+const device_type TMS70C46 = &device_creator<tms70c46_device>;
+
+// TMS70Cx2 is an update to TMS70x2 with some extra features. Due to some changes
+// in peripheral file I/O, it is not backward compatible to TMS70x2.
+
+
+// flag helpers
+#define SR_C 0x80 /* Carry */
+#define SR_N 0x40 /* Negative */
+#define SR_Z 0x20 /* Zero */
+#define SR_I 0x10 /* Interrupt */
+
+#define GET_C() (m_sr >> 7 & 1)
+#define SET_C(x) m_sr = (m_sr & 0x7f) | ((x) >> 1 & 0x80)
+#define SET_NZ(x) m_sr = (m_sr & 0x9f) | ((x) >> 1 & 0x40) | (((x) & 0xff) ? 0 : 0x20)
+#define SET_CNZ(x) m_sr = (m_sr & 0x1f) | ((x) >> 1 & 0xc0) | (((x) & 0xff) ? 0 : 0x20)
+
+
+// internal memory maps
+static ADDRESS_MAP_START(tms7000_io, AS_IO, 8, tms7000_device)
+ AM_RANGE(TMS7000_PORTB, TMS7000_PORTB) AM_READNOP
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7000_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0x0000, 0x007f) AM_RAM // 128 bytes internal RAM
+ AM_RANGE(0x0080, 0x00ff) AM_READWRITE(tms7000_unmapped_rf_r, tms7000_unmapped_rf_w)
+ AM_RANGE(0x0104, 0x0105) AM_WRITENOP // no port A write or ddr
+ AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7001_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0x0000, 0x007f) AM_RAM // 128 bytes internal RAM
+ AM_RANGE(0x0080, 0x00ff) AM_READWRITE(tms7000_unmapped_rf_r, tms7000_unmapped_rf_w)
+ AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w)
+ AM_RANGE(0x0110, 0x0117) AM_READWRITE(tms7002_pf_r, tms7002_pf_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7002_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0x0000, 0x00ff) AM_RAM // 256 bytes internal RAM
+ AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w)
+ AM_RANGE(0x0110, 0x0117) AM_READWRITE(tms7002_pf_r, tms7002_pf_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7020_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0xf000, 0xffff) AM_ROM // 2kB internal ROM
+ AM_IMPORT_FROM( tms7000_mem )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7040_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0xf000, 0xffff) AM_ROM // 4kB internal ROM
+ AM_IMPORT_FROM( tms7000_mem )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7041_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0xf000, 0xffff) AM_ROM
+ AM_IMPORT_FROM( tms7001_mem )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms7042_mem, AS_PROGRAM, 8, tms7000_device )
+ AM_RANGE(0xf000, 0xffff) AM_ROM
+ AM_IMPORT_FROM( tms7002_mem )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(tms70c46_mem, AS_PROGRAM, 8, tms70c46_device )
+ AM_RANGE(0x010c, 0x010c) AM_READWRITE(e_bus_data_r, e_bus_data_w)
+ AM_RANGE(0x010d, 0x010d) AM_NOP // ? always writes $FF before checking keyboard... maybe INT3 ack?
+ AM_RANGE(0x010e, 0x010e) AM_READWRITE(dockbus_data_r, dockbus_data_w)
+ AM_RANGE(0x010f, 0x010f) AM_READWRITE(dockbus_status_r, dockbus_status_w)
+ AM_RANGE(0x0118, 0x0118) AM_READWRITE(control_r, control_w)
+ AM_IMPORT_FROM( tms7040_mem )
+ADDRESS_MAP_END
+
+
+// device definitions
+tms7000_device::tms7000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, TMS7000, "TMS7000", tag, owner, clock, "tms7000", __FILE__),
+ m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, ADDRESS_MAP_NAME(tms7000_mem)),
+ m_io_config("io", ENDIANNESS_BIG, 8, 8, 0, ADDRESS_MAP_NAME(tms7000_io)),
+ m_info_flags(0)
+{
+}
+
+tms7000_device::tms7000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal, UINT32 info_flags, const char *shortname, const char *source)
+ : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, internal),
+ m_io_config("io", ENDIANNESS_BIG, 8, 8, 0, ADDRESS_MAP_NAME(tms7000_io)),
+ m_info_flags(info_flags)
+{
+}
+
+tms7020_device::tms7020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7020, "TMS7020", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), 0, "tms7020", __FILE__)
+{
+}
+
+tms7020_exl_device::tms7020_exl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7020_EXL, "TMS7020 (Exelvision)", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), 0, "tms7020_exl", __FILE__)
+{
+}
+
+tms7040_device::tms7040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7040, "TMS7040", tag, owner, clock, ADDRESS_MAP_NAME(tms7040_mem), 0, "tms7040", __FILE__)
+{
+}
+
+tms70c00_device::tms70c00_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS70C00, "TMS70C00", tag, owner, clock, ADDRESS_MAP_NAME(tms7000_mem), TMS7000_CHIP_IS_CMOS, "tms70c00", __FILE__)
+{
+}
+
+tms70c20_device::tms70c20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS70C20, "TMS70C20", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), TMS7000_CHIP_IS_CMOS, "tms70c20", __FILE__)
+{
+}
+
+tms70c40_device::tms70c40_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS70C40, "TMS70C40", tag, owner, clock, ADDRESS_MAP_NAME(tms7040_mem), TMS7000_CHIP_IS_CMOS, "tms70c40", __FILE__)
+{
+}
+
+tms7001_device::tms7001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7001, "TMS7001", tag, owner, clock, ADDRESS_MAP_NAME(tms7001_mem), TMS7000_CHIP_FAMILY_70X2, "tms7001", __FILE__)
+{
+}
+
+tms7041_device::tms7041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7041, "TMS7041", tag, owner, clock, ADDRESS_MAP_NAME(tms7041_mem), TMS7000_CHIP_FAMILY_70X2, "tms7041", __FILE__)
+{
+}
+
+tms7002_device::tms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7002, "TMS7002", tag, owner, clock, ADDRESS_MAP_NAME(tms7002_mem), TMS7000_CHIP_FAMILY_70X2, "tms7002", __FILE__)
+{
+}
+
+tms7042_device::tms7042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS7042, "TMS7042", tag, owner, clock, ADDRESS_MAP_NAME(tms7042_mem), TMS7000_CHIP_FAMILY_70X2, "tms7042", __FILE__)
+{
+}
+
+tms70c46_device::tms70c46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms7000_device(mconfig, TMS70C46, "TMS70C46", tag, owner, clock, ADDRESS_MAP_NAME(tms70c46_mem), TMS7000_CHIP_IS_CMOS, "tms70c46", __FILE__)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tms7000_device::device_start()
+{
+ // init/zerofill
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+ m_io = &space(AS_IO);
+
+ m_icountptr = &m_icount;
+
+ m_irq_state[TMS7000_INT1_LINE] = false;
+ m_irq_state[TMS7000_INT3_LINE] = false;
+
+ m_idle_state = false;
+ m_idle_halt = false;
+ m_pc = 0;
+ m_sp = 0;
+ m_sr = 0;
+ m_op = 0;
+
+ memset(m_io_control, 0, 3);
+
+ memset(m_port_latch, 0, 4);
+ memset(m_port_ddr, 0, 4);
+ m_port_ddr[1] = 0xff; // !
+
+ for (int tmr = 0; tmr < 2; tmr++)
+ {
+ m_timer_handle[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tms7000_device::simple_timer_cb), this));
+ m_timer_handle[tmr]->adjust(attotime::never, tmr);
+
+ m_timer_data[tmr] = 0;
+ m_timer_control[tmr] = 0;
+ m_timer_decrementer[tmr] = 0;
+ m_timer_prescaler[tmr] = 0;
+ m_timer_capture_latch[tmr] = 0;
+ }
+
+ // register for savestates
+ save_item(NAME(m_irq_state));
+ save_item(NAME(m_idle_state));
+ save_item(NAME(m_pc));
+ save_item(NAME(m_sp));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_op));
+
+ save_item(NAME(m_io_control));
+ save_item(NAME(m_port_latch));
+ save_item(NAME(m_port_ddr));
+ save_item(NAME(m_timer_data));
+ save_item(NAME(m_timer_control));
+ save_item(NAME(m_timer_decrementer));
+ save_item(NAME(m_timer_prescaler));
+ save_item(NAME(m_timer_capture_latch));
+
+ // register for debugger
+ state_add(TMS7000_PC, "PC", m_pc).formatstr("%02X");
+ state_add(TMS7000_SP, "S", m_sp).formatstr("%02X");
+ state_add(TMS7000_ST, "ST", m_sr).formatstr("%02X");
+
+ state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%02X").noshow();
+ state_add(STATE_GENSP, "GENSP", m_sp).formatstr("%02X").noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%8s").noshow();
+}
+
+void tms7000_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "%c%c%c%c%c%c%c%c",
+ m_sr & 0x80 ? 'C':'c',
+ m_sr & 0x40 ? 'N':'n',
+ m_sr & 0x20 ? 'Z':'z',
+ m_sr & 0x10 ? 'I':'i',
+ m_sr & 0x08 ? '?':'.',
+ m_sr & 0x04 ? '?':'.',
+ m_sr & 0x02 ? '?':'.',
+ m_sr & 0x01 ? '?':'.'
+ );
+ break;
+
+ default: break;
+ }
+}
+
+offs_t tms7000_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( tms7000 );
+ return CPU_DISASSEMBLE_NAME(tms7000)(this, buffer, pc, oprom, opram, options);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void tms7000_device::device_reset()
+{
+ if (m_idle_state)
+ {
+ m_pc++;
+ m_idle_state = false;
+ }
+
+ // while _RESET is asserted:
+ // clear ports
+ write_p(0x04, 0xff); // port a
+ write_p(0x06, 0xff); // port b
+
+ write_p(0x05, 0x00); // ddr a
+ write_p(0x09, 0x00); // ddr c
+ write_p(0x0b, 0x00); // ddr d
+
+ if (!chip_is_cmos())
+ {
+ write_p(0x08, 0xff); // port c
+ write_p(0x0a, 0xff); // port d
+ }
+
+ // when _RESET goes inactive (0 to 1)
+ m_sr = 0;
+
+ write_p(0x00, 0x00); // IOCNT0
+ if (chip_is_family_70x2())
+ write_p(0x10, 0x00); // IOCNT1
+
+ m_sp = 0xff;
+ m_op = 0xff;
+ execute_one(m_op);
+ m_icount -= 3; // 17 total
+}
+
+
+//-------------------------------------------------
+// interrupts
+//-------------------------------------------------
+
+void tms7000_device::execute_set_input(int extline, int state)
+{
+ if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE)
+ return;
+
+ bool irqstate = (state == CLEAR_LINE) ? false : true;
+
+ // reverse polarity (TMS70cx2-only)
+ if (m_io_control[2] & (0x01 << (4 * extline)))
+ irqstate = !irqstate;
+
+ if (m_irq_state[extline] != irqstate)
+ {
+ m_irq_state[extline] = irqstate;
+
+ // set/clear internal irq flag
+ flag_ext_interrupt(extline);
+
+ if (m_irq_state[extline])
+ {
+ // latch timer 1 on INT3
+ if (extline == TMS7000_INT3_LINE)
+ m_timer_capture_latch[0] = m_timer_decrementer[0];
+
+ // on TMS70cx2, latch timer 2 on INT1
+ if (extline == TMS7000_INT1_LINE && chip_is_family_70cx2())
+ m_timer_capture_latch[1] = m_timer_decrementer[1];
+
+ // clear external if it's edge-triggered (TMS70cx2-only)
+ if (m_io_control[2] & (0x02 << (4 * extline)))
+ m_irq_state[extline] = false;
+
+ check_interrupts();
+ }
+ }
+}
+
+void tms7000_device::flag_ext_interrupt(int extline)
+{
+ if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE)
+ return;
+
+ // set/clear for pending external interrupt
+ if (m_irq_state[extline])
+ m_io_control[0] |= (0x02 << (4 * extline));
+ else
+ m_io_control[0] &= ~(0x02 << (4 * extline));
+}
+
+void tms7000_device::check_interrupts()
+{
+ // global interrupt bit
+ if (!(m_sr & SR_I))
+ return;
+
+ // check for and handle interrupt
+ for (int irqline = 0; irqline < 5; irqline++)
+ {
+ // INT 1,2,3 are in IOCNT0 d0-d5
+ // INT 4,5 are in IOCNT1 d0-d3
+ int shift = (irqline > 2) ? irqline * 2 - 6 : irqline * 2;
+ if ((m_io_control[irqline > 2] >> shift & 3) == 3)
+ {
+ // ack
+ m_io_control[irqline > 2] &= ~(0x02 << shift);
+ if (irqline == 0 || irqline == 2)
+ flag_ext_interrupt(irqline / 2);
+
+ do_interrupt(irqline);
+ return;
+ }
+ }
+}
+
+void tms7000_device::do_interrupt(int irqline)
+{
+ if (m_idle_state)
+ {
+ m_icount -= 17;
+ m_pc++;
+ m_idle_state = false;
+ }
+ else
+ m_icount -= 19;
+
+ push8(m_sr);
+ push16(m_pc);
+ m_sr = 0;
+ m_pc = read_mem16(0xfffc - irqline * 2);
+
+ standard_irq_callback(irqline);
+}
+
+
+//-------------------------------------------------
+// timers
+//-------------------------------------------------
+
+void tms7000_device::timer_run(int tmr)
+{
+ m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f;
+
+ // run automatic timer if source is internal
+ if ((m_timer_control[tmr] & 0xe0) == 0x80)
+ {
+ attotime period = attotime::from_hz(clock()) * 8 * (m_timer_prescaler[tmr] + 1); // fOSC/16 - fOSC is freq _before_ internal clockdivider
+ m_timer_handle[tmr]->adjust(period, tmr);
+ }
+}
+
+void tms7000_device::timer_reload(int tmr)
+{
+ // stop possible running timer
+ m_timer_handle[tmr]->adjust(attotime::never, tmr);
+
+ if (m_timer_control[tmr] & 0x80)
+ {
+ m_timer_decrementer[tmr] = m_timer_data[tmr];
+ timer_run(tmr);
+ }
+}
+
+void tms7000_device::timer_tick_pre(int tmr)
+{
+ // timer prescaler underflow
+ if (--m_timer_prescaler[tmr] < 0)
+ {
+ m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f;
+ timer_tick_low(tmr);
+ }
+}
+
+void tms7000_device::timer_tick_low(int tmr)
+{
+ // timer decrementer underflow
+ if (--m_timer_decrementer[tmr] < 0)
+ {
+ timer_reload(tmr);
+
+ // set INT2/INT5
+ m_io_control[tmr] |= 0x08;
+
+ // cascaded timer
+ if (tmr == 0 && (m_timer_control[1] & 0xa0) == 0xa0)
+ timer_tick_pre(tmr + 1);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(tms7000_device::simple_timer_cb)
+{
+ int tmr = param;
+
+ // tick and restart timer
+ timer_tick_low(tmr);
+ timer_run(tmr);
+}
+
+
+//-------------------------------------------------
+// peripheral file - read/write internal ports
+// note: TMS7000 family is from $00 to $0b, TMS7002 family adds $10 to $17
+//-------------------------------------------------
+
+READ8_MEMBER(tms7000_device::tms7000_pf_r)
+{
+ switch (offset)
+ {
+ // i/o control
+ case 0x00: case 0x10:
+ return m_io_control[offset >> 4];
+
+ // timer 1/2 data
+ case 0x02: case 0x12:
+ // current decrementer value
+ return m_timer_decrementer[offset >> 4];
+
+ // timer 1 control
+ case 0x03:
+ // timer capture (latched by INT3)
+ return m_timer_capture_latch[0];
+
+ // port data
+ case 0x04: case 0x06: case 0x08: case 0x0a:
+ {
+ // note: port B is write-only, reading it returns the output value as if ddr is 0xff
+ int port = offset / 2 - 2;
+ if (!space.debugger_access())
+ return (m_io->read_byte(port) & ~m_port_ddr[port]) | (m_port_latch[port] & m_port_ddr[port]);
+ break;
+ }
+
+ // port direction (note: TMS7000 doesn't support it for port A)
+ case 0x05: case 0x09: case 0x0b:
+ return m_port_ddr[offset / 2 - 2];
+
+ default:
+ if (!space.debugger_access())
+ logerror("'%s' (%04X): tms7000_pf_r @ $%04x\n", tag(), m_pc, offset);
+ break;
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(tms7000_device::tms7000_pf_w)
+{
+ switch (offset)
+ {
+ // i/o control (IOCNT0)
+ case 0x00:
+ // d0,d2,d4: INT1,2,3 enable
+ // d1,d3,d5: INT1,2,3 flag (write 1 to clear flag)
+ // d6-d7: memory mode (currently not implemented)
+ m_io_control[0] = (m_io_control[0] & (~data & 0x2a)) | (data & 0xd5);
+
+ // possibly need to reactivate flags
+ if (data & 0x02)
+ flag_ext_interrupt(TMS7000_INT1_LINE);
+ if (data & 0x20)
+ flag_ext_interrupt(TMS7000_INT3_LINE);
+
+ check_interrupts();
+ break;
+
+ // i/o control (IOCNT1)
+ case 0x10:
+ // d0,d2: INT4,5 enable
+ // d1,d3: INT4,5 flag (write 1 to clear flag)
+ m_io_control[1] = (m_io_control[1] & (~data & 0x0a)) | (data & 0x05);
+ check_interrupts();
+ break;
+
+ // timer 1/2 data
+ case 0x02: case 0x12:
+ // decrementer reload value
+ m_timer_data[offset >> 4] = data;
+ break;
+
+ // timer 1/2 control
+ case 0x03:
+ // d5: t1: cmos low-power mode when IDLE opcode is used (not emulated)
+ // 0(normal), or 1(halt) - indicating it can only wake up with RESET or external interrupt
+ if (chip_is_cmos())
+ {
+ m_idle_halt = (data & 0x20) ? true : false;
+ if (m_idle_halt)
+ logerror("%s: CMOS low-power halt mode enabled\n", tag());
+ }
+ data &= ~0x20;
+ case 0x13:
+ // d0-d4: prescaler reload value
+ // d5: t2: cascade from t1
+ // d6: source (internal/external)
+ // d7: stop/start timer
+ m_timer_control[offset >> 4] = data;
+ timer_reload(offset >> 4);
+
+ // on cmos chip, clear INT2/INT5 as well
+ if (~data & 0x80 && chip_is_cmos())
+ m_io_control[offset >> 4] &= ~0x08;
+
+ break;
+
+ // port data (note: TMS7000 doesn't support it for port A)
+ case 0x04: case 0x06: case 0x08: case 0x0a:
+ {
+ // note: in memory expansion modes, some port output pins are used for memory strobes.
+ // this is currently ignored, since port writes will always be visible externally on peripheral expansion anyway.
+ int port = offset / 2 - 2;
+ m_io->write_byte(port, data & m_port_ddr[port]);
+ m_port_latch[port] = data;
+ break;
+ }
+
+ // port direction (note: TMS7000 doesn't support it for port A)
+ case 0x05: case 0x09: case 0x0b:
+ // note: changing port direction does not change(refresh) the output pins
+ m_port_ddr[offset / 2 - 2] = data;
+ break;
+
+ default:
+ logerror("'%s' (%04X): tms7000_pf_w @ $%04x = $%02x\n", tag(), m_pc, offset, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// execute
+//-------------------------------------------------
+
+#include "tms70op.inc"
+
+void tms7000_device::execute_run()
+{
+ check_interrupts();
+
+ do
+ {
+ debugger_instruction_hook(this, m_pc);
+
+ m_op = m_direct->read_byte(m_pc++);
+ execute_one(m_op);
+ } while (m_icount > 0);
+}
+
+void tms7000_device::execute_one(UINT8 op)
+{
+ switch (op)
+ {
+ case 0x00: nop(); break;
+ case 0x01: idle(); break;
+ case 0x05: eint(); break;
+ case 0x06: dint(); break;
+ case 0x07: setc(); break;
+ case 0x08: pop_st(); break;
+ case 0x09: stsp(); break;
+ case 0x0a: rets(); break;
+ case 0x0b: reti(); break;
+ case 0x0d: ldsp(); break;
+ case 0x0e: push_st(); break;
+
+ case 0x12: am_r2a(&tms7000_device::op_mov); break;
+ case 0x13: am_r2a(&tms7000_device::op_and); break;
+ case 0x14: am_r2a(&tms7000_device::op_or); break;
+ case 0x15: am_r2a(&tms7000_device::op_xor); break;
+ case 0x16: am_r2a(&tms7000_device::op_btjo); break;
+ case 0x17: am_r2a(&tms7000_device::op_btjz); break;
+ case 0x18: am_r2a(&tms7000_device::op_add); break;
+ case 0x19: am_r2a(&tms7000_device::op_adc); break;
+ case 0x1a: am_r2a(&tms7000_device::op_sub); break;
+ case 0x1b: am_r2a(&tms7000_device::op_sbb); break;
+ case 0x1c: am_r2a(&tms7000_device::op_mpy); break;
+ case 0x1d: am_r2a(&tms7000_device::op_cmp); break;
+ case 0x1e: am_r2a(&tms7000_device::op_dac); break;
+ case 0x1f: am_r2a(&tms7000_device::op_dsb); break;
+
+ case 0x22: am_i2a(&tms7000_device::op_mov); break;
+ case 0x23: am_i2a(&tms7000_device::op_and); break;
+ case 0x24: am_i2a(&tms7000_device::op_or); break;
+ case 0x25: am_i2a(&tms7000_device::op_xor); break;
+ case 0x26: am_i2a(&tms7000_device::op_btjo); break;
+ case 0x27: am_i2a(&tms7000_device::op_btjz); break;
+ case 0x28: am_i2a(&tms7000_device::op_add); break;
+ case 0x29: am_i2a(&tms7000_device::op_adc); break;
+ case 0x2a: am_i2a(&tms7000_device::op_sub); break;
+ case 0x2b: am_i2a(&tms7000_device::op_sbb); break;
+ case 0x2c: am_i2a(&tms7000_device::op_mpy); break;
+ case 0x2d: am_i2a(&tms7000_device::op_cmp); break;
+ case 0x2e: am_i2a(&tms7000_device::op_dac); break;
+ case 0x2f: am_i2a(&tms7000_device::op_dsb); break;
+
+ case 0x32: am_r2b(&tms7000_device::op_mov); break;
+ case 0x33: am_r2b(&tms7000_device::op_and); break;
+ case 0x34: am_r2b(&tms7000_device::op_or); break;
+ case 0x35: am_r2b(&tms7000_device::op_xor); break;
+ case 0x36: am_r2b(&tms7000_device::op_btjo); break;
+ case 0x37: am_r2b(&tms7000_device::op_btjz); break;
+ case 0x38: am_r2b(&tms7000_device::op_add); break;
+ case 0x39: am_r2b(&tms7000_device::op_adc); break;
+ case 0x3a: am_r2b(&tms7000_device::op_sub); break;
+ case 0x3b: am_r2b(&tms7000_device::op_sbb); break;
+ case 0x3c: am_r2b(&tms7000_device::op_mpy); break;
+ case 0x3d: am_r2b(&tms7000_device::op_cmp); break;
+ case 0x3e: am_r2b(&tms7000_device::op_dac); break;
+ case 0x3f: am_r2b(&tms7000_device::op_dsb); break;
+
+ case 0x42: am_r2r(&tms7000_device::op_mov); break;
+ case 0x43: am_r2r(&tms7000_device::op_and); break;
+ case 0x44: am_r2r(&tms7000_device::op_or); break;
+ case 0x45: am_r2r(&tms7000_device::op_xor); break;
+ case 0x46: am_r2r(&tms7000_device::op_btjo); break;
+ case 0x47: am_r2r(&tms7000_device::op_btjz); break;
+ case 0x48: am_r2r(&tms7000_device::op_add); break;
+ case 0x49: am_r2r(&tms7000_device::op_adc); break;
+ case 0x4a: am_r2r(&tms7000_device::op_sub); break;
+ case 0x4b: am_r2r(&tms7000_device::op_sbb); break;
+ case 0x4c: am_r2r(&tms7000_device::op_mpy); break;
+ case 0x4d: am_r2r(&tms7000_device::op_cmp); break;
+ case 0x4e: am_r2r(&tms7000_device::op_dac); break;
+ case 0x4f: am_r2r(&tms7000_device::op_dsb); break;
+
+ case 0x52: am_i2b(&tms7000_device::op_mov); break;
+ case 0x53: am_i2b(&tms7000_device::op_and); break;
+ case 0x54: am_i2b(&tms7000_device::op_or); break;
+ case 0x55: am_i2b(&tms7000_device::op_xor); break;
+ case 0x56: am_i2b(&tms7000_device::op_btjo); break;
+ case 0x57: am_i2b(&tms7000_device::op_btjz); break;
+ case 0x58: am_i2b(&tms7000_device::op_add); break;
+ case 0x59: am_i2b(&tms7000_device::op_adc); break;
+ case 0x5a: am_i2b(&tms7000_device::op_sub); break;
+ case 0x5b: am_i2b(&tms7000_device::op_sbb); break;
+ case 0x5c: am_i2b(&tms7000_device::op_mpy); break;
+ case 0x5d: am_i2b(&tms7000_device::op_cmp); break;
+ case 0x5e: am_i2b(&tms7000_device::op_dac); break;
+ case 0x5f: am_i2b(&tms7000_device::op_dsb); break;
+
+ case 0x62: am_b2a(&tms7000_device::op_mov); break;
+ case 0x63: am_b2a(&tms7000_device::op_and); break;
+ case 0x64: am_b2a(&tms7000_device::op_or); break;
+ case 0x65: am_b2a(&tms7000_device::op_xor); break;
+ case 0x66: am_b2a(&tms7000_device::op_btjo); break;
+ case 0x67: am_b2a(&tms7000_device::op_btjz); break;
+ case 0x68: am_b2a(&tms7000_device::op_add); break;
+ case 0x69: am_b2a(&tms7000_device::op_adc); break;
+ case 0x6a: am_b2a(&tms7000_device::op_sub); break;
+ case 0x6b: am_b2a(&tms7000_device::op_sbb); break;
+ case 0x6c: am_b2a(&tms7000_device::op_mpy); break;
+ case 0x6d: am_b2a(&tms7000_device::op_cmp); break;
+ case 0x6e: am_b2a(&tms7000_device::op_dac); break;
+ case 0x6f: am_b2a(&tms7000_device::op_dsb); break;
+
+ case 0x72: am_i2r(&tms7000_device::op_mov); break;
+ case 0x73: am_i2r(&tms7000_device::op_and); break;
+ case 0x74: am_i2r(&tms7000_device::op_or); break;
+ case 0x75: am_i2r(&tms7000_device::op_xor); break;
+ case 0x76: am_i2r(&tms7000_device::op_btjo); break;
+ case 0x77: am_i2r(&tms7000_device::op_btjz); break;
+ case 0x78: am_i2r(&tms7000_device::op_add); break;
+ case 0x79: am_i2r(&tms7000_device::op_adc); break;
+ case 0x7a: am_i2r(&tms7000_device::op_sub); break;
+ case 0x7b: am_i2r(&tms7000_device::op_sbb); break;
+ case 0x7c: am_i2r(&tms7000_device::op_mpy); break;
+ case 0x7d: am_i2r(&tms7000_device::op_cmp); break;
+ case 0x7e: am_i2r(&tms7000_device::op_dac); break;
+ case 0x7f: am_i2r(&tms7000_device::op_dsb); break;
+
+ case 0x80: am_p2a(&tms7000_device::op_mov); break;
+ case 0x82: am_a2p(&tms7000_device::op_mov); break;
+ case 0x83: am_a2p(&tms7000_device::op_and); break;
+ case 0x84: am_a2p(&tms7000_device::op_or); break;
+ case 0x85: am_a2p(&tms7000_device::op_xor); break;
+ case 0x86: am_a2p(&tms7000_device::op_btjo); break;
+ case 0x87: am_a2p(&tms7000_device::op_btjz); break;
+ case 0x88: movd_dir(); break;
+ case 0x8a: lda_dir(); break;
+ case 0x8b: sta_dir(); break;
+ case 0x8c: br_dir(); break;
+ case 0x8d: cmpa_dir(); break;
+ case 0x8e: call_dir(); break;
+
+ case 0x91: am_p2b(&tms7000_device::op_mov); break;
+ case 0x92: am_b2p(&tms7000_device::op_mov); break;
+ case 0x93: am_b2p(&tms7000_device::op_and); break;
+ case 0x94: am_b2p(&tms7000_device::op_or); break;
+ case 0x95: am_b2p(&tms7000_device::op_xor); break;
+ case 0x96: am_b2p(&tms7000_device::op_btjo); break;
+ case 0x97: am_b2p(&tms7000_device::op_btjz); break;
+ case 0x98: movd_ind(); break;
+ case 0x9a: lda_ind(); break;
+ case 0x9b: sta_ind(); break;
+ case 0x9c: br_ind(); break;
+ case 0x9d: cmpa_ind(); break;
+ case 0x9e: call_ind(); break;
+
+ case 0xa2: am_i2p(&tms7000_device::op_mov); break;
+ case 0xa3: am_i2p(&tms7000_device::op_and); break;
+ case 0xa4: am_i2p(&tms7000_device::op_or); break;
+ case 0xa5: am_i2p(&tms7000_device::op_xor); break;
+ case 0xa6: am_i2p(&tms7000_device::op_btjo); break;
+ case 0xa7: am_i2p(&tms7000_device::op_btjz); break;
+ case 0xa8: movd_inx(); break;
+ case 0xaa: lda_inx(); break;
+ case 0xab: sta_inx(); break;
+ case 0xac: br_inx(); break;
+ case 0xad: cmpa_inx(); break;
+ case 0xae: call_inx(); break;
+
+ case 0xb0: am_a2a(&tms7000_device::op_mov); break; // aka clrc/tsta
+ case 0xb1: am_b2a(&tms7000_device::op_mov); break; // undocumented
+ case 0xb2: am_a(&tms7000_device::op_dec); break;
+ case 0xb3: am_a(&tms7000_device::op_inc); break;
+ case 0xb4: am_a(&tms7000_device::op_inv); break;
+ case 0xb5: am_a(&tms7000_device::op_clr); break;
+ case 0xb6: am_a(&tms7000_device::op_xchb); break;
+ case 0xb7: am_a(&tms7000_device::op_swap); break;
+ case 0xb8: push_a(); break;
+ case 0xb9: pop_a(); break;
+ case 0xba: am_a(&tms7000_device::op_djnz); break;
+ case 0xbb: decd_a(); break;
+ case 0xbc: am_a(&tms7000_device::op_rr); break;
+ case 0xbd: am_a(&tms7000_device::op_rrc); break;
+ case 0xbe: am_a(&tms7000_device::op_rl); break;
+ case 0xbf: am_a(&tms7000_device::op_rlc); break;
+
+ case 0xc0: am_a2b(&tms7000_device::op_mov); break;
+ case 0xc1: am_b2b(&tms7000_device::op_mov); break; // aka tstb
+ case 0xc2: am_b(&tms7000_device::op_dec); break;
+ case 0xc3: am_b(&tms7000_device::op_inc); break;
+ case 0xc4: am_b(&tms7000_device::op_inv); break;
+ case 0xc5: am_b(&tms7000_device::op_clr); break;
+ case 0xc6: am_b(&tms7000_device::op_xchb); break; // result equivalent to tstb
+ case 0xc7: am_b(&tms7000_device::op_swap); break;
+ case 0xc8: push_b(); break;
+ case 0xc9: pop_b(); break;
+ case 0xca: am_b(&tms7000_device::op_djnz); break;
+ case 0xcb: decd_b(); break;
+ case 0xcc: am_b(&tms7000_device::op_rr); break;
+ case 0xcd: am_b(&tms7000_device::op_rrc); break;
+ case 0xce: am_b(&tms7000_device::op_rl); break;
+ case 0xcf: am_b(&tms7000_device::op_rlc); break;
+
+ case 0xd0: am_a2r(&tms7000_device::op_mov); break;
+ case 0xd1: am_b2r(&tms7000_device::op_mov); break;
+ case 0xd2: am_r(&tms7000_device::op_dec); break;
+ case 0xd3: am_r(&tms7000_device::op_inc); break;
+ case 0xd4: am_r(&tms7000_device::op_inv); break;
+ case 0xd5: am_r(&tms7000_device::op_clr); break;
+ case 0xd6: am_r(&tms7000_device::op_xchb); break;
+ case 0xd7: am_r(&tms7000_device::op_swap); break;
+ case 0xd8: push_r(); break;
+ case 0xd9: pop_r(); break;
+ case 0xda: am_r(&tms7000_device::op_djnz); break;
+ case 0xdb: decd_r(); break;
+ case 0xdc: am_r(&tms7000_device::op_rr); break;
+ case 0xdd: am_r(&tms7000_device::op_rrc); break;
+ case 0xde: am_r(&tms7000_device::op_rl); break;
+ case 0xdf: am_r(&tms7000_device::op_rlc); break;
+
+ case 0xe0: jmp(true); break;
+ case 0xe1: jmp(m_sr & SR_N); break; // jn/jlt
+ case 0xe2: jmp(m_sr & SR_Z); break; // jz/jeq
+ case 0xe3: jmp(m_sr & SR_C); break; // jc/jhs
+ case 0xe4: jmp(!(m_sr & (SR_Z | SR_N))); break; // jp/jgt
+ case 0xe5: jmp(!(m_sr & SR_N)); break; // jpz/jge - note: error in TI official documentation
+ case 0xe6: jmp(!(m_sr & SR_Z)); break; // jnz/jne
+ case 0xe7: jmp(!(m_sr & SR_C)); break; // jnc/jl
+
+ case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
+ trap(op << 1); break;
+
+ default: illegal(op); break;
+ }
+}
+
+void tms7020_exl_device::execute_one(UINT8 op)
+{
+ // TMS7020 Exelvision EXL 100 custom opcode(s)
+ if (op == 0xd7)
+ lvdp();
+ else
+ tms7000_device::execute_one(op);
+}
+
+
+//-------------------------------------------------
+// TMS70C46 specifics
+//-------------------------------------------------
+
+void tms70c46_device::device_start()
+{
+ // init/zerofill
+ m_control = 0;
+
+ // register for savestates
+ save_item(NAME(m_control));
+
+ tms7000_device::device_start();
+}
+
+void tms70c46_device::device_reset()
+{
+ m_control = 0;
+ m_io->write_byte(TMS7000_PORTE, 0xff);
+
+ tms7000_device::device_reset();
+}
+
+READ8_MEMBER(tms70c46_device::control_r)
+{
+ return m_control;
+}
+
+WRITE8_MEMBER(tms70c46_device::control_w)
+{
+ // d5: enable external databus
+ if (~m_control & data & 0x20)
+ m_io->write_byte(TMS7000_PORTE, 0xff); // go into high impedance
+
+ // d4: enable clock divider when accessing slow memory (not emulated)
+ // known fast memory areas: internal ROM/RAM, system RAM
+ // known slow memory areas: system ROM, cartridge ROM/RAM
+
+ // d0-d3(all bits?): clock divider when d4 is set and addressbus is in slow memory area
+ // needs to be measured, i just know that $30 is full speed, and $38 is about 4 times slower
+ m_control = data;
+}
+
+// DOCK-BUS: TODO..
+// right now pretend that nothing is connected
+// external pins are HD0-HD3(data), HSK(handshake), BAV(bus available)
+
+READ8_MEMBER(tms70c46_device::dockbus_status_r)
+{
+ // d0: slave _HSK
+ // d1: slave _BAV
+ // d2: unused?
+ // d3: IRQ active
+ return 0;
+}
+
+WRITE8_MEMBER(tms70c46_device::dockbus_status_w)
+{
+ // d0: master _HSK (setting it low(write 1) also clears IRQ)
+ // d1: master _BAV
+ // other bits: unused?
+}
+
+READ8_MEMBER(tms70c46_device::dockbus_data_r)
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER(tms70c46_device::dockbus_data_w)
+{
+}
diff --git a/src/devices/cpu/tms7000/tms7000.h b/src/devices/cpu/tms7000/tms7000.h
new file mode 100644
index 00000000000..92effc0d079
--- /dev/null
+++ b/src/devices/cpu/tms7000/tms7000.h
@@ -0,0 +1,366 @@
+// license:BSD-3-Clause
+// copyright-holders:hap, Tim Lindner
+/*
+
+ Texas Instruments TMS7000
+
+*/
+
+#pragma once
+
+#ifndef __TMS7000_H__
+#define __TMS7000_H__
+
+#include "emu.h"
+#include "debugger.h"
+
+
+enum { TMS7000_PC=1, TMS7000_SP, TMS7000_ST };
+
+enum
+{
+ /* note: INT2,4,5 are generated internally */
+ TMS7000_INT1_LINE = 0,
+ TMS7000_INT3_LINE
+};
+
+enum
+{
+ TMS7000_PORTA = 0, /* read-only on 70x0 */
+ TMS7000_PORTB, /* write-only */
+ TMS7000_PORTC,
+ TMS7000_PORTD,
+ TMS7000_PORTE /* TMS70C46 only */
+};
+
+// chip info flags
+#define TMS7000_CHIP_IS_CMOS 0x01
+#define TMS7000_CHIP_FAMILY_70X0 0x00
+#define TMS7000_CHIP_FAMILY_70X2 0x02
+#define TMS7000_CHIP_FAMILY_70CX2 0x04
+#define TMS7000_CHIP_FAMILY_MASK 0x06
+
+
+class tms7000_device : public cpu_device
+{
+public:
+ // construction/destruction
+ tms7000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ tms7000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal, UINT32 info_flags, const char *shortname, const char *source);
+
+ DECLARE_READ8_MEMBER(tms7000_unmapped_rf_r) { if (!space.debugger_access()) logerror("'%s' (%04X): unmapped_rf_r @ $%04x\n", tag(), m_pc, offset + 0x80); return 0; };
+ DECLARE_WRITE8_MEMBER(tms7000_unmapped_rf_w) { logerror("'%s' (%04X): unmapped_rf_w @ $%04x = $%02x\n", tag(), m_pc, offset + 0x80, data); };
+
+ DECLARE_READ8_MEMBER(tms7000_pf_r);
+ DECLARE_WRITE8_MEMBER(tms7000_pf_w);
+ DECLARE_READ8_MEMBER(tms7002_pf_r) { return tms7000_pf_r(space, offset + 0x10); }
+ DECLARE_WRITE8_MEMBER(tms7002_pf_w) { tms7000_pf_w(space, offset + 0x10, data); }
+
+ bool chip_is_cmos() { return (m_info_flags & TMS7000_CHIP_IS_CMOS) ? true : false; }
+ UINT32 chip_get_family() { return m_info_flags & TMS7000_CHIP_FAMILY_MASK; }
+ bool chip_is_family_70x0() { return chip_get_family() == TMS7000_CHIP_FAMILY_70X0; }
+ bool chip_is_family_70x2() { return chip_get_family() == TMS7000_CHIP_FAMILY_70X2; }
+ bool chip_is_family_70cx2() { return chip_get_family() == TMS7000_CHIP_FAMILY_70CX2; }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_execute_interface overrides
+ virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } // internal /2 divider
+ virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } // internal /2 divider
+ virtual UINT32 execute_min_cycles() const { return 5; }
+ virtual UINT32 execute_max_cycles() const { return 49; }
+ virtual UINT32 execute_input_lines() const { return 2; }
+ virtual void execute_run();
+ virtual void execute_set_input(int extline, int state);
+
+ // device_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); }
+
+ // device_state_interface overrides
+ void state_string_export(const device_state_entry &entry, std::string &str);
+
+ // device_disasm_interface overrides
+ virtual UINT32 disasm_min_opcode_bytes() const { return 1; }
+ virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
+ virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
+
+ virtual void execute_one(UINT8 op);
+
+ address_space_config m_program_config;
+ address_space_config m_io_config;
+
+ UINT32 m_info_flags;
+
+ address_space *m_program;
+ direct_read_data *m_direct;
+ address_space *m_io;
+ int m_icount;
+
+ bool m_irq_state[2];
+ bool m_idle_state;
+ bool m_idle_halt;
+ UINT16 m_pc;
+ UINT8 m_sp;
+ UINT8 m_sr;
+ UINT8 m_op;
+
+ UINT8 m_io_control[3];
+
+ emu_timer *m_timer_handle[2];
+ UINT8 m_timer_data[2];
+ UINT8 m_timer_control[2];
+ int m_timer_decrementer[2];
+ int m_timer_prescaler[2];
+ UINT16 m_timer_capture_latch[2];
+
+ UINT8 m_port_latch[4];
+ UINT8 m_port_ddr[4];
+
+ void flag_ext_interrupt(int extline);
+ void check_interrupts();
+ void do_interrupt(int irqline);
+
+ TIMER_CALLBACK_MEMBER(simple_timer_cb);
+ void timer_run(int tmr);
+ void timer_reload(int tmr);
+ void timer_tick_pre(int tmr);
+ void timer_tick_low(int tmr);
+
+ // internal read/write
+ inline UINT8 read_r8(UINT8 address) { return m_program->read_byte(address); }
+ inline void write_r8(UINT8 address, UINT8 data) { m_program->write_byte(address, data); }
+ inline UINT16 read_r16(UINT8 address) { return m_program->read_byte((address - 1) & 0xff) << 8 | m_program->read_byte(address); }
+ inline void write_r16(UINT8 address, UINT16 data) { m_program->write_byte((address - 1) & 0xff, data >> 8 & 0xff); m_program->write_byte(address, data & 0xff); }
+
+ inline UINT8 read_p(UINT8 address) { return m_program->read_byte(0x100 + address); }
+ inline void write_p(UINT8 address, UINT8 data) { m_program->write_byte(0x100 + address, data); }
+
+ inline UINT8 read_mem8(UINT16 address) { return m_program->read_byte(address); }
+ inline void write_mem8(UINT16 address, UINT8 data) { m_program->write_byte(address, data); }
+ inline UINT16 read_mem16(UINT16 address) { return m_program->read_byte(address) << 8 | m_program->read_byte((address + 1) & 0xffff); }
+ inline void write_mem16(UINT16 address, UINT16 data) { m_program->write_byte(address, data >> 8 & 0xff); m_program->write_byte((address + 1) & 0xffff, data & 0xff); }
+
+ inline UINT8 imm8() { return m_direct->read_byte(m_pc++); }
+ inline UINT16 imm16() { UINT16 ret = m_direct->read_byte(m_pc++) << 8; return ret | m_direct->read_byte(m_pc++); }
+
+ inline UINT8 pull8() { return m_program->read_byte(m_sp--); }
+ inline void push8(UINT8 data) { m_program->write_byte(++m_sp, data); }
+ inline UINT16 pull16() { UINT16 ret = m_program->read_byte(m_sp--); return ret | m_program->read_byte(m_sp--) << 8; }
+ inline void push16(UINT16 data) { m_program->write_byte(++m_sp, data >> 8 & 0xff); m_program->write_byte(++m_sp, data & 0xff); }
+
+ // opcode handlers
+ void br_dir();
+ void br_inx();
+ void br_ind();
+ void call_dir();
+ void call_inx();
+ void call_ind();
+ void cmpa_dir();
+ void cmpa_inx();
+ void cmpa_ind();
+ void decd_a();
+ void decd_b();
+ void decd_r();
+ void dint();
+ void eint();
+ void idle();
+ void lda_dir();
+ void lda_inx();
+ void lda_ind();
+ void ldsp();
+ void movd_dir();
+ void movd_inx();
+ void movd_ind();
+ void nop();
+ void pop_a();
+ void pop_b();
+ void pop_r();
+ void pop_st();
+ void push_a();
+ void push_b();
+ void push_r();
+ void push_st();
+ void reti();
+ void rets();
+ void setc();
+ void sta_dir();
+ void sta_inx();
+ void sta_ind();
+ void stsp();
+ void trap(UINT8 address);
+ void illegal(UINT8 op);
+
+ typedef int (tms7000_device::*op_func)(UINT8, UINT8);
+ int op_clr(UINT8 param1, UINT8 param2);
+ int op_dec(UINT8 param1, UINT8 param2);
+ int op_inc(UINT8 param1, UINT8 param2);
+ int op_inv(UINT8 param1, UINT8 param2);
+ int op_rl(UINT8 param1, UINT8 param2);
+ int op_rlc(UINT8 param1, UINT8 param2);
+ int op_rr(UINT8 param1, UINT8 param2);
+ int op_rrc(UINT8 param1, UINT8 param2);
+ int op_swap(UINT8 param1, UINT8 param2);
+ int op_xchb(UINT8 param1, UINT8 param2);
+
+ int op_adc(UINT8 param1, UINT8 param2);
+ int op_add(UINT8 param1, UINT8 param2);
+ int op_and(UINT8 param1, UINT8 param2);
+ int op_cmp(UINT8 param1, UINT8 param2);
+ int op_dac(UINT8 param1, UINT8 param2);
+ int op_dsb(UINT8 param1, UINT8 param2);
+ int op_mpy(UINT8 param1, UINT8 param2);
+ int op_mov(UINT8 param1, UINT8 param2);
+ int op_or(UINT8 param1, UINT8 param2);
+ int op_sbb(UINT8 param1, UINT8 param2);
+ int op_sub(UINT8 param1, UINT8 param2);
+ int op_xor(UINT8 param1, UINT8 param2);
+
+ inline void shortbranch(bool check);
+ inline void jmp(bool check);
+ int op_djnz(UINT8 param1, UINT8 param2);
+ int op_btjo(UINT8 param1, UINT8 param2);
+ int op_btjz(UINT8 param1, UINT8 param2);
+
+ void am_a(op_func op);
+ void am_b(op_func op);
+ void am_r(op_func op);
+ void am_a2a(op_func op);
+ void am_a2b(op_func op);
+ void am_a2r(op_func op);
+ void am_a2p(op_func op);
+ void am_b2a(op_func op);
+ void am_b2b(op_func op);
+ void am_b2r(op_func op);
+ void am_b2p(op_func op);
+ void am_r2a(op_func op);
+ void am_r2b(op_func op);
+ void am_r2r(op_func op);
+ void am_i2a(op_func op);
+ void am_i2b(op_func op);
+ void am_i2r(op_func op);
+ void am_i2p(op_func op);
+ void am_p2a(op_func op);
+ void am_p2b(op_func op);
+};
+
+
+class tms7020_device : public tms7000_device
+{
+public:
+ tms7020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms7020_exl_device : public tms7000_device
+{
+public:
+ tms7020_exl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void execute_one(UINT8 op);
+
+private:
+ void lvdp();
+};
+
+
+class tms7040_device : public tms7000_device
+{
+public:
+ tms7040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms70c00_device : public tms7000_device
+{
+public:
+ tms70c00_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms70c20_device : public tms7000_device
+{
+public:
+ tms70c20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms70c40_device : public tms7000_device
+{
+public:
+ tms70c40_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms70c46_device : public tms7000_device
+{
+public:
+ tms70c46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER(control_r);
+ DECLARE_WRITE8_MEMBER(control_w);
+
+ DECLARE_READ8_MEMBER(dockbus_status_r);
+ DECLARE_WRITE8_MEMBER(dockbus_status_w);
+ DECLARE_READ8_MEMBER(dockbus_data_r);
+ DECLARE_WRITE8_MEMBER(dockbus_data_w);
+
+ // access I/O port E if databus is disabled
+ DECLARE_READ8_MEMBER(e_bus_data_r) { return (space.debugger_access()) ? 0xff : ((m_control & 0x20) ? 0xff : m_io->read_byte(TMS7000_PORTE)); }
+ DECLARE_WRITE8_MEMBER(e_bus_data_w) { if (~m_control & 0x20) m_io->write_byte(TMS7000_PORTE, data); }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ UINT8 m_control;
+};
+
+
+class tms7001_device : public tms7000_device
+{
+public:
+ tms7001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms7041_device : public tms7000_device
+{
+public:
+ tms7041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms7002_device : public tms7000_device
+{
+public:
+ tms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+class tms7042_device : public tms7000_device
+{
+public:
+ tms7042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+extern const device_type TMS7000;
+extern const device_type TMS7020;
+extern const device_type TMS7020_EXL;
+extern const device_type TMS7040;
+extern const device_type TMS70C00;
+extern const device_type TMS70C20;
+extern const device_type TMS70C40;
+extern const device_type TMS70C46;
+extern const device_type TMS7001;
+extern const device_type TMS7041;
+extern const device_type TMS7002;
+extern const device_type TMS7042;
+
+#endif /* __TMS7000_H__ */
diff --git a/src/devices/cpu/tms7000/tms70op.inc b/src/devices/cpu/tms7000/tms70op.inc
new file mode 100644
index 00000000000..f1aeef7be3c
--- /dev/null
+++ b/src/devices/cpu/tms7000/tms70op.inc
@@ -0,0 +1,716 @@
+// license:BSD-3-Clause
+// copyright-holders:hap, Tim Lindner
+
+// TMS7000 opcode handlers
+
+// addressing modes (not all opcodes have a write cycle)
+#define WB_NO -1
+#define AM_WB(write_func, address, param1, param2) \
+ int result = (this->*op)(param1, param2); \
+ if (result > WB_NO) write_func(address, result)
+
+void tms7000_device::am_a(op_func op)
+{
+ m_icount -= 5;
+ AM_WB(write_r8, 0, read_r8(0), 0);
+}
+
+void tms7000_device::am_b(op_func op)
+{
+ m_icount -= 5;
+ AM_WB(write_r8, 1, read_r8(1), 0);
+}
+
+void tms7000_device::am_r(op_func op)
+{
+ m_icount -= 7;
+ UINT8 r = imm8();
+ AM_WB(write_r8, r, read_r8(r), 0);
+}
+
+void tms7000_device::am_a2a(op_func op)
+{
+ m_icount -= 6;
+ AM_WB(write_r8, 0, read_r8(0), read_r8(0));
+}
+
+void tms7000_device::am_a2b(op_func op)
+{
+ m_icount -= 6;
+ AM_WB(write_r8, 1, read_r8(1), read_r8(0));
+}
+
+void tms7000_device::am_a2p(op_func op)
+{
+ m_icount -= 10;
+ UINT8 r = imm8();
+ AM_WB(write_p, r, read_p(r), read_r8(0));
+}
+
+void tms7000_device::am_a2r(op_func op)
+{
+ m_icount -= 8;
+ UINT8 r = imm8();
+ AM_WB(write_r8, r, read_r8(r), read_r8(0));
+}
+
+void tms7000_device::am_b2a(op_func op)
+{
+ m_icount -= 5;
+ AM_WB(write_r8, 0, read_r8(0), read_r8(1));
+}
+
+void tms7000_device::am_b2b(op_func op)
+{
+ m_icount -= 6;
+ AM_WB(write_r8, 1, read_r8(1), read_r8(1));
+}
+
+void tms7000_device::am_b2r(op_func op)
+{
+ m_icount -= 7;
+ UINT8 r = imm8();
+ AM_WB(write_r8, r, read_r8(r), read_r8(1));
+}
+
+void tms7000_device::am_b2p(op_func op)
+{
+ m_icount -= 9;
+ UINT8 r = imm8();
+ AM_WB(write_p, r, read_p(r), read_r8(1));
+}
+
+void tms7000_device::am_r2a(op_func op)
+{
+ m_icount -= 8;
+ AM_WB(write_r8, 0, read_r8(0), read_r8(imm8()));
+}
+
+void tms7000_device::am_r2b(op_func op)
+{
+ m_icount -= 8;
+ AM_WB(write_r8, 1, read_r8(1), read_r8(imm8()));
+}
+
+void tms7000_device::am_r2r(op_func op)
+{
+ m_icount -= 10;
+ UINT8 param2 = read_r8(imm8());
+ UINT8 r = imm8();
+ AM_WB(write_r8, r, read_r8(r), param2);
+}
+
+void tms7000_device::am_i2a(op_func op)
+{
+ m_icount -= 7;
+ AM_WB(write_r8, 0, read_r8(0), imm8());
+}
+
+void tms7000_device::am_i2b(op_func op)
+{
+ m_icount -= 7;
+ AM_WB(write_r8, 1, read_r8(1), imm8());
+}
+
+void tms7000_device::am_i2r(op_func op)
+{
+ m_icount -= 9;
+ UINT8 param2 = imm8();
+ UINT8 r = imm8();
+ AM_WB(write_r8, r, read_r8(r), param2);
+}
+
+void tms7000_device::am_i2p(op_func op)
+{
+ m_icount -= 11;
+ UINT8 param2 = imm8();
+ UINT8 r = imm8();
+ AM_WB(write_p, r, read_p(r), param2);
+}
+
+void tms7000_device::am_p2a(op_func op)
+{
+ m_icount -= 9;
+ AM_WB(write_r8, 0, read_r8(0), read_p(imm8()));
+}
+
+void tms7000_device::am_p2b(op_func op)
+{
+ m_icount -= 8;
+ AM_WB(write_r8, 1, read_r8(1), read_p(imm8()));
+}
+
+
+
+// common opcodes
+// 1 param
+int tms7000_device::op_clr(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = 0;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_dec(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 - 1;
+ SET_NZ(t);
+ SET_C(~t);
+ return t;
+}
+
+int tms7000_device::op_inc(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 + 1;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_inv(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = ~param1;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_rl(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 << 1 | param1 >> 7;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_rlc(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 << 1 | GET_C();
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_rr(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 >> 1 | param1 << 8 | (param1 << 7 & 0x80);
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_rrc(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 >> 1 | param1 << 8 | GET_C() << 7;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_swap(UINT8 param1, UINT8 param2)
+{
+ m_icount -= 3;
+ UINT16 t = param1 >> 4 | param1 << 4;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_xchb(UINT8 param1, UINT8 param2)
+{
+ m_icount -= 1;
+ UINT8 t = read_r8(1);
+ SET_CNZ(t);
+ write_r8(1, param1);
+ return t;
+}
+
+// 2 params
+int tms7000_device::op_adc(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 + param2 + GET_C();
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_add(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 + param2;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_and(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = param1 & param2;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_cmp(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 - param2;
+ SET_NZ(t);
+ SET_C(~t);
+ return WB_NO;
+}
+
+int tms7000_device::op_mpy(UINT8 param1, UINT8 param2)
+{
+ m_icount -= 39;
+ UINT16 t = param1 * param2;
+ SET_CNZ(t >> 8 & 0xff);
+ write_mem16(0, t); // always writes result to regs A-B
+ return WB_NO;
+}
+
+int tms7000_device::op_mov(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = param2;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_or(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = param1 | param2;
+ SET_CNZ(t);
+ return t;
+}
+
+int tms7000_device::op_sbb(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 - param2 - (!GET_C());
+ SET_NZ(t);
+ SET_C(~t);
+ return t;
+}
+
+int tms7000_device::op_sub(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 - param2;
+ SET_NZ(t);
+ SET_C(~t);
+ return t;
+}
+
+int tms7000_device::op_xor(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = param1 ^ param2;
+ SET_CNZ(t);
+ return t;
+}
+
+// BCD arthrimetic handling
+static const UINT8 lut_bcd_out[6] = { 0x00, 0x06, 0x00, 0x66, 0x60, 0x66 };
+
+int tms7000_device::op_dac(UINT8 param1, UINT8 param2)
+{
+ m_icount -= 2;
+ int c = GET_C();
+
+ UINT8 h1 = param1 >> 4 & 0xf;
+ UINT8 l1 = param1 >> 0 & 0xf;
+ UINT8 h2 = param2 >> 4 & 0xf;
+ UINT8 l2 = param2 >> 0 & 0xf;
+
+ // compute bcd constant
+ UINT8 d = ((l1 + l2 + c) < 10) ? 0 : 1;
+ if ((h1 + h2) == 9)
+ d |= 2;
+ else if ((h1 + h2) > 9)
+ d |= 4;
+
+ UINT8 t = param1 + param2 + c + lut_bcd_out[d];
+ SET_CNZ(t);
+ if (d > 2)
+ m_sr |= SR_C;
+
+ return t;
+}
+
+int tms7000_device::op_dsb(UINT8 param1, UINT8 param2)
+{
+ m_icount -= 2;
+ int c = !GET_C();
+
+ UINT8 h1 = param1 >> 4 & 0xf;
+ UINT8 l1 = param1 >> 0 & 0xf;
+ UINT8 h2 = param2 >> 4 & 0xf;
+ UINT8 l2 = param2 >> 0 & 0xf;
+
+ // compute bcd constant
+ UINT8 d = ((l1 - c) >= l2) ? 0 : 1;
+ if (h1 == h2)
+ d |= 2;
+ else if (h1 < h2)
+ d |= 4;
+
+ UINT8 t = param1 - param2 - c - lut_bcd_out[d];
+ SET_CNZ(t);
+ if (d <= 2)
+ m_sr |= SR_C;
+
+ return t;
+}
+
+// branches
+inline void tms7000_device::shortbranch(bool check)
+{
+ m_icount -= 2;
+ INT8 d = (INT8)imm8();
+
+ if (check)
+ {
+ m_pc += d;
+ m_icount -= 2;
+ }
+}
+
+inline void tms7000_device::jmp(bool check)
+{
+ m_icount -= 3;
+ shortbranch(check);
+}
+
+int tms7000_device::op_djnz(UINT8 param1, UINT8 param2)
+{
+ UINT16 t = param1 - 1;
+ shortbranch(t != 0);
+ return t;
+}
+
+int tms7000_device::op_btjo(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = param1 & param2;
+ SET_CNZ(t);
+ shortbranch(t != 0);
+ return WB_NO;
+}
+
+int tms7000_device::op_btjz(UINT8 param1, UINT8 param2)
+{
+ UINT8 t = ~param1 & param2;
+ SET_CNZ(t);
+ shortbranch(t != 0);
+ return WB_NO;
+}
+
+
+
+// other opcodes
+// dec double
+void tms7000_device::decd_a()
+{
+ m_icount -= 9;
+ UINT32 t = read_r16(0) - 1;
+ write_r16(0, t);
+ SET_NZ(t >> 8);
+ SET_C(~(t >> 8));
+}
+
+void tms7000_device::decd_b()
+{
+ m_icount -= 9;
+ UINT32 t = read_r16(1) - 1;
+ write_r16(1, t);
+ SET_NZ(t >> 8);
+ SET_C(~(t >> 8));
+}
+
+void tms7000_device::decd_r()
+{
+ m_icount -= 11;
+ UINT8 r = imm8();
+ UINT32 t = read_r16(r) - 1;
+ write_r16(r, t);
+ SET_NZ(t >> 8);
+ SET_C(~(t >> 8));
+}
+
+// cmpa extended
+void tms7000_device::cmpa_dir()
+{
+ m_icount -= 12;
+ UINT16 t = read_r8(0) - read_mem8(imm16());
+ SET_NZ(t);
+ SET_C(~t);
+}
+
+void tms7000_device::cmpa_inx()
+{
+ m_icount -= 14;
+ UINT16 t = read_r8(0) - read_mem8(imm16() + read_r8(1));
+ SET_NZ(t);
+ SET_C(~t);
+}
+
+void tms7000_device::cmpa_ind()
+{
+ m_icount -= 11;
+ UINT16 t = read_r8(0) - read_mem8(read_r16(imm8()));
+ SET_NZ(t);
+ SET_C(~t);
+}
+
+// lda extended
+void tms7000_device::lda_dir()
+{
+ m_icount -= 11;
+ UINT8 t = read_mem8(imm16());
+ write_r8(0, t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::lda_inx()
+{
+ m_icount -= 13;
+ UINT8 t = read_mem8(imm16() + read_r8(1));
+ write_r8(0, t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::lda_ind()
+{
+ m_icount -= 10;
+ UINT8 t = read_mem8(read_r16(imm8()));
+ write_r8(0, t);
+ SET_CNZ(t);
+}
+
+// sta extended
+void tms7000_device::sta_dir()
+{
+ m_icount -= 11;
+ UINT8 t = read_r8(0);
+ write_mem8(imm16(), t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::sta_inx()
+{
+ m_icount -= 13;
+ UINT8 t = read_r8(0);
+ write_mem8(imm16() + read_r8(1), t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::sta_ind()
+{
+ m_icount -= 10;
+ UINT8 t = read_r8(0);
+ write_mem8(read_r16(imm8()), t);
+ SET_CNZ(t);
+}
+
+// mov double
+void tms7000_device::movd_dir()
+{
+ m_icount -= 15;
+ UINT16 t = imm16();
+ write_r16(imm8(), t);
+ SET_CNZ(t >> 8 & 0xff);
+}
+
+void tms7000_device::movd_inx()
+{
+ m_icount -= 17;
+ UINT16 t = imm16() + read_r8(1);
+ write_r16(imm8(), t);
+ SET_CNZ(t >> 8 & 0xff);
+}
+
+void tms7000_device::movd_ind()
+{
+ m_icount -= 14;
+ UINT16 t = read_r16(imm8());
+ write_r16(imm8(), t);
+ SET_CNZ(t >> 8 & 0xff);
+}
+
+// long branch
+void tms7000_device::br_dir()
+{
+ m_icount -= 10;
+ m_pc = imm16();
+}
+
+void tms7000_device::br_inx()
+{
+ m_icount -= 12;
+ m_pc = imm16() + read_r8(1);
+}
+
+void tms7000_device::br_ind()
+{
+ m_icount -= 9;
+ m_pc = read_r16(imm8());
+}
+
+// call/return
+void tms7000_device::call_dir()
+{
+ m_icount -= 14;
+ UINT16 t = imm16();
+ push16(m_pc);
+ m_pc = t;
+}
+
+void tms7000_device::call_inx()
+{
+ m_icount -= 16;
+ UINT16 t = imm16() + read_r8(1);
+ push16(m_pc);
+ m_pc = t;
+}
+
+void tms7000_device::call_ind()
+{
+ m_icount -= 13;
+ UINT16 t = read_r16(imm8());
+ push16(m_pc);
+ m_pc = t;
+}
+
+void tms7000_device::trap(UINT8 address)
+{
+ m_icount -= 14;
+ push16(m_pc);
+ m_pc = read_mem16(0xff00 | address);
+}
+
+void tms7000_device::reti()
+{
+ m_icount -= 9;
+ m_pc = pull16();
+ m_sr = pull8() & 0xf0;
+ check_interrupts();
+}
+
+void tms7000_device::rets()
+{
+ m_icount -= 7;
+ m_pc = pull16();
+}
+
+// pop
+void tms7000_device::pop_a()
+{
+ m_icount -= 6;
+ UINT8 t = pull8();
+ write_r8(0, t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::pop_b()
+{
+ m_icount -= 6;
+ UINT8 t = pull8();
+ write_r8(1, t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::pop_r()
+{
+ m_icount -= 8;
+ UINT8 t = pull8();
+ write_r8(imm8(), t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::pop_st()
+{
+ m_icount -= 6;
+ m_sr = pull8() & 0xf0;
+ check_interrupts();
+}
+
+// push
+void tms7000_device::push_a()
+{
+ m_icount -= 6;
+ UINT8 t = read_r8(0);
+ push8(t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::push_b()
+{
+ m_icount -= 6;
+ UINT8 t = read_r8(1);
+ push8(t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::push_r()
+{
+ m_icount -= 8;
+ UINT8 t = read_r8(imm8());
+ push8(t);
+ SET_CNZ(t);
+}
+
+void tms7000_device::push_st()
+{
+ m_icount -= 6;
+ push8(m_sr);
+}
+
+// other
+void tms7000_device::nop()
+{
+ m_icount -= 5;
+}
+
+void tms7000_device::idle()
+{
+ m_icount -= 6;
+ m_pc--;
+ m_idle_state = true;
+}
+
+void tms7000_device::dint()
+{
+ m_icount -= 5;
+ m_sr &= ~(SR_N | SR_Z | SR_C | SR_I);
+}
+
+void tms7000_device::eint()
+{
+ m_icount -= 5;
+ m_sr |= (SR_N | SR_Z | SR_C | SR_I);
+ check_interrupts();
+}
+
+void tms7000_device::ldsp()
+{
+ m_icount -= 5;
+ m_sp = read_r8(1);
+}
+
+void tms7000_device::stsp()
+{
+ m_icount -= 6;
+ write_r8(1, m_sp);
+}
+
+void tms7000_device::setc()
+{
+ m_icount -= 5;
+ m_sr = (m_sr & ~SR_N) | SR_C | SR_Z;
+}
+
+// not standard
+void tms7020_exl_device::lvdp()
+{
+ /* on EXL100, opcode D7 ?? (SWAP R) was changed to LVDP, mostly equivalent to:
+ * MOVP P40,xx
+ * MOVP P36,A
+ */
+ m_icount -= 10; // TODO: check real timing
+ imm8(); // always 0x28? discarded?
+ read_p(0x28);
+ UINT8 t = read_p(0x24);
+ write_r8(0, t);
+ SET_CNZ(t);
+}
+
+// illegal opcode handling
+void tms7000_device::illegal(UINT8 op)
+{
+ m_icount -= 5; // guessed
+ logerror("%s: illegal opcode $%02X @ $%04x\n", tag(), op, m_pc);
+}