summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/tms9900
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/emu/cpu/tms9900
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/emu/cpu/tms9900')
-rw-r--r--src/emu/cpu/tms9900/9900dasm.c812
-rw-r--r--src/emu/cpu/tms9900/99xxcore.h5319
-rw-r--r--src/emu/cpu/tms9900/ti990_10.c148
-rw-r--r--src/emu/cpu/tms9900/ti990_10.h61
-rw-r--r--src/emu/cpu/tms9900/tms9900.c2736
-rw-r--r--src/emu/cpu/tms9900/tms9900.h403
-rw-r--r--src/emu/cpu/tms9900/tms9980a.c300
-rw-r--r--src/emu/cpu/tms9900/tms9980a.h56
-rw-r--r--src/emu/cpu/tms9900/tms9995.c3466
-rw-r--r--src/emu/cpu/tms9900/tms9995.h446
-rw-r--r--src/emu/cpu/tms9900/tms99com.h93
11 files changed, 0 insertions, 13840 deletions
diff --git a/src/emu/cpu/tms9900/9900dasm.c b/src/emu/cpu/tms9900/9900dasm.c
deleted file mode 100644
index 7b3153e6c4c..00000000000
--- a/src/emu/cpu/tms9900/9900dasm.c
+++ /dev/null
@@ -1,812 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Raphael Nabet
-/*****************************************************************************
- *
- * 9900dasm.c
- * TMS 9900 family disassembler
- *
- * Copyright Raphael Nabet
- * Based on previous work Copyright John Butler.
- * Based on 6502dasm.c 6502/65c02/6510 disassembler by Juergen Buchmueller
- *
- * - 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. :)
- * - 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 "tms9900.h"
-
-#define MASK 0x0000ffff
-#define BITS(val,n1,n2) ((val>>(15-(n2))) & (MASK>>(15-((n2)-(n1)))))
-
-enum format_t
-{
- format_1, /* 2 address instructions */
- format_2a, /* jump instructions */
- format_2b, /* bit I/O instructions */
- format_3_9, /* logical, multiply, and divide instructions */
- format_4, /* CRU instructions */
- format_5, /* register shift instructions */
- format_6, /* single address instructions */
- format_7, /* instructions without operands */
- format_8a, /* immediate instructions (destination register) */
- format_8b, /* immediate instructions (no destination register) */
- format_9, /* extended operation instruction */
- format_10, /* memory map file instruction */
- format_11, /* multiple precision instructions */
- format_12, /* string instructions */
- format_13, /* multiple precision shift instructions */
- format_14, /* bit testing instructions */
- format_15, /* invert order of field instruction */
- format_16, /* field instructions */
- format_17, /* alter register and jump instructions */
- format_18, /* single register operand instructions */
- format_liim,/* format for liim (looks like format 18) */
- format_19, /* move address instruction */
- format_20, /* list search instructions */
- format_21, /* extend precision instruction */
-
- illegal
-};
-
-/* definitions for flags */
-enum
-{
- /* processor set on which opcodes are available */
- ps_any = 0x01, /* every processor in the tms9900/ti990 family */
- ps_mapper = 0x02, /* processors with memory mapper (ti990/10, ti990/12,
- and tms99000 with mapper coprocessor) */
- ps_tms9995 = 0x04, /* ti990/12, tms9995, and later */
- ps_tms99000 = 0x08, /* ti990/12, tms99000, and later */
- ps_ti990_12 = 0x10, /* ti990/12 only */
-
- /* additional flags for special decoding */
- sd_11 = 0x100, /* bit 11 should be cleared in li, ai, andi, ori, ci, stwp, stst */
- sd_11_15 = 0x200 /* bits 11-15 should be cleared in lwpi, limi, idle, rset, rtwp, ckon, ckof, lrex */
-};
-
-struct description_t
-{
- const char *mnemonic;
- format_t format;
- int flags;
-};
-
-
-enum opcodes {
- /* basic instruction set */
- _a=0, _ab, _c, _cb, _s, _sb, _soc, _socb, _szc, _szcb,
- _mov, _movb, _coc, _czc, _xor, _mpy, _div, _xop, _b, _bl,
- _blwp, _clr, _seto, _inv, _neg, _abs, _swpb, _inc, _inct, _dec,
- _dect, _x, _ldcr, _stcr, _sbo, _sbz, _tb, _jeq, _jgt, _jh,
- _jhe, _jl, _jle, _jlt, _jmp, _jnc, _jne, _jno, _joc, _jop,
- _sla, _sra, _src, _srl, _ai, _andi, _ci, _li, _ori, _lwpi,
- _limi, _stst, _stwp, _rtwp, _idle, _rset, _ckof, _ckon, _lrex,
-
- /* mapper instruction set */
- _lds, _ldd, _lmf,
-
- /* tms9995 instruction set */
- _divs, _mpys, _lst, _lwp,
-
- /* tms99000 instruction set */
- _bind,
-
- /* ti990/12 instruction set */
- _sram, _slam, _rto, _lto, _cnto, _slsl, _slsp, _bdc, _dbc, _swpm,
- _xorm, _orm, _andm, _sm, _am, _mova, _emd, _eint, _dint, _stpc,
- _cs, _seqb, _movs, _lim, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs,
-
- _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, _nrm, _tmb,
- _tcmb, _tsmb, _srj, _arj, _xit, _insf, _xv, _xf, _ar, _cir,
- _sr, _mr, _dr, _lr, _str, _iof, _sneb, _crc, _ts, _ad,
- _cid, _sd, _md, _dd, _ld, _std, _ep,
-
- /* tms9940-only instruction set */
- _liim, _dca, _dcs,
-
- _ill
-};
-
-
-static const description_t descriptions[144+3+1] =
-{
- /* basic instruction set */
- { "a", format_1, ps_any }, { "ab", format_1, ps_any },
- { "c", format_1, ps_any }, { "cb", format_1, ps_any },
- { "s", format_1, ps_any }, { "sb", format_1, ps_any },
- { "soc", format_1, ps_any }, { "socb", format_1, ps_any },
- { "szc", format_1, ps_any }, { "szcb", format_1, ps_any },
- { "mov", format_1, ps_any }, { "movb", format_1, ps_any },
- { "coc", format_3_9, ps_any }, { "czc", format_3_9, ps_any },
- { "xor", format_3_9, ps_any }, { "mpy", format_3_9, ps_any },
- { "div", format_3_9, ps_any }, { "xop", format_9, ps_any },
- { "b", format_6, ps_any }, { "bl", format_6, ps_any },
- { "blwp", format_6, ps_any }, { "clr", format_6, ps_any },
- { "seto", format_6, ps_any }, { "inv", format_6, ps_any },
- { "neg", format_6, ps_any }, { "abs", format_6, ps_any },
- { "swpb", format_6, ps_any }, { "inc", format_6, ps_any },
- { "inct", format_6, ps_any }, { "dec", format_6, ps_any },
- { "dect", format_6, ps_any }, { "x", format_6, ps_any },
- { "ldcr", format_4, ps_any }, { "stcr", format_4, ps_any },
- { "sbo", format_2b, ps_any }, { "sbz", format_2b, ps_any },
- { "tb", format_2b, ps_any }, { "jeq", format_2a, ps_any },
- { "jgt", format_2a, ps_any }, { "jh", format_2a, ps_any },
- { "jhe", format_2a, ps_any }, { "jl", format_2a, ps_any },
- { "jle", format_2a, ps_any }, { "jlt", format_2a, ps_any },
- { "jmp", format_2a, ps_any }, { "jnc", format_2a, ps_any },
- { "jne", format_2a, ps_any }, { "jno", format_2a, ps_any },
- { "joc", format_2a, ps_any }, { "jop", format_2a, ps_any },
- { "sla", format_5, ps_any }, { "sra", format_5, ps_any },
- { "src", format_5, ps_any }, { "srl", format_5, ps_any },
- { "ai", format_8a, ps_any|sd_11 }, { "andi", format_8a, ps_any|sd_11 },
- { "ci", format_8a, ps_any|sd_11 }, { "li", format_8a, ps_any|sd_11 },
- { "ori", format_8a, ps_any|sd_11 }, { "lwpi", format_8b, ps_any|sd_11|sd_11_15 },
- { "limi", format_8b, ps_any|sd_11|sd_11_15 }, { "stst", format_18, ps_any|sd_11 },
- { "stwp", format_18, ps_any|sd_11 }, { "rtwp", format_7, ps_any|sd_11|sd_11_15 },
- { "idle", format_7, ps_any|sd_11|sd_11_15 }, { "rset", format_7, ps_any|sd_11|sd_11_15 },
- { "ckof", format_7, ps_any|sd_11|sd_11_15 }, { "ckon", format_7, ps_any|sd_11|sd_11_15 },
- { "lrex", format_7, ps_any|sd_11|sd_11_15 },
-
- /* mapper instruction set */
- { "lds", format_6, ps_mapper }, { "ldd", format_6, ps_mapper },
- { "lmf", format_10, ps_mapper },
-
- /* tms9995 instruction set */
- { "divs", format_6, ps_tms9995 }, { "mpys", format_6, ps_tms9995 },
- { "lst", format_18, ps_tms9995 }, { "lwp", format_18, ps_tms9995 },
-
- /* tms99000 instruction set */
- { "bind", format_6, ps_tms99000 },
-
- /* ti990/12 instruction set */
- { "sram", format_13, ps_ti990_12 }, { "slam", format_13, ps_ti990_12 },
- { "rto", format_11, ps_ti990_12 }, { "lto", format_11, ps_ti990_12 },
- { "cnto", format_11, ps_ti990_12 }, { "slsl", format_20, ps_ti990_12 },
- { "slsp", format_20, ps_ti990_12 }, { "bdc", format_11, ps_ti990_12 },
- { "dbc", format_11, ps_ti990_12 }, { "swpm", format_11, ps_ti990_12 },
- { "xorm", format_11, ps_ti990_12 }, { "orm", format_11, ps_ti990_12 },
- { "andm", format_11, ps_ti990_12 }, { "sm", format_11, ps_ti990_12 },
- { "am", format_11, ps_ti990_12 }, { "mova", format_19, ps_ti990_12 },
- { "emd", format_7, ps_ti990_12 }, { "eint", format_7, ps_ti990_12 },
- { "dint", format_7, ps_ti990_12 }, { "stpc", format_18, ps_ti990_12 },
- { "cs", format_12, ps_ti990_12 }, { "seqb", format_12, ps_ti990_12 },
- { "movs", format_12, ps_ti990_12 }, { "lim", format_18, ps_ti990_12 },
- { "lcs", format_18, ps_ti990_12 }, { "blsk", format_8a, ps_ti990_12 },
- { "mvsr", format_12, ps_ti990_12 }, { "mvsk", format_12, ps_ti990_12 },
- { "pops", format_12, ps_ti990_12 }, { "pshs", format_12, ps_ti990_12 },
- { "cri", format_7, ps_ti990_12 }, { "cdi", format_7, ps_ti990_12 },
- { "negr", format_7, ps_ti990_12 }, { "negd", format_7, ps_ti990_12 },
- { "cre", format_7, ps_ti990_12 }, { "cde", format_7, ps_ti990_12 },
- { "cer", format_7, ps_ti990_12 }, { "ced", format_7, ps_ti990_12 },
- { "nrm", format_11, ps_ti990_12 }, { "tmb", format_14, ps_ti990_12 },
- { "tcmb", format_14, ps_ti990_12 }, { "tsmb", format_14, ps_ti990_12 },
- { "srj", format_17, ps_ti990_12 }, { "arj", format_17, ps_ti990_12 },
- { "xit", format_7, ps_ti990_12 }, { "insf", format_16, ps_ti990_12 },
- { "xv", format_16, ps_ti990_12 }, { "xf", format_16, ps_ti990_12 },
- { "ar", format_6, ps_ti990_12 }, { "cir", format_6, ps_ti990_12 },
- { "sr", format_6, ps_ti990_12 }, { "mr", format_6, ps_ti990_12 },
- { "dr", format_6, ps_ti990_12 }, { "lr", format_6, ps_ti990_12 },
- { "str", format_6, ps_ti990_12 }, { "iof", format_15, ps_ti990_12 },
- { "sneb", format_12, ps_ti990_12 }, { "crc", format_12, ps_ti990_12 },
- { "ts", format_12, ps_ti990_12 }, { "ad", format_6, ps_ti990_12 },
- { "cid", format_6, ps_ti990_12 }, { "sd", format_6, ps_ti990_12 },
- { "md", format_6, ps_ti990_12 }, { "dd", format_6, ps_ti990_12 },
- { "ld", format_6, ps_ti990_12 }, { "std", format_6, ps_ti990_12 },
- { "ep", format_21, ps_ti990_12 },
-
- /* tms9940-only instruction set */
- /* these instructions are said to be format 9 (xop), but since the xop
- level is interpreted as part of the opcode, dca and dcs should be handled
- like format 6. liim looks like format 18, but slightly different,
- therefore it is handled like a special format. */
- { "liim", format_liim,/*ps_tms9940*/0 }, { "dca", format_6, /*ps_tms9940*/0 },
- { "dcs", format_6, /*ps_tms9940*/0 },
-
- { NULL, illegal, ps_any }
-};
-
-
-static const enum opcodes ops_4000_ffff_s12[12]=
-{
- _szc, _szcb, _s, _sb, /*4000-7000*/
- _c, _cb, _a, _ab, _mov, _movb, _soc, _socb /*8000-f000*/
-};
-
-
-static const enum opcodes ops_2000_3fff_s10[8]=
-{
- _coc, _czc, _xor, _xop, _ldcr, _stcr, _mpy, _div /*2000-3800*/
-};
-
-
-static const enum opcodes ops_1000_1fff_s8[16]=
-{
- _jmp, _jlt, _jle, _jeq, _jhe, _jgt, _jne, _jnc, /*1000-1700*/
- _joc, _jno, _jl, _jh, _jop, _sbo, _sbz, _tb /*1800-1f00*/
-};
-
-
-static const enum opcodes ops_0e40_0fff_s6[7]=
-{
- _ad, _cid, _sd, _md, _dd, _ld, _std /*0e40-0fc0*/
-};
-
-
-static const enum opcodes ops_0e00_0e3f_s4[4]=
-{
- _iof, _sneb, _crc, _ts /*0e00-0e30*/
-};
-
-
-static const enum opcodes ops_0c40_0dff_s6[7]=
-{
- _ar, _cir, _sr, _mr, _dr, _lr, _str /*0c40-0dc0*/
-};
-
-
-static const enum opcodes ops_0c10_0c3f_s4[3]=
-{
- _insf, _xv, _xf /*0c10-0c30*/
-};
-
-
-static const enum opcodes ops_0c00_0c0f_s0[16]=
-{
- _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, /*0c00-0c07*/
- _nrm, _tmb, _tcmb, _tsmb, _srj, _arj, _xit, _xit /*0c08-0c0f*/
-};
-
-
-
-static const enum opcodes ops_0800_0bff_s8[4]=
-{
- _sra, _srl, _sla, _src /*0800-0b00*/
-};
-
-
-static const enum opcodes ops_0400_07ff_s6[16]=
-{
- _blwp, _b, _x, _clr, _neg, _inv, _inc, _inct, /*0400-05c0*/
- _dec, _dect, _bl, _swpb, _seto, _abs, _lds, _ldd /*0600-07c0*/
-};
-
-
-static const enum opcodes ops_0200_03ff_s5[16]=
-{
- _li, _ai, _andi, _ori, _ci, _stwp, _stst, _lwpi, /*0200-02e0*/
- _limi, _lmf, _idle, _rset, _rtwp, _ckon, _ckof, _lrex /*0300-03e0*/
-};
-
-
-static const enum opcodes ops_0100_01ff_s6[4]=
-{
- _ill, _bind, _divs, _mpys /*0100-01c0*/
-};
-
-
-static const enum opcodes ops_0030_00ff_s4[13]=
-{
- _stpc, _cs, _seqb, _movs, _lim, /*0030-0070*/
- _lst, _lwp, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs /*0080-00f0*/
-};
-
-
-static const enum opcodes ops_001c_002f_s0[20]=
-{
- _sram, _slam, _rto, _lto, /*001c-001f*/
- _cnto, _slsl, _slsp, _bdc, _dbc, _swpm, _xorm, _orm, /*0020-0027*/
- _andm, _sm, _am, _mova, _ill, _emd, _eint, _dint /*0028-002f*/
-};
-
-
-
-static int PC;
-
-
-INLINE UINT16 readop_arg(const UINT8 *opram, unsigned pc)
-{
- UINT16 result = opram[PC++ - pc] << 8;
- return result | opram[PC++ - pc];
-}
-
-static int print_arg (char *dest, int mode, int arg, const UINT8 *opram, unsigned pc)
-{
- int base;
-
- switch (mode)
- {
- case 0x0: /* workspace register */
- return sprintf (dest, "R%d", arg);
- case 0x1: /* workspace register indirect */
- return sprintf (dest, "*R%d", arg);
- case 0x2: /* symbolic|indexed */
- base = readop_arg(opram, pc);
- if (arg) /* indexed */
- return sprintf (dest, "@>%04x(R%d)", base, arg);
- else /* symbolic (direct) */
- return sprintf (dest, "@>%04x", base);
- case 0x3: /* workspace register indirect auto increment */
- return sprintf (dest, "*R%d+", arg);
- }
-
- return 0;
-}
-
-
-/*****************************************************************************
- * Disassemble a single command and return the number of bytes it uses.
- *****************************************************************************/
-unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram)
-{
- int OP, OP2, opc;
- int sarg, darg, smode, dmode;
- signed char displacement;
- int byte_count, checkpoint;
- int bit_position, bit_width;
- unsigned dasmflags = 0;
-
- const char *mnemonic;
- format_t format;
- int flags;
-
- /*
- Under tms9900, opcodes >0400->07FF are incompletely decoded: bits 11 is ignored, and so are
- bits 12-15 for instructions which do not require a register. On the other hand, ti990/10
- generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15.
- Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are
- non-zero.
- */
- #define BETTER_0200_DECODING (model_id == TI990_10_ID)
- #define COMPLETE_0200_DECODING (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID))
-
- int processor_mask = ps_any;
-
- if ((model_id == TI990_10_ID) /*|| (model_id == TI990_12_ID)*/ || (model_id >= TMS99000_ID))
- processor_mask |= ps_mapper; /* processors with memory mapper (ti990/10, ti990/12,
- and tms99000 with mapper coprocessor) */
- if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID))
- processor_mask |= ps_tms9995; /* ti990/12, tms9995, and later */
-
- if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS99000_ID))
- processor_mask |= ps_tms99000; /* ti990/12, tms99000, and later */
-
- /*if ((model_id == TI990_12_ID))
- processor_mask |= ps_ti990_12;*/ /* ti990/12, tms99000, and later */
-
- PC = pc;
- OP = oprom[PC++ - pc] << 8;
- OP |= oprom[PC++ - pc];
-
- /* let's identify the opcode */
- if (OP >= 0x4000)
- opc = ops_4000_ffff_s12[(OP - 0x4000) >> 12];
- else if (OP >= 0x2000)
- opc = ops_2000_3fff_s10[(OP - 0x2000) >> 10];
- else if (OP >= 0x1000)
- opc = ops_1000_1fff_s8[(OP - 0x1000) >> 8];
- else if (OP >= 0x0C00)
- {
- if (OP >= 0x0E40)
- opc = ops_0e40_0fff_s6[(OP - 0x0E40) >> 6];
- else if (OP >= 0x0E00)
- opc = ops_0e00_0e3f_s4[(OP - 0x0E00) >> 4];
- else if (OP >= 0x0C40)
- opc = ops_0c40_0dff_s6[(OP - 0x0C40) >> 6];
- else if (OP >= 0x0C10)
- opc = ops_0c10_0c3f_s4[(OP - 0x0C10) >> 4];
- else
- opc = ops_0c00_0c0f_s0[OP - 0x0C00];
- }
- else if (OP >= 0x0800)
- opc = ops_0800_0bff_s8[(OP - 0x0800) >> 8];
- else if (OP >= 0x0400)
- opc = ops_0400_07ff_s6[(OP - 0x0400) >> 6];
- else if (OP >= 0x0200)
- {
- opc = ops_0200_03ff_s5[(OP - 0x0200) >> 5];
- if (BETTER_0200_DECODING || COMPLETE_0200_DECODING)
- {
- flags = descriptions[opc].flags;
- if ( (COMPLETE_0200_DECODING && (flags & sd_11_15) && (OP & 0x001f))
- || ((flags & sd_11) && (OP & 0x0010)) )
- {
- opc = _ill;
- if (OP >= 0x03f0)
- opc = _ep; /* the ep opcode is located in a "hole" */
- }
- }
- }
- else if (OP >= 0x0100)
- opc = ops_0100_01ff_s6[(OP - 0x0100) >> 6];
- else if (OP >= 0x0030)
- opc = ops_0030_00ff_s4[(OP - 0x0030) >> 4];
- else if (OP >= 0x001C)
- opc = ops_001c_002f_s0[OP - 0x001C];
- else
- opc = _ill;
-
- /* read flags */
- flags = descriptions[opc].flags;
- /* set as illegal if the processor does not implement this instruction */
- if (! (flags & processor_mask))
- {
- opc = _ill;
- flags = descriptions[opc].flags; /* read new flags */
- }
-
- /* tms9940 replace a few xops with custom instructions */
- if ((opc == _xop) && ((model_id == TMS9940_ID) || (model_id == TMS9985_ID)))
- {
- switch (BITS(OP,6,9))
- {
- case 0:
- /* opcode is dca */
- opc = _dca;
- break;
-
- case 1:
- /* opcode is dcs */
- opc = _dcs;
- break;
-
- case 2:
- case 3: /* should be 2, but instruction decoding is incomplete */
- /* opcode is liim */
- if (BITS(OP,12,15) == 0)
- /* ts must be == 0 */
- opc = _liim;
- else
- /* I don't know what happens when ts != 0. Maybe the CPU does
- the complete address decoding, and liim gets a bogus value
- instead of the immediate. Since I do not know, I handle this
- as an illegal instruction. */
- opc = _ill;
- break;
-
- default:
- /* this is still a software xop */
- break;
- }
- }
-
- mnemonic = descriptions[opc].mnemonic;
- format = descriptions[opc].format;
-
- /* bl and blwp instructions are subroutines */
- if (mnemonic != NULL && mnemonic[0] == 'b' && mnemonic[1] == 'l')
- dasmflags = DASMFLAG_STEP_OVER;
-
- /* b *r11 and rtwp are returns */
- else if (opc == 0x045b || (mnemonic != NULL && strcmp(mnemonic, "rtwp") == 0))
- dasmflags = DASMFLAG_STEP_OUT;
-
- switch (format)
- {
- case format_1: /* 2 address instructions */
- smode = BITS(OP,10,11);
- sarg = BITS(OP,12,15);
- dmode = BITS(OP,4,5);
- darg = BITS(OP,6,9);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- break;
-
- case format_2a: /* jump instructions */
- displacement = (signed char)BITS(OP,8,15);
- sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & (PC + displacement * 2));
- break;
-
- case format_2b: /* bit I/O instructions */
- displacement = (signed char)BITS(OP,8,15);
- sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & displacement);
- break;
-
- case format_3_9: /* logical, multiply, and divide instructions */
- case format_4: /* CRU instructions */
- case format_9: /* extended operation instruction */
- smode = BITS(OP,10,11);
- sarg = BITS(OP,12,15);
- darg = BITS(OP,6,9);
-
- if ((darg == 0) && (format == format_4))
- darg = 16;
-
- if (format == format_3_9)
- {
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",R%d", darg);
- }
- else
- {
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",%d", darg);
- }
- break;
-
- case format_5: /* register shift instructions */
- sarg = BITS(OP,12,15);
- darg = BITS(OP,8,11);
-
- sprintf (buffer, darg ? "%-4s R%d,%d" : "%-4s R%d,R%d", mnemonic, sarg, darg);
- break;
-
- case format_6: /* single address instructions */
- smode = BITS(OP,10,11);
- sarg = BITS(OP,12,15);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- break;
-
- case format_7: /* instructions without operands */
- sprintf (buffer, "%s", mnemonic);
- break;
-
- case format_8a: /* immediate instructions (destination register) */
- darg = BITS(OP,12,15);
- sarg = readop_arg(opram, pc);
-
- sprintf (buffer, "%-4s R%d,>%04x", mnemonic, darg, sarg);
- break;
-
- case format_8b: /* immediate instructions (no destination register) */
- sarg = readop_arg(opram, pc);
-
- sprintf (buffer, "%-4s >%04x", mnemonic, sarg);
- break;
-
- case format_10: /* memory map file instruction */
- sarg = BITS(OP,12,15);
- darg = BITS(OP,11,11);
-
- sprintf (buffer, "%-4s R%d,%d", mnemonic, sarg, darg);
- break;
-
- case format_11: /* multiple precision instructions */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
- byte_count = BITS(OP2,0,3);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
- break;
-
- case format_12: /* string instructions */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
- byte_count = BITS(OP2,0,3);
- checkpoint = BITS(OP,12,15);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- buffer += sprintf (buffer, byte_count ? ",%d,R%d" : ",R%d,R%d", byte_count, checkpoint);
- break;
-
- case format_13: /* multiple precision shift instructions */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- darg = BITS(OP2,6,9);
- byte_count = BITS(OP2,0,3);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
- buffer += sprintf (buffer, darg ? ",%d" : ",R%d", darg);
- break;
-
- case format_14: /* bit testing instructions */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- darg = BITS(OP2,0,9);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- if (darg == 0x3ff)
- buffer += sprintf (buffer, ",R0");
- else
- buffer += sprintf (buffer, ",%d", darg);
- break;
-
- case format_15: /* invert order of field instruction */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- bit_position = BITS(OP2,0,3);
- bit_width = BITS(OP,12,15);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, bit_position ? ",(%d," : ",(R%d,", bit_position);
- buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width);
- break;
-
- case format_16: /* field instructions */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
- bit_position = BITS(OP2,0,3);
- bit_width = BITS(OP,12,15);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- buffer += sprintf (buffer, bit_position ? ",(%d," : ",(%d,", bit_position);
- buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width);
- break;
-
- case format_17: /* alter register and jump instructions */
- OP2 = readop_arg(opram, pc);
-
- displacement = (signed char)BITS(OP2,8,15);
- sarg = BITS(OP2,4,7);
- darg = BITS(OP2,0,3);
- if (darg)
- sprintf (buffer, darg ? "%-4s >%04x,%d,R%d" : "%-4s >%04x,R%d,R%d",
- mnemonic, 0xffff & (PC + displacement * 2), sarg, darg);
- break;
-
- case format_18: /* single register operand instructions */
- sarg = BITS(OP,12,15);
-
- sprintf (buffer, "%-4s R%d", mnemonic, sarg);
- break;
-
- case format_liim: /* liim instruction */
- sarg = BITS(OP,14,15);
-
- sprintf (buffer, "%-4s %d", mnemonic, sarg);
- break;
-
- case format_19: /* move address instruction */
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- break;
-
- case format_20: /* list search instructions */
- {
- const char *condition_code;
-
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
-
- switch (BITS(OP2,0,3))
- {
- case 0:
- condition_code = "eq";
- break;
- case 1:
- condition_code = "ne";
- break;
- case 2:
- condition_code = "he";
- break;
- case 3:
- condition_code = "l";
- break;
- case 4:
- condition_code = "ge";
- break;
- case 5:
- condition_code = "lt";
- break;
- case 6:
- condition_code = "le";
- break;
- case 7:
- condition_code = "h";
- break;
- case 8:
- condition_code = "lte";
- break;
- case 9:
- condition_code = "gt";
- break;
- default:
- condition_code = "??";
- break;
- }
-
- buffer += sprintf (buffer, "%-4s %s,", mnemonic, condition_code);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- break;
- }
-
- case format_21: /* extend precision instruction */
- {
- int dest_byte_count;
-
- OP2 = readop_arg(opram, pc);
-
- smode = BITS(OP2,10,11);
- sarg = BITS(OP2,12,15);
- dmode = BITS(OP2,4,5);
- darg = BITS(OP2,6,9);
- byte_count = BITS(OP2,0,3);
- dest_byte_count = BITS(OP,12,15);
-
- buffer += sprintf (buffer, "%-4s ", mnemonic);
- buffer += print_arg (buffer, smode, sarg, opram, pc);
- buffer += sprintf (buffer, ",");
- buffer += print_arg (buffer, dmode, darg, opram, pc);
- buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count);
- buffer += sprintf (buffer, dest_byte_count ? ",%d" : ",R%d", dest_byte_count);
- break;
- }
-
- default:
- logerror("debbugger internal error, file %s, line %d\n", __FILE__, __LINE__);
- case illegal:
- sprintf (buffer, "data >%04x", OP);
- break;
- }
-
- return (PC - pc) | DASMFLAG_SUPPORTED | dasmflags;
-}
-
-CPU_DISASSEMBLE( tms9900 )
-{
- return Dasm9900(buffer, pc, TMS9900_ID, oprom, opram);
-}
-
-CPU_DISASSEMBLE( tms9980 )
-{
- return Dasm9900(buffer, pc, TMS9980_ID, oprom, opram);
-}
-
-CPU_DISASSEMBLE( tms9995 )
-{
- return Dasm9900(buffer, pc, TMS9995_ID, oprom, opram);
-}
diff --git a/src/emu/cpu/tms9900/99xxcore.h b/src/emu/cpu/tms9900/99xxcore.h
deleted file mode 100644
index cb94fac286f..00000000000
--- a/src/emu/cpu/tms9900/99xxcore.h
+++ /dev/null
@@ -1,5319 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Raphael Nabet
-
-/***************************************************************************
- Legacy TMS99xx core implementation
-
- PLEASE DO NOT REMOVE THIS FILE from the source tree, even if none of the
- drivers make use of it anymore. It still contains documentation and
- incomplete implementations of cores that are not (yet) used in drivers.
-
- It need not be included in the build process, however.
-
- Michael Zapf, February 2014
-
-***************************************************************************/
-
-/*
- 99xxcore.h : generic tms99xx emulation
-
- The TMS99XX_MODEL switch tells which emulator we want to build. Set the
- switch, then include 99xxcore.h, and you will have an emulator for this
- processor.
-
- Only ti990/10, tms9900, tms9980a/9981, and tms9995 work OK for now. Note
- that tms9995 has not been tested extensively.
-
- tms9940 is WIP: it is probably still buggy (particularily the BCD support),
- as it has not been tested. tms9985 has been implemented as a 9940 with
- a data bus, which should be mostly correct.
-
- I think all software aspects of tms9985 and tms9989 are implemented.
- You just need to implement bus interfaces, provided you know them.
- (I don't...)
-
- tms99000 cannot be implemented fully yet, due to lack of documentation.
-
- ti990/12 is not supported at all, and it should probably be implemented as
- a separate processor core, anyway.
-
- Original tms9900 emulator by Edward Swartz
- Smoothed out by Raphael Nabet
- Originally converted for Mame by M.Coates
- Processor timing, support for tms9980 and tms9995, and many bug fixes by R Nabet
-*/
-
-/*
- The first member of the family was actually the ti990/10 minicomputer,
- released in 1975. tms9900 was released in 1976, and has the same
- instruction set as ti990/10: however, tms9900 is slower, it does not
- support privileges and memory mapping, and illegal instructions do not
- cause an error interrupt.
-
- The ti990 family later evoluted into the huge ti990/12 system, with support
- for 144 different instructions, and microcode programming in case some user
- found it was not enough. ti990/10 was eventually replaced by a cheaper
- ti990/10a board, built around a tms99000 microprocessor.
-
- The tms9980 processor is merely a tms9900 with a 8-bit data bus (instead of
- 16-bit on tms9900).
-
- tms9940 is a microcontroller, and is mostly similar to 9900/9980. The
- variant I know has 2kb of ROM, 128 bytes of RAM, a timer, 32 I/O line, some
- of which can be reconfigured as a CRU bus, but no external memory bus. It
- includes three additional opcodes, which are not supported by any other
- member of the family (with the probable exception of TMS9985).
-
- tms9985 is similar to tms9940, but it supports an external 8-bit-wide
- memory bus. At least one variant included 8kb of ROM, 256 bytes of RAM.
- It was ill-fated, as it was never released due to technical problems.
-
- tms9989 is mostly alien to me. I guess it is a close relative of tms9995,
- although I am not sure. I have read that the SBP68689 supports tms9995
- opcodes, but that tms9989 does not.
-
- tms9995 belongs to another generation. It is quite faster than tms9900,
- and supports 4 extra opcodes. Its external bus is 8-bit-wide, and it has
- 256 bytes of internal 16-bit RAM.
-
- tms99000 is the successor to both ti9900 and ti990/10. It supports
- privileges, and has a coprocessor interface which enables the use of an
- external memory mapper. Additionnally, it can use a Macrostore ROM to
- emulate additional instructions.
-
- This feature allowed TI to expand the 99000 family with the tms99105 (which
- was said to support 84 instructions types), the tms99110 (which supported
- floating point instructions), and possibly another chip (tms99220???) which
- included parts of the UCSD P-system in Macrostore.
-
-References :
-* 9900 family systems design, chapter 6, 7, 8
-* TMS 9980A/ TMS 9981 Product Data Book
-* TMS 9995 16-Bit Microcomputer Data Manual
-* Model 990/10A computer general description, section 4 (p/n 2302633-9701 A)
-* 990/99000 assembly language reference manual (p/n 2270509-9701 A)
-* Chapter 18 of unidentified book is the only reference on tms9940 I have found so far (Paperport format)
- <ftp://ftp.whtech.com//datasheets/Hardware manuals/tms9900 9901 9904 9940 9980 (by a osborne).max>
-
-Other references can be found on spies.com:
-<http://www.spies.com/arcade/simulation/processors/index.html>
-<http://www.spies.com/~aek/pdf/ti/>
-
-*/
-
-
-#if (TMS99XX_MODEL == TI990_10_ID)
-
- #define TMS99XX_PREFIX ti990_10
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( ti990_10l )
- #define TMS99XX_device_get_name "TI990/10L"
- #define TMS99XX_device_get_shortname "ti990_10l"
-
-#elif (TMS99XX_MODEL == TMS9900_ID)
-
- #define TMS99XX_PREFIX tms9900
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9900l )
- #define TMS99XX_device_get_name "TMS9900L"
- #define TMS99XX_device_get_shortname "tms9900l"
-
-#elif (TMS99XX_MODEL == TMS9940_ID)
-
- #define TMS99XX_PREFIX tms9940
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9940l )
- #define TMS99XX_device_get_name "TMS9940L"
- #define TMS99XX_device_get_shortname "tms9940l"
-
- #error "tms9940 is not yet supported"
-
-#elif (TMS99XX_MODEL == TMS9980_ID)
-
- #define TMS99XX_PREFIX tms9980a
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9980al )
- #define TMS99XX_device_get_name "TMS9980AL/TMS9981L"
- #define TMS99XX_device_get_shortname "tms9980al"
-
-#elif (TMS99XX_MODEL == TMS9985_ID)
-
- #define TMS99XX_PREFIX tms9985
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9985l )
- #define TMS99XX_device_get_name "TMS9985L"
- #define TMS99XX_device_get_shortname "tms9985l"
-
- #error "tms9985 is not yet supported"
-
-#elif (TMS99XX_MODEL == TMS9989_ID)
-
- #define TMS99XX_PREFIX tms9989
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9989l )
- #define TMS99XX_device_get_name "TMS9989L"
- #define TMS99XX_device_get_shortname "tms9989l"
-
- #error "tms9989 is not yet supported"
-
-#elif (TMS99XX_MODEL == TMS9995_ID)
-
- #define TMS99XX_PREFIX tms9995
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9995l )
- #define TMS99XX_device_get_name "TMS9995L"
- #define TMS99XX_device_get_shortname "tms9995l"
-
-#elif (TMS99XX_MODEL == TMS99000_ID)
-
- #define TMS99XX_PREFIX tms99000
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99000l )
- #define TMS99XX_device_get_name "TMS99000L"
- #define TMS99XX_device_get_shortname "tms99000l"
-
- #error "tms99000 is not yet supported"
-
-#elif (TMS99XX_MODEL == TMS99105A_ID)
-
- #define TMS99XX_PREFIX tms99105a
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99105al )
- #define TMS99XX_device_get_name "TMS99105AL"
- #define TMS99XX_device_get_shortname "tms99105al"
-
- #error "tms99105a is not yet supported"
-
-#elif (TMS99XX_MODEL == TMS99110A_ID)
-
- #define TMS99XX_PREFIX tms99110a
- #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99110al )
- #define TMS99XX_device_get_name "TMS99110AL"
- #define TMS99XX_device_get_shortname "tms99110al"
-
- #error "tms99110a is not yet supported"
-
-#endif
-
-/*
- Now for some preprocessor wizardry.
-*/
-#define concat2(a,b) a##b
-
-#define GET_INFO(prefix) concat2(prefix,_get_info)
-#define RESET_PARAM(prefix) concat2(prefix,reset_param)
-
-#define TMS99XX_RESET_PARAM RESET_PARAM(TMS99XX_PREFIX)
-
-
-
-/*
- I include this macro because we may eventually support other 99000 variants such as tms99110,
- and this macro will remain true for every 99000 family member, even when we have
- (TMS99XX_MODEL != TMS99000_ID).
-*/
-#define IS_99000 (TMS99XX_MODEL == TMS99000_ID)
-
-/*
- On microprocessor implementations (other than TMS9940 and, probably, TMS9985), the CKOF, CKON,
- IDLE, LREX and RSET cause an external CRU write. CKOF, CKON and LREX do nothing apart of this,
- therefore they must be implemented with external hardware (CKON and CKOF are supposed to
- enable/disable a line clock interrupt, and LREX to trigger a LOAD interrupt). IDLE and RSET
- are functional, but, on the one hand, the design allowed to light a diagnostic LED when
- the processor is in IDLE state, and, on the other hand, the RSET instruction is supposed
- to reset external devices as well.
-
- On the TI990/10 and TI990/12 minicomputers, there is no such CRU write. The line clock
- interrupt latch is part of the CPU board, LREX is fully functional, the IDLE led is connected
- to the board, and the RSET line is part of the TILINE bus connector.
-
- On the TMS9940, CKOF, CKON, LREX and RSET are not supported. IDLE, on the other hand, is
- supported, and the CPU can be configured to output its IDLE state on the P16 I/O pin.
-*/
-#define EXTERNAL_INSTRUCTION_DECODING (TMS99XX_MODEL != TI990_10_ID) && (TMS99XX_MODEL != TI9940_ID) && (TMS99XX_MODEL != TI9985_ID)
-#define EXTERNAL_INSTRUCTION_CALLBACK (TMS99XX_MODEL == TI990_10_ID)
-
-/*
- ti990/10, ti990/12 and tms99000 support privileges
-
- privileged instructions:
- CKOF, CKON, IDLE, LIMI, LREX, RSET,
- LDD, LDS, LMF, (memory mapping instructions)
- DINT, EINT, EMD , LCS, LIM, SLSP. (990/12 instructions)
-
- instructions which are privileged when the effective CRU address is higher than 0xE00:
- LDCR, SBO, SBZ, STCR, TB.
-
- instructions whose behaviour is modified in user mode (only user flags in ST are affected):
- RTWP,
- LST. (ti990/12 and tms99000 instruction)
-*/
-#define HAS_PRIVILEGE ((TMS99XX_MODEL == TI990_10_ID) || IS_99000)
-
-/*
- opcode groups
-
- * 69 basic opcodes implemented on all family members
- * 3 memory mapping opcodes implemented on ti990/10 with mapping option, ti990/12, and
- the tim99610 mapper in conjunction with any tms99000 family member: LMF, LDS, LDD
- * 3 opcodes implemented on tms9940 (and probably tms9985) only: DCA, DCS, LIIM
- * 4 opcodes implemented on ti990/12, tms9989 and above: MPYS, DIVS, LST, LWP
- * 1 opcode implemented on ti990/12, and tms99000: BIND
- * 72 opcodes implemented on ti990/12 only (some of which are emulated by tms99105 & tms99110)
-*/
-
-#define HAS_MAPPING ((TMS99XX_MODEL == TI990_10_ID) /*|| IS_99000*/)
-#define HAS_9995_OPCODES ((TMS99XX_MODEL == TMS9989_ID) || (TMS99XX_MODEL == TMS9995_ID) || IS_99000)
-#define HAS_BIND_OPCODE IS_99000
-
-#define HAS_OVERFLOW_INTERRUPT ((TMS99XX_MODEL == TMS9995_ID) || IS_99000)
-
-/*
- Under tms9900, opcodes >0200->03FF are incompletely decoded: bits 11 is ignored, and so are
- bits 12-15 for instructions which do not require a register. On the other hand, ti990/10
- generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15.
- Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are
- non-zero.
-*/
-#define BETTER_0200_DECODING (TMS99XX_MODEL == TI990_10_ID)
-#define COMPLETE_0200_DECODING (TMS99XX_MODEL >= TMS9995_ID)
-
-/*
- TI990/10 and tms9900 force unused bits in the ST register to 0.
- TMS9995 does not.
-*/
-#define USE_ST_MASK (TMS99XX_MODEL <= TMS9985_ID)
-
-/*
- TI990/10, TMS9900 and TMS99000 have a 16-bit-wide memory bus, and use 16-bus accessors.
- TMS9940 use 16-bit accessors, too, as it has an internal 16-bit bus, and no external bus.
-*/
-#define USE_16_BIT_ACCESSORS ((TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (IS_99000))
-
-struct tms99xx_state;
-
-INLINE void execute(tms99xx_state *cpustate, UINT16 opcode);
-
-#if EXTERNAL_INSTRUCTION_DECODING
-static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID);
-#endif
-static UINT16 decipheraddr(tms99xx_state *cpustate, UINT16 opcode);
-static UINT16 decipheraddrbyte(tms99xx_state *cpustate, UINT16 opcode);
-static void contextswitch(tms99xx_state *cpustate, UINT16 addr);
-#if HAS_MAPPING || HAS_PRIVILEGE
-static void contextswitchX(tms99xx_state *cpustate, UINT16 addr);
-#else
-#define contextswitchX(cs, addr) contextswitch(cs, addr)
-#endif
-static void field_interrupt(tms99xx_state *cpustate);
-
-/***************************/
-/* Mame Interface Routines */
-/***************************/
-
-
-/* tms9900 ST register bits. */
-
-/* These bits are set by every compare, move and arithmetic or logical operation : */
-/* (Well, COC, CZC and TB only set the E bit, but these are kind of exceptions.) */
-#define ST_LGT 0x8000 /* Logical Greater Than (strictly) */
-#define ST_AGT 0x4000 /* Arithmetical Greater Than (strictly) */
-#define ST_EQ 0x2000 /* Equal */
-
-/* These bits are set by arithmetic operations, when it makes sense to update them. */
-#define ST_C 0x1000 /* Carry */
-#define ST_OV 0x0800 /* OVerflow (overflow with operations on signed integers, */
- /* and when the result of a 32bits:16bits division cannot fit in a 16-bit word.) */
-
-/* This bit is set by move and arithmetic operations WHEN THEY USE BYTE OPERANDS. */
-#define ST_OP 0x0400 /* Odd Parity */
-
-#if (TMS99XX_MODEL != TMS9940_ID)
-
-/* This bit is set by the XOP instruction. */
-#define ST_X 0x0200 /* Xop */
-
-#endif
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-
-/* This bit is set by arithmetic operations to support BCD */
-#define ST_DC 0x0100 /* Digit Carry */
-
-#endif
-
-#if HAS_PRIVILEGE
-
-/* This bit is set in user (i.e. non-supervisor) mode */
-#define ST_PR 0x0100 /* PRivilege */
-
-#endif
-
-#if HAS_MAPPING
-
-/* This tells which map is currently in use */
-#define ST_MF 0x0080 /* Map File */
-
-#endif
-
-#if (HAS_OVERFLOW_INTERRUPT)
-
-/* This bit is set in ti990/12, TMS9995 and later chips to generate a level-2 interrupt when
-the Overflow status bit is set */
-#define ST_OVIE 0x0020 /* OVerflow Interrupt Enable */
-
-#endif
-
-#if (IS_99000)
-
-/* This bit enables the macrostore feature on tms99000 */
-/* (It is used on ti990/12 with a different meaning.) */
-#define ST_EMR 0x0010 /* Enable Macrostore Rom */
-
-#endif
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-
-#define ST_IM 0x0003 /* Interrupt Mask */
-
-#else
-
-#define ST_IM 0x000F /* Interrupt Mask */
-
-#endif
-
-/* On models before TMS9995 (TMS9989 ?), unused ST bits are always forced to 0, so we define
-a ST_MASK */
-#if (USE_ST_MASK)
- #if (TMS99XX_MODEL == TI990_10_ID)
- #define ST_MASK 0xFF8F
- #elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-#define ST_MASK 0xFD03
- #else
- #define ST_MASK 0xFE0F
- #endif
-#endif
-
-
-/* error interrupt register bits */
-
-#if (TMS99XX_MODEL == TI990_10_ID)
-
-/* This bit is set in user (i.e. non-supervisor) mode */
-#define EIR_MAPERR 0x0800 /* memory MAPping ERRor */
-#define EIR_MER 0x1000 /* Memory parity ERRor */
-#define EIR_ILLOP 0x2000 /* ILLegal OPcode */
-#define EIR_PRIVOP 0x4000 /* PRiviledged OPeration */
-#define EIR_TIMEOUT 0x8000 /* TILINE TIMEOUT */
-
-#endif
-
-
-/* Offsets for registers. */
-#define R0 0
-#define R1 2
-#define R2 4
-#define R3 6
-#define R4 8
-#define R5 10
-#define R6 12
-#define R7 14
-#define R8 16
-#define R9 18
-#define R10 20
-#define R11 22
-#define R12 24
-#define R13 26
-#define R14 28
-#define R15 30
-
-struct map_file_t
-{
- UINT16 L[3], B[3]; /* actual registers */
- UINT32 limit[3], bias[3]; /* equivalent in a more convenient form */
-};
-
-struct tms99xx_state
-{
-/* "actual" tms9900 registers : */
- UINT16 WP; /* Workspace pointer */
- UINT16 PC; /* Program counter */
- UINT16 STATUS; /* STatus register */
-
-/* Now, data used for emulation */
- UINT8 lastparity;
- char lds_flag, ldd_flag;
- UINT16 IR; /* Instruction register, with the currently parsed opcode */
-
- UINT8 interrupt_pending; /* true if an interrupt must be honored... */
-
-#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
- UINT8 load_state; /* nonzero if the LOAD* line is active (low) */
-#endif
-
-#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
- /* On tms9900, we cache the state of INTREQ* and IC0-IC3 here */
- /* On tms9980/9981, we translate the state of IC0-IC2 to the equivalent state for a tms9900,
- and store the result here */
- UINT8 irq_level; /* when INTREQ* is active, interrupt level on IC0-IC3 ; else always 16 */
- UINT8 irq_state; /* nonzero if the INTREQ* line is active (low) */
- /* with TMS9940, bit 0 means INT1, bit 1 decrementer, bit 2 INT2 */
-#elif (TMS99XX_MODEL == TMS9995_ID)
- /* tms9995 is quite different : it latches the interrupt inputs */
- UINT8 irq_level; /* We store the level of the request with the highest level here */
- UINT8 int_state; /* interrupt lines state */
- UINT8 int_latch; /* interrupt latches state */
-#endif
-
- /* interrupt callback */
- /* note that this callback is used by tms9900_set_irq_line(cpustate) and tms9980a_set_irq_line(cpustate) to
- retreive the value on IC0-IC3 (non-standard behaviour) */
- device_irq_acknowledge_delegate irq_callback;
- legacy_cpu_device *device;
- address_space *program;
- address_space *io;
- int icount;
-
- UINT8 IDLE; /* nonzero if processor is IDLE - i.e waiting for interrupt while writing
- special data on CRU bus */
-
-#if HAS_MAPPING
- UINT8 mapping_on; /* set by a CRU write */
- map_file_t map_files[3]; /* internal mapper registers */
- UINT8 cur_map; /* equivalent to ST_MF status bit */
- UINT8 cur_src_map; /* set to 2 by LDS */
- UINT8 cur_dst_map; /* set to 2 by LDD */
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- UINT8 reset_maperr; /* reset mapper error flag line (reset flags in 945417-9701 p. 3-90) */
-
- UINT32 mapper_address_latch; /* used to load the map file and for diagnostic purpose */
- UINT16 mapper_cru_read_register; /* read register select code for mapper cru interface */
- UINT8 diaglat; /* set when diagnostic address latch is done */
- UINT8 latch_control[3]; /* latch control */
-
-#endif
-#endif
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- UINT16 error_interrupt_register; /* one flag for each interrupt condition */
- ti99xx_error_interrupt_func error_interrupt_callback;
-#endif
-
-#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
- UINT8 RAM[256]; /* on-chip RAM (I know this is weird, but the internal bus is 16-bit-wide, whereas the external bus is 8-bit-wide) */
-#endif
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
- /* on-chip event counter/timer*/
- UINT8 decrementer_enabled;
- UINT16 decrementer_interval;
- UINT16 decrementer_count; /* used in event counter mode*/
- emu_timer *timer; /* used in timer mode */
-#endif
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- /* additionnal registers */
- UINT16 flag; /* flag register */
- UINT8 MID_flag; /* MID flag register */
-
- /* chip config, which can be set on reset */
- UINT8 memory_wait_states_byte;
- UINT8 memory_wait_states_word;
-
- /* mask option (off on normal tms9995) */
- UINT8 is_mp9537;
-#endif
-
- /* Some instructions (i.e. XOP, BLWP, and MID) disable interrupt recognition until another
- instruction is executed : so they set this flag */
- UINT8 disable_interrupt_recognition;
-
- /* notify the driver of changes in IDLE state */
- ti99xx_idle_func idle_callback;
-
-#if EXTERNAL_INSTRUCTION_CALLBACK
- ti99xx_rset_func rset_callback;
- ti99xx_lrex_func lrex_callback;
- ti99xx_ckon_ckof_func ckon_ckof_callback;
-#endif
-
- int write_inhibit;
- int extra_byte; /* buffer holding the unused byte in a word read */
-};
-
-INLINE tms99xx_state *get_safe_token(device_t *device)
-{
- assert(device != NULL);
-// assert(device->type() == TMS99XX_GET_INFO);
- return (tms99xx_state *)downcast<legacy_cpu_device *>(device)->token();
-}
-
-#if (TMS99XX_MODEL == TMS9995_ID)
-static void reset_decrementer(tms99xx_state *cpustate);
-#endif
-
-
-#if (TMS99XX_MODEL == TI990_10_ID)
-
-/*
- accessor for the internal ROM
-*/
-READ16_HANDLER(ti990_10_internal_r)
-{
- //return cpustate->ROM[offset];
- return space.read_word(0x1ffc00+offset);
-}
-
-#endif
-
-#if (TMS99XX_MODEL == TMS9995_ID)
-
-/*
- accessor for the first 252 bytes of internal RAM
-*/
-READ8_HANDLER(tms9995_internal1_r)
-{
- tms99xx_state *cpustate = get_safe_token(&space.device());
- return cpustate->RAM[offset];
-}
-
-WRITE8_HANDLER(tms9995_internal1_w)
-{
- tms99xx_state *cpustate = get_safe_token(&space.device());
- cpustate->RAM[offset]=data;
-}
-
-/*
- accessor for the last 4 bytes of internal RAM
-*/
-READ8_HANDLER(tms9995_internal2_r)
-{
- tms99xx_state *cpustate = get_safe_token(&space.device());
- return cpustate->RAM[offset+0xfc];
-}
-
-WRITE8_HANDLER(tms9995_internal2_w)
-{
- tms99xx_state *cpustate = get_safe_token(&space.device());
- cpustate->RAM[offset+0xfc]=data;
-}
-
-#endif
-
-#if (TMS99XX_MODEL == TI990_10_ID)
-
- /* on-board ROMs are not emulated (we use a hack) */
-
- #define readword(cs, addr) readwordX((cs), (addr), (cs)->cur_map)
- static int readwordX(tms99xx_state *cpustate, int addr, int map_file)
- {
- if ((map_file == 0) && (addr >= 0xf800))
- { /* intercept TPCS and CPU ROM */
- if (addr < 0xfc00)
- /* TPCS */
- return cpustate->program->read_word(0x1f0000+addr);
- else
- /* CPU ROM */
- return cpustate->program->read_word(0x1f0000+addr); /* hack... */
- }
- else if (! cpustate->mapping_on)
- {
- return cpustate->program->read_word(addr);
- }
- else
- {
- int map_index;
-
- if (addr <= cpustate->map_files[map_file].limit[0])
- map_index = 0;
- else if (addr <= cpustate->map_files[map_file].limit[1])
- map_index = 1;
- else if (addr <= cpustate->map_files[map_file].limit[2])
- map_index = 2;
- else
- { /* mapping error */
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = addr;
- if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR))
- {
- cpustate->error_interrupt_register |= EIR_MAPERR;
- cpustate->write_inhibit = 1;
- }
- return cpustate->program->read_word(addr);
- }
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr;
- if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr))
- cpustate->diaglat = 1;
- return cpustate->program->read_word(cpustate->map_files[map_file].bias[map_index]+addr);
- }
- }
-
- #define writeword(cs, addr, data) writewordX((cs), (addr), (data), (cs)->cur_map)
- static void writewordX(tms99xx_state *cpustate, int addr, int data, int map_file)
- {
- if ((map_file == 0) && (addr >= 0xf800))
- { /* intercept TPCS and CPU ROM */
- if (addr < 0xfc00)
- /* TPCS */
- cpustate->program->write_word(0x1f0000+addr, data);
- else
- /* CPU ROM */
- cpustate->program->write_word(0x1f0000+addr, data); /* hack... */
- }
- else if (! cpustate->mapping_on)
- {
- cpustate->program->write_word(addr, data);
- }
- else
- {
- int map_index;
-
- if (addr <= cpustate->map_files[map_file].limit[0])
- map_index = 0;
- else if (addr <= cpustate->map_files[map_file].limit[1])
- map_index = 1;
- else if (addr <= cpustate->map_files[map_file].limit[2])
- map_index = 2;
- else
- { /* mapping error */
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = addr;
- if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR))
- {
- cpustate->error_interrupt_register |= EIR_MAPERR;
- cpustate->write_inhibit = 1;
- }
- if (cpustate->write_inhibit)
- (void)cpustate->program->read_word(addr);
- else
- cpustate->program->write_word(addr, data);
- return;
- }
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr;
- if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr))
- cpustate->diaglat = 1;
- cpustate->program->write_word(cpustate->map_files[map_file].bias[map_index]+addr, data);
- }
- }
-
- #define readbyte(cs, addr) readbyteX((cs), (addr), (cs)->cur_map)
- static int readbyteX(tms99xx_state *cpustate, int addr, int map_file)
- {
- if ((map_file == 0) && (addr >= 0xf800))
- { /* intercept TPCS and CPU ROM */
- if (addr < 0xfc00)
- /* TPCS */
- return cpustate->program->read_byte(0x1f0000+addr);
- else
- /* CPU ROM */
- return cpustate->program->read_byte(0x1f0000+addr); /* hack... */
- }
- else if (! cpustate->mapping_on)
- {
- return cpustate->program->read_byte(addr);
- }
- else
- {
- int map_index;
-
- if (addr <= cpustate->map_files[map_file].limit[0])
- map_index = 0;
- else if (addr <= cpustate->map_files[map_file].limit[1])
- map_index = 1;
- else if (addr <= cpustate->map_files[map_file].limit[2])
- map_index = 2;
- else
- { /* mapping error */
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = addr;
- if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR))
- {
- cpustate->error_interrupt_register |= EIR_MAPERR;
- cpustate->write_inhibit = 1;
- }
- return cpustate->program->read_byte(addr);
- }
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr;
- if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr))
- cpustate->diaglat = 1;
- return cpustate->program->read_byte(cpustate->map_files[map_file].bias[map_index]+addr);
- }
- }
-
- #define writebyte(cs, addr, data) writebyteX((cs), (addr), (data), (cs)->cur_map)
- static void writebyteX(tms99xx_state *cpustate, int addr, int data, int map_file)
- {
- if ((map_file == 0) && (addr >= 0xf800))
- { /* intercept TPCS and CPU ROM */
- if (addr < 0xfc00)
- /* TPCS */
- cpustate->program->write_byte(0x1f0000+addr, data);
- else
- /* CPU ROM */
- cpustate->program->write_byte(0x1f0000+addr, data); /* hack... */
- }
- else if (! cpustate->mapping_on)
- {
- cpustate->program->write_byte(addr, data);
- }
- else
- {
- int map_index;
-
- if (addr <= cpustate->map_files[map_file].limit[0])
- map_index = 0;
- else if (addr <= cpustate->map_files[map_file].limit[1])
- map_index = 1;
- else if (addr <= cpustate->map_files[map_file].limit[2])
- map_index = 2;
- else
- { /* mapping error */
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = addr;
- if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR))
- {
- cpustate->error_interrupt_register |= EIR_MAPERR;
- cpustate->write_inhibit = 1;
- }
- if (cpustate->write_inhibit)
- (void)cpustate->program->read_byte(addr);
- else
- cpustate->program->write_byte(addr, data);
- return;
- }
- if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat))
- cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr;
- if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr))
- cpustate->diaglat = 1;
- cpustate->program->write_byte(cpustate->map_files[map_file].bias[map_index]+addr, data);
- }
- }
-
-#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID)
- /*16-bit data bus, 16-bit address bus (internal bus in the case of TMS9940)*/
- /*Note that tms9900 actually never accesses a single byte : when performing byte operations,
- it reads a 16-bit word, changes the relevant byte, then write a complete word. You should
- remember this when writing memory handlers.*/
- /*This does not apply to tms9995 and tms99xxx, but does apply to tms9980 (see below).*/
-
- #define readword(cs, addr) (cs)->program->read_word(addr)
- #define writeword(cs, addr,data) (cs)->program->write_word((addr), (data))
-
- #define readbyte(cs, addr) (cs)->program->read_byte(addr)
- #define writebyte(cs, addr,data) (cs)->program->write_byte((addr),(data))
-
-#elif (TMS99XX_MODEL == TMS9980_ID)
- /*8-bit data bus, 14-bit address*/
- /*Note that tms9980 never accesses a single byte (however crazy it may seem). Although this
- makes memory access slower, I have emulated this feature, because if I did otherwise,
- there would be some implementation problems in some driver sooner or later.*/
-
- INLINE int readword(tms99xx_state *cpustate, int addr)
- {
- int val;
-
- cpustate->icount -= 2;
- val = cpustate->program->read_byte(addr);
- return (val << 8) | cpustate->program->read_byte(addr+1);
- }
- #define writeword(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr), (data) >> 8); cpustate->program->write_byte((addr) + 1, (data) & 0xff); }
-
-#if 0
- #define readbyte(cs, addr) ((cs)->icount -= 2, (cs)->program->read_byte(addr))
- #define writebyte(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr),(data)); }
-#else
- /*This is how it really works*/
- /*Note that every writebyte must match a readbyte (which is indeed the case)*/
-
- static int readbyte(tms99xx_state *cpustate, int addr)
- {
- cpustate->icount -= 2;
- if (addr & 1)
- {
- cpustate->extra_byte = cpustate->program->read_byte(addr-1);
- return cpustate->program->read_byte(addr);
- }
- else
- {
- int val = cpustate->program->read_byte(addr);
- cpustate->extra_byte = cpustate->program->read_byte(addr+1);
- return val;
- }
- }
- static void writebyte (tms99xx_state *cpustate, int addr, int data)
- {
- cpustate->icount -= 2;
- if (addr & 1)
- {
- cpustate->program->write_byte(addr-1, cpustate->extra_byte);
- cpustate->program->write_byte(addr, data);
- }
- else
- {
- cpustate->program->write_byte(addr, data);
- cpustate->program->write_byte(addr+1, cpustate->extra_byte);
- }
- }
-#endif
-
-#elif (TMS99XX_MODEL == TMS9985_ID)
- /*Note that every writebyte must match a readbyte (which is indeed the case)*/
-
- static int readword(tms99xx_state *cpustate, int addr)
- {
- if (addr < 0x2000)
- {
- }
- else if ((addr >= 0x8300) && (addr < 0x8400))
- {
- }
- else
- {
- cpustate->icount -= 2;
- return (cpustate->program->read_byte(addr) << 8) + cpustate->program->read_byte(addr + 1);
- }
- }
- static void writeword(tms99xx_state *cpustate, int addr, int data)
- {
- if ((addr >= 0x8300) && (addr < 0x8400))
- {
- }
- else if (!(addr < 0x2000))
- {
- cpustate->icount -= 2;
- cpustate->program->write_byte(addr, data >> 8);
- cpustate->program->write_byte(addr + 1, data & 0xff);
- }
- }
-
- static int readbyte(tms99xx_state *cpustate, int addr)
- {
- if (addr < 0x2000)
- {
- }
- else if ((addr >= 0x8300) && (addr < 0x8400))
- {
- }
- else
- {
- cpustate->icount -= 2;
- if (addr & 1)
- {
- cpustate->extra_byte = cpustate->program->read_byte(addr-1);
- return cpustate->program->read_byte(addr);
- }
- else
- {
- int val = cpustate->program->read_byte(addr);
- cpustate->extra_byte = cpustate->program->read_byte(addr+1);
- return val;
- }
- }
- }
- static void writebyte(tms99xx_state *cpustate, int addr, int data)
- {
- if ((addr >= 0x8300) && (addr < 0x8400))
- {
- }
- else if (!(addr < 0x2000))
- {
- cpustate->icount -= 2;
- if (addr & 1)
- {
- cpustate->program->write_byte(addr-1, cpustate->extra_byte);
- cpustate->program->write_byte(addr, data);
- }
- else
- {
- cpustate->program->write_byte(addr, data);
- cpustate->program->write_byte(addr+1, cpustate->extra_byte);
- }
- }
- }
-
-#elif (TMS99XX_MODEL == TMS9995_ID)
- /*8-bit external data bus, with on-chip 16-bit RAM, and 16-bit address bus*/
- /*The code is complex, so we use functions rather than macros*/
-
- static TIMER_CALLBACK( decrementer_callback );
-
- static int readword(tms99xx_state *cpustate, int addr)
- {
- if ((addr < 0xf000) || (cpustate->is_mp9537))
- {
- int reply;
- cpustate->icount -= cpustate->memory_wait_states_word;
- reply = cpustate->program->read_byte(addr);
- return (reply << 8) | cpustate->program->read_byte(addr + 1);
- }
- else if (addr < 0xf0fc)
- {
- return *(UINT16 *)(& cpustate->RAM[addr - 0xf000]);
- }
- else if (addr < 0xfffa)
- {
- int reply;
- cpustate->icount -= cpustate->memory_wait_states_word;
- reply = cpustate->program->read_byte(addr);
- return (reply << 8) | cpustate->program->read_byte(addr + 1);
- }
- else if (addr < 0xfffc)
- {
- /* read decrementer */
- if (cpustate->decrementer_enabled && !(cpustate->flag & 1))
- /* timer mode, timer enabled */
- return cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16);
- else
- /* event counter mode or timer mode, timer disabled */
- return cpustate->decrementer_count;
- }
- else
- {
- return *(UINT16 *)(& cpustate->RAM[addr - 0xff00]);
- }
- }
-
- static void writeword (tms99xx_state *cpustate, int addr, int data)
- {
- if ((addr < 0xf000) || (cpustate->is_mp9537))
- {
- cpustate->icount -= cpustate->memory_wait_states_word;
- cpustate->program->write_byte(addr, data >> 8);
- cpustate->program->write_byte(addr + 1, data & 0xff);
- }
- else if (addr < 0xf0fc)
- {
- *(UINT16 *)(& cpustate->RAM[addr - 0xf000]) = data;
- }
- else if (addr < 0xfffa)
- {
- cpustate->icount -= cpustate->memory_wait_states_word;
- cpustate->program->write_byte(addr, data >> 8);
- cpustate->program->write_byte(addr + 1, data & 0xff);
- }
- else if (addr < 0xfffc)
- {
- /* write decrementer */
- cpustate->decrementer_interval = data;
- reset_decrementer(cpustate);
- }
- else
- {
- *(UINT16 *)(& cpustate->RAM[addr - 0xff00]) = data;
- }
- }
-
- static int readbyte(tms99xx_state *cpustate, int addr)
- {
- if ((addr < 0xf000) || (cpustate->is_mp9537))
- {
- cpustate->icount -= cpustate->memory_wait_states_byte;
- return cpustate->program->read_byte(addr);
- }
- else if (addr < 0xf0fc)
- {
- return cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)];
- }
- else if (addr < 0xfffa)
- {
- cpustate->icount -= cpustate->memory_wait_states_byte;
- return cpustate->program->read_byte(addr);
- }
- else if (addr < 0xfffc)
- {
- /* read decrementer */
- int value;
-
- if (cpustate->decrementer_enabled && !(cpustate->flag & 1))
- /* timer mode, timer enabled */
- value = cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16);
- else
- /* event counter mode or timer mode, timer disabled */
- value = cpustate->decrementer_count;
-
- if (addr & 1)
- return (value & 0xFF);
- else
- return (value >> 8);
- }
- else
- {
- return cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)];
- }
- }
-
- static void writebyte (tms99xx_state *cpustate, int addr, int data)
- {
- if ((addr < 0xf000) || (cpustate->is_mp9537))
- {
- cpustate->icount -= cpustate->memory_wait_states_byte;
- cpustate->program->write_byte(addr, data);
- }
- else if (addr < 0xf0fc)
- {
- cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)] = data;
- }
- else if (addr < 0xfffa)
- {
- cpustate->icount -= cpustate->memory_wait_states_byte;
- cpustate->program->write_byte(addr, data);
- }
- else if (addr < 0xfffc)
- {
- /* write decrementer */
- /* Note that a byte write to tms9995 timer messes everything up. */
- cpustate->decrementer_interval = (data << 8) | data;
- reset_decrementer(cpustate);
- }
- else
- {
- cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)] = data;
- }
- }
-
-#else
-
- #error "memory access not implemented"
-
-#endif
-
-#if !HAS_MAPPING
- #define readwordX(cs, addr, map_file) readword(cs, addr)
- #define writewordX(cs, addr, data, map_file) writeword(cs, (addr), (data))
- #define readbyteX(cs, addr, map_file) readbyte(cs, addr)
- #define writebyteX(cs, addr, data, map_file) writebyte(cs, (addr), (data))
-#endif
-
-#define READREG(reg) readword(cpustate, (cpustate->WP+(reg)) & 0xffff)
-#define WRITEREG(reg, data) writeword(cpustate, (cpustate->WP+(reg)) & 0xffff, (data))
-
-INLINE UINT16 READREG_DEBUG(tms99xx_state *cpustate, int reg)
-{
- int temp = cpustate->icount;
- UINT16 result = READREG(reg);
- cpustate->icount = temp;
- return result;
-}
-
-INLINE void WRITEREG_DEBUG(tms99xx_state *cpustate, int reg, UINT16 data)
-{
- int temp = cpustate->icount;
- WRITEREG(reg, data);
- cpustate->icount = temp;
-}
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- READ8_HANDLER(ti990_10_mapper_cru_r)
- {
- tms99xx_state *cpustate = get_safe_token(&space.device());
- int reply = 0;
-
- switch(cpustate->mapper_cru_read_register)
- {
- case 0xb000:
- reply = cpustate->map_files[cpustate->cur_map].B[0];
- break;
- case 0xb001:
- reply = cpustate->map_files[cpustate->cur_map].B[1];
- break;
- case 0xb010:
- reply = cpustate->map_files[cpustate->cur_map].B[2];
- break;
- case 0xb011:
- reply = cpustate->map_files[cpustate->cur_map].L[0];
- break;
- case 0xb100:
- reply = cpustate->map_files[cpustate->cur_map].L[1];
- break;
- case 0xb101:
- reply = cpustate->map_files[cpustate->cur_map].L[2];
- break;
- case 0xb110:
- reply = cpustate->mapper_address_latch;
- break;
- case 0xb111:
- reply = cpustate->mapper_address_latch >> 16;
- break;
- }
-
- if (offset)
- return (reply >> 8) & 0xff;
- else
- return reply & 0xff;
- }
-
- WRITE8_HANDLER(ti990_10_mapper_cru_w)
- {
- tms99xx_state *cpustate = get_safe_token(&space.device());
- switch (offset)
- {
- case 0:
- case 1:
- case 2:
- /* read register select */
- if (data)
- cpustate->mapper_cru_read_register |= (1 << offset);
- else
- cpustate->mapper_cru_read_register &= ~ (1 << offset);
- break;
- case 3:
- /* enable mapping */
- cpustate->mapping_on = data;
- break;
- case 4:
- /* reset flags */
- cpustate->reset_maperr = data;
- if (data)
- {
- cpustate->error_interrupt_register &= ~ EIR_MAPERR;
- cpustate->diaglat = 0;
- }
- break;
- case 5:
- case 6:
- case 7:
- /* latch control */
- cpustate->latch_control[7-offset] = data;
- break;
- }
- }
-
- INLINE void handle_error_interrupt(tms99xx_state *cpustate)
- {
- if (cpustate->error_interrupt_callback)
- (*cpustate->error_interrupt_callback)(cpustate->device, cpustate->error_interrupt_register ? 1 : 0);
- }
-
- READ8_HANDLER(ti990_10_eir_cru_r)
- {
- tms99xx_state *cpustate = get_safe_token(&space.device());
- return (offset == 1) ? (cpustate->error_interrupt_register & 0xff) : 0;
- }
-
- WRITE8_HANDLER(ti990_10_eir_cru_w)
- {
- tms99xx_state *cpustate = get_safe_token(&space.device());
- if (offset < 4) /* does not work for EIR_MAPERR */
- {
- cpustate->error_interrupt_register &= ~ (1 << offset);
-
- handle_error_interrupt(cpustate);
- }
- }
-
-
-#endif
-
-/* Interrupt mask */
-#define IMASK (cpustate->STATUS & ST_IM)
-
-/*
- CYCLES macro : you provide timings for tms9900 and tms9995, and the macro chooses for you.
-
- BTW, I have no idea what the timings are for tms9989 and tms99xxx...
-*/
-#if TMS99XX_MODEL == TI990_10_ID
- /* Use TI990/10 timings*/
- #define CYCLES(a,b,c) cpustate->icount -= a
-#elif TMS99XX_MODEL <= TMS9985_ID
- /* Use TMS9900/TMS9980 timings*/
- #define CYCLES(a,b,c) cpustate->icount -= b
-#else
- /* Use TMS9995 timings*/
- #define CYCLES(a,b,c) cpustate->icount -= c*4
-#endif
-
-#if (TMS99XX_MODEL == TMS9995_ID)
-
-static void set_flag0(tms99xx_state *cpustate, int val);
-static void set_flag1(tms99xx_state *cpustate, int val);
-
-#endif
-
-/************************************************************************
- * Status register functions
- ************************************************************************/
-
-/*
- remember that the OP ST bit is maintained in cpustate->lastparity
-*/
-
-/*
- setstat sets the ST_OP bit according to cpustate->lastparity
-
- It must be called before reading the ST register.
-*/
-
-static void setstat(tms99xx_state *cpustate)
-{
- int i;
- UINT8 a;
-
- cpustate->STATUS &= ~ ST_OP;
-
- /* We set the parity bit. */
- a = cpustate->lastparity;
-
- for (i=0; i<8; i++) /* 8 bits to test */
- {
- if (a & 1) /* If current bit is set */
- cpustate->STATUS ^= ST_OP; /* we toggle the ST_OP bit */
-
- a >>= 1; /* Next bit. */
- }
-}
-
-/*
- getstat sets emulator's cpustate->lastparity variable according to 9900's STATUS bits.
- It must be called on interrupt return, or when, for some reason,
- the emulated program sets the STATUS register directly.
-*/
-static void getstat(tms99xx_state *cpustate)
-{
-#if (USE_ST_MASK)
- cpustate->STATUS &= ST_MASK; /* unused bits are forced to 0 */
-#endif
-
- if (cpustate->STATUS & ST_OP)
- cpustate->lastparity = 1;
- else
- cpustate->lastparity = 0;
-
-#if HAS_MAPPING
- cpustate->cur_map = (cpustate->STATUS & ST_MF) ? 1 : 0;
-#endif
-}
-
-/*
- A few words about the following functions.
-
- A big portability issue is the behavior of the ">>" instruction with the sign bit, which has
- not been normalised. Every compiler does whatever it thinks smartest.
- My code assumed that when shifting right signed numbers, the operand is left-filled with a
- copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s.
- This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time
- (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers
- are bound to disagree.
-
- So, I had to create special functions with predefined tables included, so that this code work
- on every compiler. BUT this is a real slow-down.
- So, you might have to include a few lines in assembly to make this work better.
- Sorry about this, this problem is really unpleasant and absurd, but it is not my fault.
-*/
-
-
-static const UINT16 right_shift_mask_table[17] =
-{
- 0xFFFF,
- 0x7FFF,
- 0x3FFF,
- 0x1FFF,
- 0x0FFF,
- 0x07FF,
- 0x03FF,
- 0x01FF,
- 0x00FF,
- 0x007F,
- 0x003F,
- 0x001F,
- 0x000F,
- 0x0007,
- 0x0003,
- 0x0001,
- 0x0000
-};
-
-static const UINT16 inverted_right_shift_mask_table[17] =
-{
- 0x0000,
- 0x8000,
- 0xC000,
- 0xE000,
- 0xF000,
- 0xF800,
- 0xFC00,
- 0xFE00,
- 0xFF00,
- 0xFF80,
- 0xFFC0,
- 0xFFE0,
- 0xFFF0,
- 0xFFF8,
- 0xFFFC,
- 0xFFFE,
- 0xFFFF
-};
-
-INLINE UINT16 logical_right_shift(UINT16 val, int c)
-{
- return((val>>c) & right_shift_mask_table[c]);
-}
-
-INLINE INT16 arithmetic_right_shift(INT16 val, int c)
-{
- if (val < 0)
- return((val>>c) | inverted_right_shift_mask_table[c]);
- else
- return((val>>c) & right_shift_mask_table[c]);
-}
-
-
-
-
-
-/*
- Set lae
-*/
-INLINE void setst_lae(tms99xx_state *cpustate, INT16 val)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
-
- if (val > 0)
- cpustate->STATUS |= (ST_LGT | ST_AGT);
- else if (val < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-}
-
-
-/*
- Set laep (BYTE)
-*/
-INLINE void setst_byte_laep(tms99xx_state *cpustate, INT8 val)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
-
- if (val > 0)
- cpustate->STATUS |= (ST_LGT | ST_AGT);
- else if (val < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- cpustate->lastparity = val;
-}
-
-/*
- For COC, CZC, and TB
-*/
-INLINE void setst_e(tms99xx_state *cpustate, UINT16 val, UINT16 to)
-{
- if (val == to)
- cpustate->STATUS |= ST_EQ;
- else
- cpustate->STATUS &= ~ ST_EQ;
-}
-
-/*
- For CI, C, CB
-*/
-INLINE void setst_c_lae(tms99xx_state *cpustate, UINT16 to, UINT16 val)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
-
- if (val == to)
- cpustate->STATUS |= ST_EQ;
- else
- {
- if ( ((INT16) val) > ((INT16) to) )
- cpustate->STATUS |= ST_AGT;
- if ( ((UINT16) val) > ((UINT16) to) )
- cpustate->STATUS |= ST_LGT;
- }
-}
-
-/*
- Set laeco for add
-*/
-INLINE INT16 setst_add_laeco(tms99xx_state *cpustate, int a, int b)
-{
- UINT32 res;
- INT16 res2;
-
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
-
- res = (a & 0xffff) + (b & 0xffff);
-
- if (res & 0x10000)
- cpustate->STATUS |= ST_C;
-
- if ((res ^ b) & (res ^ a) & 0x8000)
- cpustate->STATUS |= ST_OV;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (((a & b) | ((a | b) & ~ res)) & 0x0800)
- cpustate->STATUS |= ST_DC;
-#endif
-
- res2 = (INT16) res;
-
- if (res2 > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (res2 < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return res2;
-}
-
-
-/*
- Set laeco for subtract
-*/
-INLINE INT16 setst_sub_laeco(tms99xx_state *cpustate, int a, int b)
-{
- UINT32 res;
- INT16 res2;
-
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
-
- res = (a & 0xffff) - (b & 0xffff);
-
- if (! (res & 0x10000))
- cpustate->STATUS |= ST_C;
-
- if ((a ^ b) & (a ^ res) & 0x8000)
- cpustate->STATUS |= ST_OV;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800)
- cpustate->STATUS |= ST_DC;
-#endif
-
- res2 = (INT16) res;
-
- if (res2 > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (res2 < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return res2;
-}
-
-
-/*
- Set laecop for add (BYTE)
-*/
-INLINE INT8 setst_addbyte_laecop(tms99xx_state *cpustate, int a, int b)
-{
- unsigned int res;
- INT8 res2;
-
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
-
- res = (a & 0xff) + (b & 0xff);
-
- if (res & 0x100)
- cpustate->STATUS |= ST_C;
-
- if ((res ^ b) & (res ^ a) & 0x80)
- cpustate->STATUS |= ST_OV;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (((a & b) | ((a | b) & ~ res)) & 0x08)
- cpustate->STATUS |= ST_DC;
-#endif
-
- res2 = (INT8) res;
-
- if (res2 > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (res2 < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- cpustate->lastparity = res2;
-
- return res2;
-}
-
-
-/*
- Set laecop for subtract (BYTE)
-*/
-INLINE INT8 setst_subbyte_laecop(tms99xx_state *cpustate, int a, int b)
-{
- unsigned int res;
- INT8 res2;
-
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
-
- res = (a & 0xff) - (b & 0xff);
-
- if (! (res & 0x100))
- cpustate->STATUS |= ST_C;
-
- if ((a ^ b) & (a ^ res) & 0x80)
- cpustate->STATUS |= ST_OV;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08)
- cpustate->STATUS |= ST_DC;
-#endif
-
- res2 = (INT8) res;
-
- if (res2 > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (res2 < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- cpustate->lastparity = res2;
-
- return res2;
-}
-
-
-
-/*
- For NEG
-*/
-INLINE void setst_laeo(tms99xx_state *cpustate, INT16 val)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV);
-
- if (val > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (val < 0)
- {
- cpustate->STATUS |= ST_LGT;
- if (((UINT16) val) == 0x8000)
- cpustate->STATUS |= ST_OV;
- }
- else
- cpustate->STATUS |= ST_EQ;
-}
-
-
-
-/*
- Meat of SRA
-*/
-INLINE UINT16 setst_sra_laec(tms99xx_state *cpustate, INT16 a, UINT16 c)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
-
- if (c != 0)
- {
- a = arithmetic_right_shift(a, c-1);
- if (a & 1) // The carry bit equals the last bit that is shifted out
- cpustate->STATUS |= ST_C;
- a = arithmetic_right_shift(a, 1);
- }
-
- if (a > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (a < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return a;
-}
-
-
-/*
- Meat of SRL. Same algorithm as SRA, except that we fills in with 0s.
-*/
-INLINE UINT16 setst_srl_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
-
- if (c != 0)
- {
- a = logical_right_shift(a, c-1);
- if (a & 1)
- cpustate->STATUS |= ST_C;
- a = logical_right_shift(a, 1);
- }
-
- if (((INT16) a) > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (((INT16) a) < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return a;
-}
-
-
-//
-// Meat of SRC
-//
-INLINE UINT16 setst_src_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
-
- if (c != 0)
- {
- a = logical_right_shift(a, c) | (a << (16-c));
- if (a & 0x8000) // The carry bit equals the last bit that is shifted out
- cpustate->STATUS |= ST_C;
- }
-
- if (((INT16) a) > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (((INT16) a) < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return a;
-}
-
-
-//
-// Meat of SLA
-//
-INLINE UINT16 setst_sla_laeco(tms99xx_state *cpustate, UINT16 a, UINT16 c)
-{
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
-
- if (c != 0)
- {
- {
- register UINT16 mask;
- register UINT16 ousted_bits;
-
- mask = 0xFFFF << (16-c-1);
- ousted_bits = a & mask;
-
- if (ousted_bits) // If ousted_bits is neither all 0s
- if (ousted_bits ^ mask) // nor all 1s,
- cpustate->STATUS |= ST_OV; // we set overflow
- }
-
- a <<= c-1;
- if (a & 0x8000) // The carry bit equals the last bit that is shifted out
- cpustate->STATUS |= ST_C;
-
- a <<= 1;
- }
-
- if (((INT16) a) > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (((INT16) a) < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- return a;
-}
-
-/**************************************************************************/
-
-static void register_for_save_state(device_t *device)
-{
- tms99xx_state *cpustate = get_safe_token(device);
- device->save_item(NAME(cpustate->WP));
- device->save_item(NAME(cpustate->PC));
- device->save_item(NAME(cpustate->STATUS));
- device->save_item(NAME(cpustate->interrupt_pending));
-
-#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
- device->save_item(NAME(cpustate->load_state));
-#endif
-
-#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
- device->save_item(NAME(cpustate->irq_level));
- device->save_item(NAME(cpustate->irq_state));
-#elif (TMS99XX_MODEL == TMS9995_ID)
- device->save_item(NAME(cpustate->irq_level));
- device->save_item(NAME(cpustate->int_state));
- device->save_item(NAME(cpustate->int_latch));
-#endif
-
- device->save_item(NAME(cpustate->IDLE));
-
-#if HAS_MAPPING
- device->save_item(NAME(cpustate->mapping_on));
- device->save_item(NAME(cpustate->map_files[0].L));
- device->save_item(NAME(cpustate->map_files[0].B));
- device->save_item(NAME(cpustate->map_files[0].limit));
- device->save_item(NAME(cpustate->map_files[0].bias));
- device->save_item(NAME(cpustate->map_files[1].L));
- device->save_item(NAME(cpustate->map_files[1].B));
- device->save_item(NAME(cpustate->map_files[1].limit));
- device->save_item(NAME(cpustate->map_files[1].bias));
- device->save_item(NAME(cpustate->map_files[2].L));
- device->save_item(NAME(cpustate->map_files[2].B));
- device->save_item(NAME(cpustate->map_files[2].limit));
- device->save_item(NAME(cpustate->map_files[2].bias));
- device->save_item(NAME(cpustate->cur_map));
- device->save_item(NAME(cpustate->cur_src_map));
- device->save_item(NAME(cpustate->cur_dst_map));
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- device->save_item(NAME(cpustate->reset_maperr));
- device->save_item(NAME(cpustate->mapper_address_latch));
- device->save_item(NAME(cpustate->mapper_cru_read_register));
- device->save_item(NAME(cpustate->diaglat));
- device->save_item(NAME(cpustate->latch_control));
-#endif
-#endif
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- device->save_item(NAME(cpustate->error_interrupt_register));
-#endif
-
-#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
- device->save_item(NAME(cpustate->RAM));
-#endif
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
- device->save_item(NAME(cpustate->decrementer_enabled));
- device->save_item(NAME(cpustate->decrementer_interval));
- device->save_item(NAME(cpustate->decrementer_count));
-#endif
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- device->save_item(NAME(cpustate->flag));
- device->save_item(NAME(cpustate->MID_flag));
- device->save_item(NAME(cpustate->memory_wait_states_byte));
- device->save_item(NAME(cpustate->memory_wait_states_word));
- device->save_item(NAME(cpustate->is_mp9537));
-#endif
-
- device->save_item(NAME(cpustate->disable_interrupt_recognition));
-}
-
-
-static CPU_INIT( tms99xx )
-{
- const TMS99XX_RESET_PARAM *param = (const TMS99XX_RESET_PARAM *) device->static_config();
- tms99xx_state *cpustate = get_safe_token(device);
-
- register_for_save_state(device);
-
- cpustate->irq_level = 16;
- cpustate->irq_callback = irqcallback;
- cpustate->device = device;
- cpustate->program = &device->space(AS_PROGRAM);
- cpustate->io = &device->space(AS_IO);
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- cpustate->timer = device->machine().scheduler().timer_alloc(FUNC(decrementer_callback), cpustate);
-#endif
-
- cpustate->idle_callback = param ? param->idle_callback : NULL;
- #if (TMS99XX_MODEL == TI990_10_ID)
- cpustate->rset_callback = param ? param->rset_callback : NULL;
- cpustate->lrex_callback = param ? param->lrex_callback : NULL;
- cpustate->ckon_ckof_callback = param ? param->ckon_ckof_callback : NULL;
-
- cpustate->error_interrupt_callback = param ? param->error_interrupt_callback : NULL;
- #endif
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- /* we can ask at reset time that the CPU always generates one wait state automatically */
- if (param == NULL)
- { /* if no param, the default is currently "wait state added" */
- cpustate->memory_wait_states_byte = 4;
- cpustate->memory_wait_states_word = 12;
- cpustate->is_mp9537 = 0;
- }
- else
- {
- cpustate->memory_wait_states_byte = (param->auto_wait_state) ? 4 : 0;
- cpustate->memory_wait_states_word = (param->auto_wait_state) ? 12 : 4;
- cpustate->is_mp9537 = param->is_mp9537;
- }
-#endif
-
-}
-
-/*
- TMS9900 hard reset
-*/
-static CPU_RESET( tms99xx )
-{
- tms99xx_state *cpustate = get_safe_token(device);
-
- cpustate->STATUS = 0; /* TMS9980 and TMS9995 Data Books say so */
- getstat(cpustate);
-
- #if HAS_MAPPING
- cpustate->mapping_on = 0;
- {
- int i,j;
-
- for (i=0; i<3; i++)
- for (j=0; j<3; j++)
- {
- cpustate->map_files[i].L[j] = 0;
- cpustate->map_files[i].limit[j] = 0xffff;
- cpustate->map_files[i].B[j] = 0;
- cpustate->map_files[i].bias[j] = 0;
- }
- }
- cpustate->cur_map = 0; /* equivalent to ST_MF status bit */
- cpustate->cur_src_map = 0; /* set to 2 by LDS */
- cpustate->cur_dst_map = 0; /* set to 2 by LDD */
-
- cpustate->reset_maperr = 0;
- #endif
-
- if (cpustate->IDLE)
- {
- cpustate->IDLE = 0; /* clear IDLE condition */
- if (cpustate->idle_callback)
- (*cpustate->idle_callback)(device, 0);
- }
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- cpustate->MID_flag = 0;
-
- /* Clear flag bits 0 & 1 */
- set_flag0(cpustate, 0);
- set_flag1(cpustate, 0);
-
- /* Clear internal interrupt latches */
- cpustate->int_latch = 0;
- cpustate->flag &= 0xFFE3;
-#endif
-
- /* The ST register and interrupt latches changed, didn't they ? */
- field_interrupt(cpustate);
-
- contextswitchX(cpustate, 0x0000);
-
- CYCLES(6, 26, 14);
-}
-
-static CPU_EXIT( tms99xx )
-{
- /* nothing to do ? */
-}
-
-/* fetch : read one word at * PC, and increment PC. */
-INLINE UINT16 fetch(tms99xx_state *cpustate)
-{
- UINT16 value = readword(cpustate, cpustate->PC);
- cpustate->PC += 2;
- return value;
-}
-
-
-static CPU_EXECUTE( tms99xx )
-{
- tms99xx_state *cpustate = get_safe_token(device);
-
- cpustate->lds_flag = 0;
- cpustate->ldd_flag = 0;
-
- do
- {
- /* all TMS9900 chips I know do not honor interrupts after XOP, BLWP or MID (after any
- interrupt-like instruction, actually), and they do not either after LDS and LDD
- (There are good reasons for this). */
- if ((cpustate->interrupt_pending) && (! cpustate->disable_interrupt_recognition))
- {
- int level;
-
- level = cpustate->irq_level;
-
-
- if (cpustate->load_state)
- { /* LOAD has the highest priority */
-
- contextswitchX(cpustate, 0xFFFC); /* load vector, save PC, WP and ST */
-
- cpustate->STATUS &= ~ST_IM; /* clear interrupt mask */
-
- /* clear IDLE status if necessary */
- if (cpustate->IDLE)
- {
- cpustate->IDLE = 0; /* clear IDLE condition */
- if (cpustate->idle_callback)
- (*cpustate->idle_callback)(device, 0);
- }
-
- CYCLES(6/*to be confirmed*/, 22, 14);
- }
- else if (level <= IMASK)
- { /* a maskable interrupt is honored only if its level isn't greater than IMASK */
-
- contextswitchX(cpustate, level*4); /* load vector, save PC, WP and ST */
-
- /* change interrupt mask */
- if (level)
- {
- cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (level -1); /* decrement mask */
- cpustate->interrupt_pending = 0; /* as a consequence, the interrupt request will be subsequently ignored */
- }
- else
- cpustate->STATUS &= ~ST_IM; /* clear mask (is this correct???) */
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- cpustate->STATUS &= 0xFE00;
-#endif
-
- /* clear IDLE status if necessary */
- if (cpustate->IDLE)
- {
- cpustate->IDLE = 0; /* clear IDLE condition */
- if (cpustate->idle_callback)
- (*cpustate->idle_callback)(device, 0);
- }
-
-#if (TMS99XX_MODEL == TMS9995_ID)
- /* Clear bit in latch */
- /* I think tms9989 does this, too */
- if (level != 2)
- { /* Only do this on level 1, 3, 4 interrupts */
- int mask = 1 << level;
- int flag_mask = (level == 1) ? 4 : mask;
-
- cpustate->int_latch &= ~ mask;
- cpustate->flag &= ~ flag_mask;
-
- /* unlike tms9900, we can call the callback */
- if (level == 1)
- (* cpustate->irq_callback)(cpustate->device, 0);
- else if (level == 4)
- (* cpustate->irq_callback)(cpustate->device, 1);
- }
-#endif
-
- CYCLES(6, 22, 14);
- }
- else
- {
- logerror("tms9900l.c : the interrupt_pending flag was set incorrectly\n");
- cpustate->interrupt_pending = 0;
- }
- }
-
- debugger_instruction_hook(device, cpustate->PC);
-
- if (cpustate->IDLE)
- { /* IDLE instruction has halted execution */
- #if EXTERNAL_INSTRUCTION_DECODING
- external_instruction_notify(cpustate, 2);
- CYCLES(Moof!, 2, 2); /* 2 cycles per CRU write */
- #else
- cpustate->icount = 0; /* much simpler... */
- #endif
- }
- else
- { /* we execute an instruction */
- cpustate->disable_interrupt_recognition = 0; /* default value */
- cpustate->IR = fetch(cpustate);
- execute(cpustate, cpustate->IR);
- #if HAS_MAPPING
- if (cpustate->lds_flag)
- {
- cpustate->lds_flag = 0;
- cpustate->cur_src_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/;
- }
- else
- cpustate->cur_src_map = cpustate->cur_map;
- if (cpustate->ldd_flag)
- {
- cpustate->ldd_flag = 0;
- cpustate->cur_dst_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/;
- }
- else
- cpustate->cur_dst_map = cpustate->cur_map;
- #if (TMS99XX_MODEL == TI990_10_ID)
- cpustate->write_inhibit = 0;
- #endif
- #endif
-
- #if (HAS_OVERFLOW_INTERRUPT)
- #if (TMS99XX_MODEL == TMS9995_ID)
- /* Note that TI had some problem implementing this... I don't know if this feature works on
- a real-world TMS9995. */
- if ((cpustate->STATUS & ST_OVIE) && (cpustate->STATUS & ST_OV) && (cpustate->irq_level > 2))
- cpustate->irq_level = 2; /* interrupt request */
- #else
- #warning "todo..."
- #endif
- #endif
- }
-
- } while (cpustate->icount > 0);
-}
-
-#if (TMS99XX_MODEL == TI990_10_ID)
-
-static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state)
-{
- if (irqline == INPUT_LINE_NMI)
- {
- cpustate->load_state = state; /* save new state */
-
- field_interrupt(cpustate); /* interrupt status changed */
- }
- else
- {
- /*if (cpustate->irq_state == state)
- return;*/
-
- cpustate->irq_state = state;
-
- if (state == CLEAR_LINE)
- cpustate->irq_level = 16;
- /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
- else
- cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0);
-
- field_interrupt(cpustate); /* interrupt state is likely to have changed */
- }
-}
-
-#elif (TMS99XX_MODEL == TMS9900_ID)
-
-/*
-void tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, int state) : change the state of the LOAD* line
-
- state == 0 -> LOAD* goes high (inactive)
- state != 0 -> LOAD* goes low (active)
-
- While LOAD* is low, we keep triggering LOAD interrupts...
-
- A problem : some peripherals lower the LOAD* line for a fixed time interval (causing the 1st
- instruction of the LOAD interrupt routine to be repeated while the line is low), and will be
- perfectly happy with the current scheme, but others might be more clever and wait for the IAQ
- (Instruction acquisition) line to go high, and this needs a callback function to emulate.
-*/
-
-/*
-void tms99xx_set_irq_line(cpustate, int irqline, int state) : sets the state of the interrupt line.
-
- irqline is ignored, and should always be 0.
-
- state == 0 -> INTREQ* goes high (inactive)
- state != 0 -> INTREQ* goes low (active)
-*/
-/*
- R Nabet 991020, revised 991218 :
- In short : interrupt code should call "cpu_set_irq_line(0, 0, ASSERT_LINE);" to set an
- interrupt request (level-triggered interrupts). Also, there MUST be a call to
- "cpu_set_irq_line(0, 0, CLEAR_LINE);" in the machine code, when the interrupt line is released by
- the hardware (generally in response to an action performed by the interrupt routines).
- On tms9995 (9989 ?), you can use PULSE_LINE, too, since the processor latches the line...
-
- **Note** : HOLD_LINE *NEVER* makes sense on the TMS9900 (or 9980, 9995...). The reason is the
- TMS9900 does NOT tell the world it acknoledges an interrupt, so no matter how much hardware you
- use, you cannot know when the CPU takes the interrupt, hence you cannot release the line when
- the CPU takes the interrupt. Generally, the interrupt condition is cleared by the interrupt
- routine (with some CRU or memory access).
-
- Note that cpu_generate_interrupt uses HOLD_LINE, so your driver interrupt code
- should always use the new style, i.e. return "ignore_interrupt(cpustate)" and call
- "cpu_set_irq_line(0, 0, ASSERT_LINE);" explicitely.
-
- Last, many TMS9900-based hardware use a TMS9901 interrupt-handling chip. If anybody wants
- to emulate some hardware which uses it, note that I am writing some emulation in the TI99/4(A)
- driver in MESS, so you should ask me.
-*/
-/*
- * HJB 990430: changed to use irq_callback(cpustate) to retrieve the vector
- * instead of using 16 irqlines.
- *
- * R Nabet 990830 : My mistake, I rewrote all these once again ; I think it is now correct.
- * A driver using the TMS9900 should do :
- * cpu_0_irq_line_vector_w(0, level);
- * cpu_set_irq_line(0,0,ASSERT_LINE);
- *
- * R Nabet 991108 : revised once again, with advice from Juergen Buchmueller, after a discussion
- * with Nicola...
- * We use the callback to retreive the interrupt level as soon as INTREQ* is asserted.
- * As a consequence, I do not support HOLD_LINE normally... However, we do not really have to
- * support HOLD_LINE, since no real world TMS9900-based system can support this.
- * FYI, there are two alternatives to retreiving the interrupt level with the callback :
- * a) using 16 pseudo-IRQ lines. Mostly OK, though it would require a few core changes.
- * However, this could cause some problems if someone tried to set two lines simulteanously...
- * And TMS9900 did NOT have 16 lines ! This is why Juergen and I did not retain this solution.
- * b) modifying the interrupt system in order to provide an extra int to every xxx_set_irq_line
- * function. I think this solution would be fine, but it would require quite a number of
- * changes in the MAME core. (And I did not feel the courage to check out 4000 drivers and 25
- * cpu cores ;-) .)
- *
- * Note that this does not apply to tms9995.
-*/
-static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state)
-{
- if (irqline == INPUT_LINE_NMI)
- {
- cpustate->load_state = state; /* save new state */
-
- field_interrupt(cpustate); /* interrupt status changed */
- }
- else
- {
- /*if (cpustate->irq_state == state)
- return;*/
-
- cpustate->irq_state = state;
-
- if (state == CLEAR_LINE)
- cpustate->irq_level = 16;
- /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
- else
- cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0);
-
- field_interrupt(cpustate); /* interrupt state is likely to have changed */
- }
-}
-
-#elif (TMS99XX_MODEL == TMS9980_ID)
-/*
- interrupt system similar to tms9900, but only 3 interrupt pins (IC0-IC2)
-*/
-
-static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state)
-{
- if (state == CLEAR_LINE)
- {
- cpustate->load_state = 0;
- cpustate->irq_state = 0;
- cpustate->irq_level = 16;
- /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
- }
- else
- {
- int level;
-
- if (irqline == INPUT_LINE_NMI)
- level = 2; /* translate MAME's convention to CPU's representation */
- else
- level = (* cpustate->irq_callback)(cpustate->device, 0);
-
- switch (level)
- {
- case 0:
- case 1:
- cpustate->load_state = 0;
- cpustate->irq_state = 0;
- cpustate->irq_level = 16;
- CPU_RESET_NAME(tms99xx)(cpustate->device);
- break;
- case 2:
- cpustate->load_state = 1;
- cpustate->irq_state = 0;
- cpustate->irq_level = 16;
- break;
- case 7:
- cpustate->load_state = 0;
- cpustate->irq_state = 0;
- cpustate->irq_level = 16;
- break;
- default: /* external levels 1, 2, 3, 4 */
- cpustate->load_state = 0;
- cpustate->irq_state = 1;
- cpustate->irq_level = level - 2;
- break;
- }
- }
-
- field_interrupt(cpustate); /* interrupt state is likely to have changed */
-}
-
-#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-/*
- 2 interrupt pins (int1 and int2)
-*/
-
-static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state)
-{
- int mask;
-
- if (irqline == 0)
- /* INT1 */
- mask = 1;
- else if (irqline == 1)
- /* INT2 */
- mask = 4;
- else
- /* What on earth??? */
- return;
-
- if (state)
- cpustate->irq_state |= mask;
- else
- cpustate->irq_state &= ~mask;
-
- field_interrupt(cpustate); /* interrupt state is likely to have changed */
-}
-
-#elif (TMS99XX_MODEL == TMS9995_ID)
-/*
- this call-back is called by MESS timer system when the timer reaches 0.
-*/
-static TIMER_CALLBACK( decrementer_callback )
-{
- tms99xx_state *cpustate = (tms99xx_state *)ptr;
-
- /* request decrementer interrupt */
- cpustate->int_latch |= 0x8;
- cpustate->flag |= 0x8;
-
- field_interrupt(cpustate);
-}
-
-
-/*
- reset and load the timer/decrementer
-
- Note that I don't know whether toggling flag0/flag1 causes the decrementer to be reloaded or not
-*/
-static void reset_decrementer(tms99xx_state *cpustate)
-{
- cpustate->timer->adjust(attotime::never);
-
- /* reload count */
- cpustate->decrementer_count = cpustate->decrementer_interval;
-
- /* decrementer / timer enabled ? */
- cpustate->decrementer_enabled = ((cpustate->flag & 2) && (cpustate->decrementer_interval));
-
- if (cpustate->decrementer_enabled && ! (cpustate->flag & 1))
- { /* timer */
- attotime period = cpustate->device->cycles_to_attotime(cpustate->decrementer_interval * 16L);
- cpustate->timer->adjust(period, 0, period);
- }
-}
-
-/*
- You have two interrupt line : one triggers level-1 interrupts, the other triggers level-4
- interrupts (or decrements the decrementer register).
-
- According to the hardware, you may use PULSE_LINE (edge-triggered interrupts), or ASSERT_LINE
- (level-triggered interrupts). Edge-triggered interrupts are way simpler, but if multiple devices
- share the same line, they must use level-triggered interrupts.
-*/
-static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state)
-{
- if (irqline == INPUT_LINE_NMI)
- {
- cpustate->load_state = state; /* save new state */
-
- field_interrupt(cpustate); /* interrupt status changed */
- }
- else
- {
- int mask = (irqline == 0) ? 0x2 : 0x10;
- int flag_mask = (irqline == 0) ? 0x4 : 0x10;
-
- if (((cpustate->int_state & mask) != 0) ^ (state != 0))
- { /* only if state changes */
- if (state)
- {
- cpustate->int_state |= mask;
-
- if ((irqline == 1) && (cpustate->flag & 1))
- { /* event counter mode : INT4* triggers no interrupt... */
- if (cpustate->decrementer_enabled)
- { /* decrement, then interrupt if reach 0 */
- if ((-- cpustate->decrementer_count) == 0)
- {
- decrementer_callback(cpustate->device->machine(), cpustate, 0);
- cpustate->decrementer_count = cpustate->decrementer_interval; /* reload */
- }
- }
- }
- else
- { /* plain interrupt mode */
- cpustate->int_latch |= mask;
- cpustate->flag |= flag_mask;
- }
- }
- else
- {
- cpustate->int_state &= ~ mask;
- }
-
- field_interrupt(cpustate); /* interrupt status changed */
- }
- }
-}
-
-#else
-
-#error "interrupt system not implemented"
-
-#endif
-
-/*
- * field_interrupt
- *
- * Determines whether if an interrupt is pending, and sets the relevant flag.
- *
- * Called when an interrupt pin (LOAD*, INTREQ*, IC0-IC3) is changed, and when the interrupt mask
- * is modified.
- *
- * By using this flag, we save some compares in the execution loop. Subtle, isn't it ;-) ?
- *
- * R Nabet.
- */
-#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
-
-static void field_interrupt(tms99xx_state *cpustate)
-{
- cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state));
-}
-
-#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-
-static void field_interrupt(tms99xx_state *cpustate)
-{
- if (cpustate->irq_state & 1)
- cpustate->irq_level = 1;
- else if (cpustate->irq_state & 2)
- cpustate->irq_level = 2;
- else if (cpustate->irq_state & 4)
- cpustate->irq_level = 3;
- else
- cpustate->irq_level = 4;
- /* trick : 4 will always be bigger than the IM (0-3), so there will never be interrupts */
-
- cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state));
-}
-
-#elif (TMS99XX_MODEL == TMS9995_ID)
-
-static void field_interrupt(tms99xx_state *cpustate)
-{
- if (cpustate->load_state)
- {
- cpustate->interrupt_pending = 1;
- }
- else
- {
- int current_int;
- int level;
-
- if (cpustate->flag & 1)
- /* event counter mode : ignore int4* line... */
- current_int = (cpustate->int_state & ~0x10) | cpustate->int_latch;
- else
- /* normal behavior */
- current_int = cpustate->int_state | cpustate->int_latch;
-
- if (current_int)
- /* find first bit to 1 */
- /* possible values : 1, 3, 4 */
- for (level=0; ! (current_int & 1); current_int >>= 1, level++)
- ;
- else
- level=16;
-
- cpustate->irq_level = level;
-
- cpustate->interrupt_pending = (level <= IMASK);
- }
-}
-
-#else
-
-#error "field_interrupt(cpustate) not written"
-
-#endif
-
-static CPU_DISASSEMBLE( tms99xx )
-{
- extern unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram);
- return Dasm9900(buffer, pc, TMS99XX_MODEL, oprom, opram);
-}
-
-
-/*****************************************************************************/
-/*
- CRU support code
-
- The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address.
- Special instructions are dedicated to reading and writing one or several consecutive bits.
-
-
-
- Note that TMS99000 additionally supports parallel CRU operations, although I don't know how
- this feature is implemented.
-*/
-
-enum
-{
-#if (TMS99XX_MODEL == TI990_10_ID)
- /* 3 MSBs do exist, although they are not connected (don't ask...) */
- CRUAddrBit = 15
-#elif (TMS99XX_MODEL == TMS9900_ID)
- /* 3 MSBs are always 0 to support external instructions */
- CRUAddrBit = 12
-#elif (TMS99XX_MODEL == TMS9980_ID)
- /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */
- CRUAddrBit = 11
-#elif (TMS99XX_MODEL == TMS9940_ID)
- /* 9 internal address lines (8 external) */
- CRUAddrBit = 9
-#elif (TMS99XX_MODEL == TMS9995_ID)
- /* no such problem here : data bus lines D0-D2 provide the external instruction code */
- CRUAddrBit = 15
-#else
- #warning "I don't know how your processor handles CRU."
- CRUAddrBit = 15
-#endif
-};
-
-enum
-{
- rCRUAddrMask = (1 << (CRUAddrBit - 3)) - 1,
- wCRUAddrMask = (1 << CRUAddrBit) - 1
-};
-
-
-#if (TMS99XX_MODEL == TMS9995_ID)
-
-/* set decrementer mode flag */
-static void set_flag0(tms99xx_state *cpustate, int val)
-{
- if (val)
- cpustate->flag |= 1;
- else
- cpustate->flag &= ~ 1;
-
- reset_decrementer(cpustate);
-}
-
-/* set decrementer enable flag */
-static void set_flag1(tms99xx_state *cpustate, int val)
-{
- if (val)
- cpustate->flag |= 2;
- else
- cpustate->flag &= ~ 2;
-
- reset_decrementer(cpustate);
-}
-
-#endif
-
-enum cru_error_code
-{
- CRU_OK = 0,
- CRU_PRIVILEGE_VIOLATION = -1
-};
-
-#define WRITEPORT(cs, port, data) (cs)->io->write_byte(port, data)
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-/* on tms9940, we have to handle internal CRU ports */
-static void write_single_CRU(tms99xx_state *cpustate, int port, int data)
-{
- int mask;
-
- if (! (port & 0x100))
- {
- /*if (cpustate->config & CB0)*/
- /* External CRU */
- WRITEPORT(cpustate, port, (data & 0x01));
- }
- else
- {
- /* internal CRU */
- switch ((port >> 4) & 0xf)
- {
- case 0x8:
- if (port == 0x181)
- {
- /* clear decrementer interrupt */
- cpustate->irq_state &= ~2;
- }
- if (port >= 0x183) && (port <= 0x186)
- {
- /* write configuration register */
- mask = 1 << (port - 0x183);
- /* ... */
- }
- break;
-
- case 0x9:
- if (port <= 0x19D)
- {
- /* write decrementer latch */
- mask = 1 << (port - 0x190);
- /* ... */
- }
- else if (port == 0x19E)
- {
- /* set decrementer as timer (1) or event counter (0) */
- /* ... */
- }
- break;
-
- case 0xA:
- /* multiprocessor system interface */
- mask = 1 << (port - 0x1A0);
- /* ... */
- break;
-
- case 0xB:
- /* flags */
- mask = 1 << (port - 0x1B0);
- /* ... */
- break;
-
- case 0xC:
- case 0xD:
- /* direction for P0-P31 */
- mask = 1 << (port - 0x1C0);
- /* ... */
- break;
-
- case 0xE:
- case 0xF:
- /* data for P0-P31 */
- mask = 1 << (port - 0x1E0);
- /* ... */
- break;
- }
- }
-}
-#elif (TMS99XX_MODEL == TMS9995_ID)
-/* on tms9995, we have to handle internal CRU ports */
-static void write_single_CRU(tms99xx_state *cpustate, int port, int data)
-{
- /* Internal CRU */
- switch (port)
- {
- case 0xF70:
- set_flag0(cpustate, data & 0x01);
- break;
- case 0xF71:
- set_flag1(cpustate, data & 0x01);
- break;
- case 0xF72:
- case 0xF73:
- case 0xF74:
- break; /* ignored */
- case 0xF75:
- case 0xF76:
- case 0xF77:
- case 0xF78:
- case 0xF79:
- case 0xF7A:
- case 0xF7B:
- case 0xF7C:
- case 0xF7D:
- case 0xF7E:
- case 0xF7F:
- { /* user defined flags */
- int mask = 1 << (port - 0xF70);
- if (data & 0x01)
- cpustate->flag |= mask;
- else
- cpustate->flag &= ~ mask;
- }
- break;
-
- case 0x0FED:
- /* MID flag */
- cpustate->MID_flag = data & 0x01;
- break;
- }
- /* External CRU */
- /* Even though all the registers above are implemented internally, accesses
- are passed to the external bus, too, and an external device might respond
- to a write to these CRU address as well (particularly a write to the user
- flag registers). */
- WRITEPORT(cpustate, port, (data & 0x01));
-}
-#else
-#define write_single_CRU(cs, port, data) WRITEPORT(cs, port, data)
-#endif
-
-/*
- performs a normal write to CRU bus (used by SBZ, SBO, LDCR : address range 0 -> 0xFFF)
-*/
-static cru_error_code writeCRU(tms99xx_state *cpustate, int CRUAddr, int Number, UINT16 Value)
-{
- int count;
-
- /*logerror("PC %4.4x Write CRU %x for %x =%x\n",cpustate->PC,CRUAddr,Number,Value);*/
-
- CRUAddr &= wCRUAddrMask;
-
- /* Write Number bits from CRUAddr */
-
- for(count=0; count<Number; count++)
- {
- #if HAS_PRIVILEGE
- if ((cpustate->STATUS & ST_PR) && (CRUAddr >= 0xE00))
- return CRU_PRIVILEGE_VIOLATION;
- #endif
-
- write_single_CRU(cpustate, CRUAddr, (Value & 0x01));
- Value >>= 1;
- CRUAddr = (CRUAddr + 1) & wCRUAddrMask;
- }
-
- return CRU_OK;
-}
-
-#if EXTERNAL_INSTRUCTION_DECODING
-/*
- Some opcodes perform a dummy write to a special CRU address, so that an external function may be
- triggered.
-
- Only the first 3 MSBs of the address matter : other address bits and the written value itself
- are undefined.
-
- How should we support this ? With callback functions ? Actually, as long as we do not support
- hardware which makes use of this feature, it does not really matter :-) .
-*/
-static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID)
-{
-#if 1
- /* I guess we can support this like normal CRU operations */
-#if (TMS99XX_MODEL == TMS9900_ID)
- WRITEPORT(cpustate, ext_op_ID << 12, 0); /* or is it 1 ??? */
-#elif (TMS99XX_MODEL == TMS9980_ID)
- WRITEPORT(cpustate, (ext_op_ID & 3) << 11, (ext_op_ID & 4) ? 1 : 0);
-#elif (TMS99XX_MODEL == TMS9995_ID)
- WRITEPORT(cpustate, ext_op_ID << 15, 0); /* or is it 1 ??? */
-#else
- #warning "I don't know how your processor handles external opcodes (maybe you don't need them, though)."
-#endif
-
-#else
- switch (ext_op_ID)
- {
- case 2: /* IDLE */
-
- break;
- case 3: /* RSET */
-
- break;
- case 5: /* CKON */
-
- break;
- case 6: /* CKOF */
-
- break;
- case 7: /* LREX */
-
- break;
- case 0:
- /* normal CRU write !!! */
- logerror("PC %4.4x : external_instruction_notify : wrong ext_op_ID",cpustate->PC);
- break;
- default:
- /* unknown address */
- logerror("PC %4.4x : external_instruction_notify : unknown ext_op_ID",cpustate->PC);
- break;
- }
-#endif
-}
-#endif
-
-/*
- performs a normal read to CRU bus (used by TB, STCR : address range 0->0xFFF)
-
- Note that on some hardware, e.g. TI99/4(a), all normal memory operations cause unwanted CRU
- read at the same address. This seems to be impossible to emulate efficiently, so, if you need
- to emulate this, you're in trouble.
-*/
-#define READPORT(cs, port) (cs)->io->read_byte(port)
-
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-/* on tms9940, we have to handle internal CRU ports */
-static int read_single_CRU(tms99xx_state *cpustate, int port)
-{
- int reply;
- int shift;
-
- if (! (port & 0x20))
- {
- /*if (cpustate->config & CB0)*/
- /* External CRU */
- reply = READPORT(cpustate, port, (data & 0x01));
- }
- else
- {
- /* internal CRU */
- switch (port)
- {
- case 0x10:
- /* read interrupt state */
- reply = cpustate->irq_state;
- break;
-
- case 0x12:
- /* read decrementer LSB */
- /* ... */
- break;
- case 0x13:
- /* read decrementer MSB */
- /* ... */
- break;
-
- case 0x14:
- /* read multiprocessor system interface LSB */
- /* ... */
- break;
- case 0x15:
- /* read multiprocessor system interface MSB */
- /* ... */
- break;
-
- case 0x16:
- /* read flags LSB */
- /* ... */
- break;
- case 0x17:
- /* read flags MSB */
- /* ... */
- break;
-
- case 0x18:
- case 0x19:
- case 0x1A:
- case 0x1B:
- /* direction for P0-P31 */
- shift = (port - 0x18) << 3;
- /* ... */
- break;
-
- case 0x1C:
- case 0x1D:
- case 0x1E:
- case 0x1F:
- /* data for P0-P31 */
- shift = (port - 0x1C) << 3;
- /* ... */
- break;
-
- default:
- reply = 0;
- break;
- }
- }
-
- return reply;
-}
-#elif (TMS99XX_MODEL == TMS9995_ID)
-/* on tms9995, we have to handle internal CRU ports */
-static int read_single_CRU(tms99xx_state *cpustate, int port)
-{
- switch (port)
- {
- case 0x1EE:
- /* flag, bits 0-7 */
- return cpustate->flag & 0xFF;
- case 0x1EF:
- /* flag, bits 8-15 */
- return (cpustate->flag >> 8) & 0xFF;
- case 0x1FD:
- /* MID flag, and external devices */
- if (cpustate->MID_flag)
- return READPORT(cpustate, port) | 0x10;
- else
- return READPORT(cpustate, port) & ~ 0x10;
- default:
- /* external devices */
- return READPORT(cpustate, port);
- }
-}
-#else
-#define read_single_CRU(cs, port) READPORT(cs, port)
-#endif
-
-static int readCRU(tms99xx_state *cpustate, int CRUAddr, int Number)
-{
- static const int BitMask[] =
- {
- 0, /* filler - saves a subtract to find mask */
- 0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,
- 0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF
- };
-
- int Offset,Location,Value;
-
- /*logerror("Read CRU %x for %x\n",CRUAddr,Number);*/
-
- Location = (CRUAddr >> 3) & rCRUAddrMask;
- Offset = CRUAddr & 07;
-
- /* Read 8 bits */
- #if HAS_PRIVILEGE
- if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
- return CRU_PRIVILEGE_VIOLATION;
- #endif
- Value = read_single_CRU(cpustate, Location);
-
- if ((Offset+Number) > 8)
- {
- /* Read next 8 bits */
- Location = (Location + 1) & rCRUAddrMask;
- #if HAS_PRIVILEGE
- if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
- return CRU_PRIVILEGE_VIOLATION;
- #endif
- Value |= read_single_CRU(cpustate, Location) << 8;
-
- if ((Offset+Number) > 16)
- {
- /* Read next 8 bits */
- Location = (Location + 1) & rCRUAddrMask;
- #if HAS_PRIVILEGE
- if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3)))
- return CRU_PRIVILEGE_VIOLATION;
- #endif
- Value |= read_single_CRU(cpustate, Location) << 16;
- }
- }
-
- /* Allow for Offset */
- Value >>= Offset;
-
- /* Mask out what we want */
- Value &= BitMask[Number];
-
- /* And update */
- return Value;
-}
-
-/*****************************************************************************/
-
-#if HAS_MAPPING
-/* load a map file from memory */
-static void load_map_file(tms99xx_state *cpustate, UINT16 src_addr, int src_map_file, int dst_file)
-{
- int i;
-
-
- /* load mapped address into the memory address register */
- if ((src_map_file == 0) && (src_addr >= 0xf800))
- { /* intercept TPCS and CPU ROM */
- if (src_addr < 0xfc00)
- /* TPCS */
- cpustate->mapper_address_latch = 0x1f0000+src_addr;
- else
- /* CPU ROM */
- cpustate->mapper_address_latch = 0x1f0000+src_addr; /* hack... */
- }
- else if (! cpustate->mapping_on)
- {
- cpustate->mapper_address_latch = src_addr;
- }
- else
- {
- int map_index;
-
- if (src_addr <= cpustate->map_files[src_map_file].limit[0])
- map_index = 0;
- else if (src_addr <= cpustate->map_files[src_map_file].limit[1])
- map_index = 1;
- else if (src_addr <= cpustate->map_files[src_map_file].limit[2])
- map_index = 2;
- else
- {
- if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR))
- {
- cpustate->error_interrupt_register |= EIR_MAPERR;
- cpustate->write_inhibit = 1;
- }
- cpustate->mapper_address_latch = src_addr;
- map_index = -1;
- }
- if (map_index != -1)
- cpustate->mapper_address_latch = cpustate->map_files[src_map_file].bias[map_index]+src_addr;
- }
-
-
- for (i=0; i<3; i++)
- {
- cpustate->map_files[dst_file].L[i] = cpustate->program->read_word(cpustate->mapper_address_latch) & 0xffe0;
- cpustate->map_files[dst_file].limit[i] = (cpustate->map_files[dst_file].L[i] ^ 0xffe0) | 0x001f;
- cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff;
- cpustate->map_files[dst_file].B[i] = cpustate->program->read_word(cpustate->mapper_address_latch);
- cpustate->map_files[dst_file].bias[i] = ((unsigned int) cpustate->map_files[dst_file].B[i]) << 5;
- cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff;
- }
-}
-#endif
-
-/* contextswitch : performs a BLWP, i.e. load PC, WP, and save old PC, old WP and ST... */
-static void contextswitch(tms99xx_state *cpustate, UINT16 addr)
-{
- UINT16 oldWP, oldpc;
-
- /* save old state */
- oldWP = cpustate->WP;
- oldpc = cpustate->PC;
-
- /* load vector */
- cpustate->WP = readword(cpustate, addr) & ~1;
- cpustate->PC = readword(cpustate, addr+2) & ~1;
-
- /* write old state to regs */
- WRITEREG(R13, oldWP);
- WRITEREG(R14, oldpc);
- setstat(cpustate);
- WRITEREG(R15, cpustate->STATUS);
-}
-
-#if HAS_MAPPING || HAS_PRIVILEGE
-
-/* privileged context switch, that occurs after a reset, interrupt or XOP:
-we enter privileged mode and select map file 0 before doing the context switch */
-/* For CPU that have no privilege support, contextswitchX would behave
-identically to contextswitch, so we can call contextswitch in all cases. */
-static void contextswitchX(tms99xx_state *cpustate, UINT16 addr)
-{
- UINT16 oldWP, oldpc, oldST;
-
- /* save old state */
- oldWP = cpustate->WP;
- oldpc = cpustate->PC;
- setstat(cpustate);
- oldST = cpustate->STATUS;
-
- /* enter privileged mode and select map file 0 */
- #if HAS_PRIVILEGE
- cpustate->STATUS &= ~ ST_PR;
- #endif
- #if HAS_MAPPING
- cpustate->STATUS &= ~ ST_MF;
- #endif
- getstat(cpustate);
-
- /* load vector */
- cpustate->WP = readword(cpustate, addr) & ~1;
- cpustate->PC = readword(cpustate, addr+2) & ~1;
-
- /* write old state to regs */
- WRITEREG(R13, oldWP);
- WRITEREG(R14, oldpc);
- WRITEREG(R15, oldST);
-}
-
-#endif
-
-/*
- * decipheraddr : compute and return the effective address in word instructions.
- *
- * NOTA : the LSBit is always ignored in word addresses,
- * but we do not set it to 0 because of XOP...
- */
-static UINT16 decipheraddr(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 ts = opcode & 0x30;
- register UINT16 reg = opcode & 0xF;
-
- reg += reg;
-
- if (ts == 0)
- /* Rx */
- return(reg + cpustate->WP);
- else if (ts == 0x10)
- { /* *Rx */
- CYCLES(0, 4, 1);
- return(readword(cpustate, reg + cpustate->WP));
- }
- else if (ts == 0x20)
- {
- register UINT16 imm;
-
- imm = fetch(cpustate);
-
- if (reg)
- { /* @>xxxx(Rx) */
- CYCLES(1, 8, 3);
- return(readword(cpustate, reg + cpustate->WP) + imm);
- }
- else
- { /* @>xxxx */
- CYCLES(3, 8, 1);
- return(imm);
- }
- }
- else /*if (ts == 0x30)*/
- { /* *Rx+ */
- register UINT16 response;
-
- reg += cpustate->WP; /* reg now contains effective address */
-
- CYCLES(1, 8, 3);
-
- response = readword(cpustate, reg);
- writeword(cpustate, reg, response+2); /* we increment register content */
- return(response);
- }
-}
-
-/* decipheraddrbyte : compute and return the effective address in byte instructions. */
-static UINT16 decipheraddrbyte(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 ts = opcode & 0x30;
- register UINT16 reg = opcode & 0xF;
-
- reg += reg;
-
- if (ts == 0)
- /* Rx */
- return(reg + cpustate->WP);
- else if (ts == 0x10)
- { /* *Rx */
- CYCLES(0, 4, 1);
- return(readword(cpustate, reg + cpustate->WP));
- }
- else if (ts == 0x20)
- {
- register UINT16 imm;
-
- imm = fetch(cpustate);
-
- if (reg)
- { /* @>xxxx(Rx) */
- CYCLES(1, 8, 3);
- return(readword(cpustate, reg + cpustate->WP) + imm);
- }
- else
- { /* @>xxxx */
- CYCLES(3, 8, 1);
- return(imm);
- }
- }
- else /*if (ts == 0x30)*/
- { /* *Rx+ */
- register UINT16 response;
-
- reg += cpustate->WP; /* reg now contains effective address */
-
- CYCLES(1, 6, 3);
-
- response = readword(cpustate, reg);
- writeword(cpustate, reg, response+1); /* we increment register content */
- return(response);
- }
-}
-
-
-/*************************************************************************/
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- /* TI990/10 generates an error interrupt */
- /* timings are unknown */
- #define HANDLE_ILLEGAL \
- { \
- cpustate->error_interrupt_register |= EIR_ILLOP; \
- if (cpustate->error_interrupt_callback) \
- (*cpustate->error_interrupt_callback)(cpustate->device, 1); \
- }
-#elif TMS99XX_MODEL <= TMS9989_ID
- /* TMS9900/TMS9980 merely ignore the instruction */
- #define HANDLE_ILLEGAL cpustate->icount -= 6
-#elif TMS99XX_MODEL == TMS9995_ID
- /* TMS9995 generates a MID interrupt */
- #define HANDLE_ILLEGAL \
- { \
- cpustate->MID_flag = 1; \
- contextswitchX(cpustate, 0x0008); \
- cpustate->STATUS = (cpustate->STATUS & 0xFE00) | 0x1; \
- cpustate->disable_interrupt_recognition = 1; \
- }
-#else
-#define HANDLE_ILLEGAL
-#warning "don't know"
-#endif
-
-#if HAS_PRIVILEGE
- #if (TMS99XX_MODEL == TI990_10_ID)
- /* TI990/10 generates an error interrupt */
- /* timings are unknown */
- #define HANDLE_PRIVILEGE_VIOLATION \
- { \
- cpustate->error_interrupt_register |= EIR_PRIVOP; \
- if (cpustate->error_interrupt_callback) \
- (*cpustate->error_interrupt_callback)(cpustate->device, 1); \
- }
- #else
- #define HANDLE_PRIVILEGE_VIOLATION
- #warning "don't know"
- #endif
-#endif
-
-/*==========================================================================
- Illegal instructions >0000->01FF (not for 9989 and later)
- >0C00->0FFF (not for 990/12 and 99110)
-============================================================================*/
-
-static void illegal(tms99xx_state *cpustate, UINT16 opcode)
-{
- HANDLE_ILLEGAL;
-}
-
-
-#if 0 /* ti990/12 only */
-/*==========================================================================
- Additionnal instructions, >0000->002F
- Additionnal single-register instruction, >0030->003F
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |
- | o p c o d e | reg # |
- ---------------------------------
-
-============================================================================*/
-static void h0000(tms99xx_state *cpustate, UINT16 opcode)
-{
- if (opcode >= 0x30)
- { /* STPC STore Program Counter */
-
- }
- else
- {
- switch (opcode /*& 0x3F*/)
- {
- case 0x1C: /* SRAM */
- /* SRAM -- Shift Right Arithmetic Multiple precision */
- case 0x1D: /* SLAM */
- /* SLAM -- Shift Left Arithmetic Multiple precision */
- case 0x1E:
- /* RTO --- Right Test for Ones */
- case 0x1F:
- /* LTO --- Left Test for Ones */
- case 0x20:
- /* CNTO -- CouNT Ones */
- case 0x21:
- /* SLSL -- Search LiSt Logical address */
- case 0x22:
- /* SLSP -- Search LiSt Physical address */
- case 0x23:
- /* BDC --- Binary to Decimal ascii Conversion */
- case 0x24:
- /* DBC --- Decimal to Binary ascii Conversion */
- case 0x25:
- /* SWPM -- SWaP Multiple precision */
- case 0x26:
- /* XORM -- eXclusive OR Multiple precision */
- case 0x27:
- /* ORM --- OR Multiple precision */
- case 0x28:
- /* ANDM -- AND Multiple precision */
- case 0x29: /* SM */
- /* SM ---- Subtract Multiple precision integer */
- case 0x2A: /* AM */
- /* AM ---- Add Multiple precision integer */
- case 0x2B:
- /* MOVA -- MOVe Address */
- case 0x2D:
- /* EMD --- Execute Micro-Diagnostics */
- case 0x2E:
- /* EINT -- Enable INTerrupts */
- case 0x2F:
- /* DINT -- Disable INTerrupts */
-
- break;
-
- default:
- HANDLE_ILLEGAL;
- break;
- }
- }
-}
-#endif
-
-
-#if HAS_9995_OPCODES
-/*==========================================================================
- Additionnal single-register instructions, >0040->00FF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e | reg # |
- ---------------------------------
-
-tms9989 and later : LST, LWP
-============================================================================*/
-static void h0040(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 addr;
-
- addr = opcode & 0xF;
- addr = ((addr + addr) + cpustate->WP) & ~1;
-
- switch ((opcode & 0xF0) >> 4)
- {
- case 8: /* LST */
- /* LST --- Load STatus register */
- /* ST = *Reg */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20);
- else
- cpustate->STATUS = readword(cpustate, addr);
- #else
- cpustate->STATUS = readword(cpustate, addr);
- #endif
- getstat(cpustate); /* set last_parity */
- break;
-
- case 9: /* LWP */
- /* LWP --- Load Workspace Pointer */
- /* WP = *Reg */
- cpustate->WP = readword(cpustate, addr) & ~1;
- break;
-
-#if 0 /* 990/12 opcodes */
- case 4:
- /* CS ---- Compare Strings */
- case 5:
- /* SEQB -- Search string for EQual Byte */
- case 6:
- /* MOVS -- MOVe String */
- case 7:
- /* LIM --- Load Interrupt Mask */
-
- case 10:
- /* LCS --- Load writable Control Store */
-
- case 11: /* BLSK */
- /* BLSK -- Branch immediate and push Link to StacK */
-
- case 12:
- /* MVSR -- MoVe String Reverse */
- case 13:
- /* MVSK -- MoVe string from StacK */
- case 14:
- /* POPS -- POP String from stack */
- case 15:
- /* PSHS -- PuSH String to stack */
-
- break;
-#endif
-
- default:
- HANDLE_ILLEGAL;
- break;
- }
-}
-
-
-/*==========================================================================
- Additionnal single-operand instructions, >0100->01FF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |TS | S |
- ---------------------------------
-
-tms9989 and later : DIVS, MPYS
-tms99xxx : BIND
-============================================================================*/
-static void h0100(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 src;
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
-#endif
-
- src = decipheraddr(cpustate, opcode) & ~1;
-
- switch ((opcode & 0xC0) >> 6)
- {
-#if HAS_BIND_OPCODE
- case 1: /* BIND */
- /* BIND -- Branch INDirect */
- cpustate->PC = readwordX(cpustate, src, src_map) & ~1;
- CYCLES(Mooof!, Mooof!, 4 /*don't know*/);
- break;
-#endif
-
- case 2: /* DIVS */
- /* DIVS -- DIVide Signed */
- /* R0 = (R0:R1)/S R1 = (R0:R1)%S */
- {
- INT16 d = readwordX(cpustate, src, src_map);
- INT32 divq = (READREG(R0) << 16) | READREG(R1);
- INT32 q = divq/d;
-
- if ((q < -32768L) || (q > 32767L))
- {
- cpustate->STATUS |= ST_OV;
- CYCLES(Mooof!, Mooof!, 10);
- }
- else
- {
- cpustate->STATUS &= ~ST_OV;
- setst_lae(cpustate, q);
- WRITEREG(R0, q);
- WRITEREG(R1, divq%d);
- /* tms9995 : 33 is the worst case */
- CYCLES(Mooof!, Mooof!, 33);
- }
- }
- break;
-
- case 3: /* MPYS */
- /* MPYS -- MultiPlY Signed */
- /* Results: R0:R1 = R0*S */
- {
- INT32 prod = ((INT32) (INT16) readwordX(cpustate, src, src_map));
- prod = prod*((INT32) (INT16) READREG(R0));
-
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
- if (prod > 0)
- cpustate->STATUS |= (ST_LGT | ST_AGT);
- else if (prod < 0)
- cpustate->STATUS |= ST_LGT;
- else
- cpustate->STATUS |= ST_EQ;
-
- WRITEREG(R0, prod >> 16);
- WRITEREG(R1, prod);
- }
- CYCLES(Mooof!, Mooof!, 25);
- break;
-
-#if 0 /* Origin unknown */
- case 0: /* EVAD */
- /* EVAD -- EValuate ADdress instruction */
-
- break;
-#endif
-
- default:
- HANDLE_ILLEGAL;
- break;
- }
-}
-#endif
-
-
-/*==========================================================================
- Immediate, Control instructions, >0200->03FF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |0| reg # |
- ---------------------------------
-
- LI, AI, ANDI, ORI, CI, STWP, STST, LIMI, LWPI, IDLE, RSET, RTWP, CKON, CKOF, LREX
-systems with memory mapper: LMF
-============================================================================*/
-static void h0200(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 addr;
- register UINT16 value; /* used for anything */
-
- addr = opcode & 0xF;
- addr = ((addr + addr) + cpustate->WP) & ~1;
-
- #if HAS_MAPPING
- if ((opcode >= 0x0320) && (opcode < 0x0340))
- { /* LMF */
- /* LMF --- Load memory Map File */
- /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610
- mapper chip to be associated with tms99000.
- Syntax: "LMF Rn,m" loads map file m (0 or 1) with six words of memory, starting at address
- specified in workspace register Rn (0 through 15). */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- return;
- }
- #endif
-
- /* read address pointer */
- addr = readword(cpustate, addr);
-
- load_map_file(cpustate, addr, cpustate->cur_map, (opcode & 0x10) ? 1 : 0);
-
- CYCLES(3, Mooof!, Mooof!);
- return;
- }
- #endif
-
- #if BETTER_0200_DECODING
- /* better instruction decoding on ti990/10 */
- if (opcode & 0x10)
- {
- HANDLE_ILLEGAL;
- return;
- }
- #elif COMPLETE_0200_DECODING
- /* full instruction decoding on tms9995 */
- if (((opcode < 0x2E0) && (opcode & 0x10)) || ((opcode >= 0x2E0) && (opcode & 0x1F)))
- {
-#if 0
- /* tms99110 opcode (not supported by 990/12) */
- if (opcode == 0x0301)
- { /* CR ---- Compare Reals */
- }
- else
- /* tms99105+tms99110 opcode (not supported by 990/12) */
- if (opcode == 0x0302)
- { /* MM ---- Multiply Multiple */
- }
- else
-#endif
- #if 0 /* ti990/12 only */
- if (opcode >= 0x03F0)
- { /* EP ---- Extended Precision */
- }
- else
- #endif
- HANDLE_ILLEGAL;
- return;
- }
- #endif
-
- switch ((opcode & 0x1e0) >> 5)
- {
- case 0: /* LI */
- /* LI ---- Load Immediate */
- /* *Reg = *PC+ */
- value = fetch(cpustate);
- writeword(cpustate, addr, value);
- setst_lae(cpustate, value);
- CYCLES(3, 12, 3);
- break;
-
- case 1: /* AI */
- /* AI ---- Add Immediate */
- /* *Reg += *PC+ */
- value = fetch(cpustate);
- value = setst_add_laeco(cpustate, readword(cpustate, addr), value);
- writeword(cpustate, addr, value);
- CYCLES(4, 14, 4);
- break;
-
- case 2: /* ANDI */
- /* ANDI -- AND Immediate */
- /* *Reg &= *PC+ */
- value = fetch(cpustate);
- value = readword(cpustate, addr) & value;
- writeword(cpustate, addr, value);
- setst_lae(cpustate, value);
- CYCLES(4, 14, 4);
- break;
-
- case 3: /* ORI */
- /* ORI --- OR Immediate */
- /* *Reg |= *PC+ */
- value = fetch(cpustate);
- value = readword(cpustate, addr) | value;
- writeword(cpustate, addr, value);
- setst_lae(cpustate, value);
- CYCLES(4, 14, 4);
- break;
-
- case 4: /* CI */
- /* CI ---- Compare Immediate */
- /* status = (*Reg-*PC+) */
- value = fetch(cpustate);
- setst_c_lae(cpustate, value, readword(cpustate, addr));
- CYCLES(6, 14, 4);
- break;
-
- case 5: /* STWP */
- /* STWP -- STore Workspace Pointer */
- /* *Reg = WP */
- writeword(cpustate, addr, cpustate->WP);
- CYCLES(2, 8, 3);
- break;
-
- case 6: /* STST */
- /* STST -- STore STatus register */
- /* *Reg = ST */
- setstat(cpustate);
- writeword(cpustate, addr, cpustate->STATUS);
- CYCLES(2, 8, 3);
- break;
-
- case 7: /* LWPI */
- /* LWPI -- Load Workspace Pointer Immediate */
- /* WP = *PC+ */
- cpustate->WP = fetch(cpustate) & ~1;
- CYCLES(3, 10, 4);
- break;
-
- case 8: /* LIMI */
- /* LIMI -- Load Interrupt Mask Immediate */
- /* ST&15 |= (*PC+)&15 */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- value = fetch(cpustate);
- cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (value & ST_IM);
- field_interrupt(cpustate); /*IM has been modified.*/
- CYCLES(3, 16, 5);
- break;
-
- case 9: /* LMF is implemented elsewhere - when it is implemented */
- HANDLE_ILLEGAL;
- break;
-
- case 10: /* IDLE */
- /* IDLE -- IDLE until a reset, interrupt, load */
- /* The TMS99000 locks until an interrupt happen (like with 68k STOP instruction),
- and continuously performs a special CRU write (code 2). */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
- cpustate->IDLE = 1;
- #if EXTERNAL_INSTRUCTION_DECODING
- external_instruction_notify(cpustate, 2);
- #endif
- if (cpustate->idle_callback)
- (*cpustate->idle_callback)(cpustate->device, 1);
- CYCLES(4, 12, 7);
- /* we take care of further external_instruction_notify(cpustate, 2); in execute(cpustate) */
- break;
-
- case 12: /* RTWP */
- /* RTWP -- Return with Workspace Pointer */
- /* WP = R13, PC = R14, ST = R15 */
- addr = (cpustate->WP + R13) & ~1;
- cpustate->WP = readword(cpustate, addr) & ~1;
- addr += 2;
- cpustate->PC = readword(cpustate, addr) & ~1;
- addr += 2;
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20);
- else
- cpustate->STATUS = readword(cpustate, addr);
- #else
- cpustate->STATUS = readword(cpustate, addr);
- #endif
- getstat(cpustate); /* set last_parity */
-
- field_interrupt(cpustate); /*IM has been modified.*/
- CYCLES(3, 14, 6);
- break;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
-
- case 11: /* RSET */
- case 13: /* CKON */
- case 14: /* CKOF */
- case 15: /* LREX */
- HANDLE_ILLEGAL; /* These instruction "have been deleted" on the TMS9940 */
- break;
-
-#else
-
- case 11: /* RSET */
- /* RSET -- ReSET */
- /* Reset the Interrupt Mask, and perform a special CRU write (code 3). */
- /* The CRU write is supposed to reset external devices. */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- cpustate->STATUS &= 0xFFF0; /*clear IM.*/
- field_interrupt(cpustate); /*IM has been modified.*/
-
- #if (TMS99XX_MODEL == TMS9995_ID)
- /*cpustate->MID_flag = 0;*/ /* not sure about this */
- #endif
- #if (TMS99XX_MODEL == TI990_10_ID)
- cpustate->error_interrupt_register = 0;
- cpustate->mapping_on = 0;
-
- cpustate->reset_maperr = 0;
- cpustate->mapper_cru_read_register = 0;
- cpustate->latch_control[0] = cpustate->latch_control[1] = cpustate->latch_control[2] = 0;
-
- cpustate->diaglat = 0;
- #endif
-
- #if EXTERNAL_INSTRUCTION_DECODING
- external_instruction_notify(cpustate, 3);
- #endif
-
- #if EXTERNAL_INSTRUCTION_CALLBACK
- if (cpustate->rset_callback)
- (*cpustate->rset_callback)(cpustate->device);
- #endif
-
- CYCLES(5, 12, 7);
- break;
-
-#if EXTERNAL_INSTRUCTION_DECODING
-
- case 13: /* CKON */
- case 14: /* CKOF */
- case 15: /* LREX */
- /* CKON -- ClocK ON */
- /* Perform a special CRU write (code 5). */
- /* An external circuitery could, for instance, enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */
- /* CKOF -- ClocK OFf */
- /* Perform a special CRU write (code 6). */
- /* An external circuitery could, for instance, disable the line clock interrupt. */
- /* LREX -- Load or REstart eXecution */
- /* Perform a special CRU write (code 7). */
- /* An external circuitery could, for instance, activate the LOAD* line,
- causing a non-maskable LOAD interrupt (vector -1). */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- external_instruction_notify(cpustate, (opcode & 0x00e0) >> 5);
-
- #if EXTERNAL_INSTRUCTION_CALLBACK
- #warning "todo..."
- #endif
-
- CYCLES(Mooof!, 12, 7);
- break;
-
-#elif EXTERNAL_INSTRUCTION_CALLBACK
-
- case 13: /* CKON */
- case 14: /* CKOF */
- /* CKON -- ClocK ON */
- /* Enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */
- /* CKOF -- ClocK OFf */
- /* Disable the line clock interrupt. */
- /* We use a callback because the line clock is implemented in machine
- code, not in the CPU core. */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- if (cpustate->ckon_ckof_callback)
- (*cpustate->ckon_ckof_callback)(cpustate->device, (opcode & 0x0020) ? 1 : 0);
-
-
- CYCLES(5, Mooof!, Mooof!);
- break;
-
- case 15: /* LREX */
- /* LREX -- Load or REstart eXecution */
- /* Trigger a LOAD interrupt (vector -1). (We use a callback, and I
- have forgotten the reason why.) */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- if (cpustate->lrex_callback)
- (*cpustate->lrex_callback)(cpustate->device);
-
- CYCLES(6, Mooof!, Mooof!);
- break;
-
-#else
-
- #warning "Should not happen..."
-
-#endif
-
-#endif
- }
-}
-
-
-/*==========================================================================
- Single-operand instructions, >0400->07FF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |TS | S |
- ---------------------------------
-
- BLWP, B, X, CLR, NEG, INV, INC, INCT, DEC, DECT, BL, SWPB, SETO, ABS
-systems with memory mapper: LDD, LDS
-============================================================================*/
-static void h0400(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 addr = decipheraddr(cpustate, opcode) & ~1;
- register UINT16 value; /* used for anything */
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
-#endif
-
- switch ((opcode & 0x3C0) >> 6)
- {
- case 0: /* BLWP */
- /* BLWP -- Branch and Link with Workspace Pointer */
- /* Result: WP = *S+, PC = *S */
- /* New R13=old WP, New R14=Old PC, New R15=Old ST */
- contextswitch(cpustate, addr);
- CYCLES(3, 26, 11);
- cpustate->disable_interrupt_recognition = 1;
- break;
- case 1: /* B */
- /* B ----- Branch */
- /* PC = S */
-#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
- (void) readwordX(cpustate, addr, src_map);
-#endif
- cpustate->PC = addr;
- CYCLES(2, 8, 3);
- break;
- case 2: /* X */
- /* X ----- eXecute */
- /* Executes instruction *S */
- execute(cpustate, readwordX(cpustate, addr, src_map));
- /* On tms9900, the X instruction actually takes 8 cycles, but we gain 2 cycles on the next
- instruction, as we don't need to fetch it. */
- CYCLES(1, 6, 2);
- break;
- case 3: /* CLR */
- /* CLR --- CLeaR */
- /* *S = 0 */
-#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
- (void) readwordX(cpustate, addr, src_map);
-#endif
- writewordX(cpustate, addr, 0, src_map);
- CYCLES(2, 10, 3);
- break;
- case 4: /* NEG */
- /* NEG --- NEGate */
- /* *S = -*S */
- value = - (INT16) readwordX(cpustate, addr, src_map);
- if (value)
- cpustate->STATUS &= ~ ST_C;
- else
- cpustate->STATUS |= ST_C;
-
- #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (value & 0x0FFF)
- cpustate->STATUS &= ~ ST_DC;
- else
- cpustate->STATUS |= ST_DC;
- #endif
-
- setst_laeo(cpustate, value);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(3, 12, 3);
- break;
- case 5: /* INV */
- /* INV --- INVert */
- /* *S = ~*S */
- value = ~ readwordX(cpustate, addr, src_map);
- writewordX(cpustate, addr, value, src_map);
- setst_lae(cpustate, value);
- CYCLES(2, 10, 3);
- break;
- case 6: /* INC */
- /* INC --- INCrement */
- /* (*S)++ */
- value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 1);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(2, 10, 3);
- break;
- case 7: /* INCT */
- /* INCT -- INCrement by Two */
- /* (*S) +=2 */
- value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 2);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(2, 10, 3);
- break;
- case 8: /* DEC */
- /* DEC --- DECrement */
- /* (*S)-- */
- value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 1);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(2, 10, 3);
- break;
- case 9: /* DECT */
- /* DECT -- DECrement by Two */
- /* (*S) -= 2 */
- value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 2);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(2, 10, 3);
- break;
- case 10: /* BL */
- /* BL ---- Branch and Link */
- /* IP=S, R11=old IP */
-#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
- (void) readwordX(cpustate, addr, src_map);
-#endif
- WRITEREG(R11, cpustate->PC);
- cpustate->PC = addr;
- CYCLES(3, 12, 5);
- break;
- case 11: /* SWPB */
- /* SWPB -- SWaP Bytes */
- /* *S = swab(*S) */
- value = readwordX(cpustate, addr, src_map);
- value = logical_right_shift(value, 8) | (value << 8);
- writewordX(cpustate, addr, value, src_map);
- CYCLES(2, 10, 13);
- break;
- case 12: /* SETO */
- /* SETO -- SET to Ones */
- /* *S = #$FFFF */
-#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
- (void) readwordX(cpustate, addr, src_map);
-#endif
- writewordX(cpustate, addr, 0xFFFF, src_map);
- CYCLES(2, 10, 3);
- break;
- case 13: /* ABS */
- /* ABS --- ABSolute value */
- /* *S = |*S| */
- /* clearing ST_C seems to be necessary, although ABS will never set it. */
-#if (TMS99XX_MODEL <= TMS9985_ID)
-
- /* ti990/10 and tms9900/tms9980 only write the result if it has changed */
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
-
- #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- /* I guess ST_DC is cleared here, too*/
- cpustate->STATUS &= ~ ST_DC;
- #endif
-
- value = readwordX(cpustate, addr, src_map);
-
- CYCLES(5, 12, Mooof!);
-
- if (((INT16) value) > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (((INT16) value) < 0)
- {
- cpustate->STATUS |= ST_LGT;
- if (value == 0x8000)
- cpustate->STATUS |= ST_OV;
-
- #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- if (! (value & 0x0FFF))
- cpustate->STATUS |= ST_DC;
- #endif
-
- writewordX(cpustate, addr, - ((INT16) value), src_map);
- CYCLES(0, 2, Mooof!);
- }
- else
- cpustate->STATUS |= ST_EQ;
-
- break;
-
-#else
-
- /* tms9995 always write the result */
- cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
- value = readwordX(cpustate, addr, src_map);
-
- CYCLES(Mooof!, Mooof!, 3);
- if (((INT16) value) > 0)
- cpustate->STATUS |= ST_LGT | ST_AGT;
- else if (((INT16) value) < 0)
- {
- cpustate->STATUS |= ST_LGT;
- if (value == 0x8000)
- cpustate->STATUS |= ST_OV;
- value = - ((INT16) value);
- }
- else
- cpustate->STATUS |= ST_EQ;
-
- writewordX(cpustate, addr, value, src_map);
-
- break;
-
-#endif
-
-
-#if HAS_MAPPING
- /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610
- mapper chip to be associated with tms99000. */
- /* These opcode allow access to another page without the need of switching a page someplace. */
- /* Note that, if I read the 990/10 schematics correctly, two consecutive LDS or LDD would
- cause some trouble. */
- case 14: /* LDS */
- /* LDS --- Long Distance Source */
-
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- load_map_file(cpustate, addr, src_map, 2);
- cpustate->lds_flag = 1;
- cpustate->disable_interrupt_recognition = 1;
- break;
- case 15: /* LDD */
- /* LDD --- Long Distance Destination */
- #if HAS_PRIVILEGE
- if (cpustate->STATUS & ST_PR)
- {
- HANDLE_PRIVILEGE_VIOLATION
- break;
- }
- #endif
-
- load_map_file(cpustate, addr, src_map, 2);
- cpustate->ldd_flag = 1;
- cpustate->disable_interrupt_recognition = 1;
- break;
-
-#else
-
- default:
- /* illegal instructions */
- HANDLE_ILLEGAL;
- break;
-
-#endif
- }
-}
-
-
-/*==========================================================================
- Shift instructions, >0800->0BFF
- --------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e | C | W |
- ---------------------------------
-
- SRA, SRL, SLA, SRC
-============================================================================*/
-static void h0800(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 addr;
- register UINT16 cnt = (opcode & 0xF0) >> 4;
- register UINT16 value;
-
- addr = (opcode & 0xF);
- addr = ((addr+addr) + cpustate->WP) & ~1;
-
- CYCLES(3, 12, 5);
-
- if (cnt == 0)
- {
- CYCLES(2, 8, 2);
-
- cnt = READREG(R0) & 0xF;
-
- if (cnt == 0)
- cnt = 16;
- }
-
- CYCLES(cnt, cnt+cnt, cnt);
-
- switch ((opcode & 0x300) >> 8)
- {
- case 0: /* SRA */
- /* SRA --- Shift Right Arithmetic */
- /* *W >>= C (*W is filled on the left with a copy of the sign bit) */
- value = setst_sra_laec(cpustate, readword(cpustate, addr), cnt);
- writeword(cpustate, addr, value);
- break;
- case 1: /* SRL */
- /* SRL --- Shift Right Logical */
- /* *W >>= C (*W is filled on the left with 0) */
- value = setst_srl_laec(cpustate, readword(cpustate, addr), cnt);
- writeword(cpustate, addr, value);
- break;
- case 2: /* SLA */
- /* SLA --- Shift Left Arithmetic */
- /* *W <<= C */
- value = setst_sla_laeco(cpustate, readword(cpustate, addr), cnt);
- writeword(cpustate, addr, value);
- break;
- case 3: /* SRC */
- /* SRC --- Shift Right Circular */
- /* *W = rightcircularshift(*W, C) */
- value = setst_src_laec(cpustate, readword(cpustate, addr), cnt);
- writeword(cpustate, addr, value);
- break;
- }
-}
-
-
-#if 0 /* 990/12 opcodes */
-/*==========================================================================
- Additionnal instructions, >0C00->0C0F
- Additionnal single-register instructions, >0C10->0C3F
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |
- | o p c o d e | reg # |
- ---------------------------------
-
-============================================================================*/
-static void h0c00(tms99xx_state *cpustate, UINT16 opcode)
-{
- if (opcode & 0x30)
- {
- switch ((opcode & 0x30) >> 4)
- {
- case 1:
- /* INSF -- INSert Field */
- break;
- case 2:
- /* XV ---- eXtract Value */
- break;
- case 3:
- /* XF ---- eXtract Field */
- break;
- }
- }
- else
- {
- switch (opcode & 0x0F)
- {
- /* floating point instructions */
- case 0:
- /* CRI --- Convert Real to Integer */
- break;
- case 2:
- /* NEGR -- NEGate Real */
- break;
- case 4:
- /* CRE --- Convert Real to Extended integer */
- break;
- case 6:
- /* CER --- Convert Extended integer to Real */
- break;
-
- case 1:
- /* CDI --- Convert Double precision real to Integer */
- break;
- case 3:
- /* NEGD -- NEGate Double precision real */
- break;
- case 5:
- /* CDE --- Convert Double precision real to Extended integer */
- break;
- case 7:
- /* CED --- Convert Extended integer to Double precision real */
- break;
-
- case 8:
- /* NRM --- NoRMalize */
- break;
-
- case 9:
- /* TMB --- Test Memory Bit */
- break;
- case 10:
- /* TCMB -- Test and Clear Memory Bit */
- break;
- case 11:
- /* TSMB -- Test and Set Memory Bit */
- break;
-
- case 12:
- /* SRJ --- Subtract from Register and Jump */
- case 13:
- /* ARJ --- Add to Register and Jump */
-
- case 14:
- case 15:
- /* XIT --- eXIT from floating point interpreter */
- /* Generated by some compilers, but equivalent to NOP on TI990/12. May have been used
- by some software floating-point emulators. */
- break;
-
- default:
- HANDLE_ILLEGAL;
- break;
- }
- }
-}
-
-
-/*==========================================================================
- Additionnal single-operand instructions, >0C40->0DFF
- >0E40->0FFF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e |TS | S |
- ---------------------------------
-
-============================================================================*/
-static void h0c40(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 src;
-
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
-#endif
-
- src = decipheraddr(cpustate, opcode) & ~1;
-
- switch ((opcode & 0x03C0) >> 6)
- {
- case 1:
- /* AR ---- Add Real */
- break;
- case 2:
- /* CIR --- Convert Integer to Real */
- break;
- case 3:
- /* SR ---- Subtract Real */
- break;
- case 4:
- /* MR ---- Multiply Real */
- break;
- case 5:
- /* DR ---- Divide Real */
- break;
- case 6:
- /* LR ---- Load Real */
- break;
- case 7:
- /* STR --- STore Real */
- break;
- case 9:
- /* AD ---- Add Double */
- break;
- case 10:
- /* CID --- Convert Integer to Double */
- break;
- case 11:
- /* SD ---- Subtract Double */
- break;
- case 12:
- /* MD ---- Multiply Double */
- break;
- case 13:
- /* DD ---- Divide Double */
- break;
- case 14:
- /* LD ---- Load Double */
- break;
- case 15:
- /* SD ---- Store Double */
- break;
- default:
- HANDLE_ILLEGAL;
- break;
- }
-}
-
-/*==========================================================================
- Additionnal single-register instructions, >0E00->0E3F
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e | reg # |
- ---------------------------------
-
-============================================================================*/
-static void h0e00(tms99xx_state *cpustate, UINT16 opcode)
-{
- switch ((opcode & 0x30) >> 4)
- {
- case 1:
- /* IOF --- Invert Order of Field */
- break;
- case 1:
- /* SNEB -- Search string for Not Equal Byte */
- break;
- case 2:
- /* CRC --- Cyclic Redundancy Code calculation */
- break;
- case 3:
- /* TS ---- Translate String */
- break;
- }
-}
-#endif
-
-
-/*==========================================================================
- Jump, CRU bit instructions, >1000->1FFF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | o p c o d e | signed offset |
- ---------------------------------
-
- JMP, JLT, JLE, JEQ, JHE, JGT, JNE, JNC, JOC, JNO, JL, JH, JOP
- SBO, SBZ, TB
-============================================================================*/
-static void h1000(tms99xx_state *cpustate, UINT16 opcode)
-{
- /* we convert 8 bit signed word offset to a 16 bit effective word offset. */
- register INT16 offset = ((INT8) opcode);
-
-
- switch ((opcode & 0xF00) >> 8)
- {
- case 0: /* JMP */
- /* JMP --- unconditional JuMP */
- /* PC += offset */
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- break;
- case 1: /* JLT */
- /* JLT --- Jump if Less Than (arithmetic) */
- /* if (A==0 && EQ==0), PC += offset */
- if (! (cpustate->STATUS & (ST_AGT | ST_EQ)))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 2: /* JLE */
- /* JLE --- Jump if Lower or Equal (logical) */
- /* if (L==0 || EQ==1), PC += offset */
- if ((! (cpustate->STATUS & ST_LGT)) || (cpustate->STATUS & ST_EQ))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 3: /* JEQ */
- /* JEQ --- Jump if EQual */
- /* if (EQ==1), PC += offset */
- if (cpustate->STATUS & ST_EQ)
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 4: /* JHE */
- /* JHE --- Jump if Higher or Equal (logical) */
- /* if (L==1 || EQ==1), PC += offset */
- if (cpustate->STATUS & (ST_LGT | ST_EQ))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 5: /* JGT */
- /* JGT --- Jump if Greater Than (arithmetic) */
- /* if (A==1), PC += offset */
- if (cpustate->STATUS & ST_AGT)
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 6: /* JNE */
- /* JNE --- Jump if Not Equal */
- /* if (EQ==0), PC += offset */
- if (! (cpustate->STATUS & ST_EQ))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 7: /* JNC */
- /* JNC --- Jump if No Carry */
- /* if (C==0), PC += offset */
- if (! (cpustate->STATUS & ST_C))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 8: /* JOC */
- /* JOC --- Jump On Carry */
- /* if (C==1), PC += offset */
- if (cpustate->STATUS & ST_C)
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 9: /* JNO */
- /* JNO --- Jump if No Overflow */
- /* if (OV==0), PC += offset */
- if (! (cpustate->STATUS & ST_OV))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 10: /* JL */
- /* JL ---- Jump if Lower (logical) */
- /* if (L==0 && EQ==0), PC += offset */
- if (! (cpustate->STATUS & (ST_LGT | ST_EQ)))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 11: /* JH */
- /* JH ---- Jump if Higher (logical) */
- /* if (L==1 && EQ==0), PC += offset */
- if ((cpustate->STATUS & ST_LGT) && ! (cpustate->STATUS & ST_EQ))
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- break;
- case 12: /* JOP */
- /* JOP --- Jump On (odd) Parity */
- /* if (P==1), PC += offset */
- {
- /* Let's set ST_OP. */
- int i;
- UINT8 a;
- a = cpustate->lastparity;
- i = 0;
-
- while (a != 0)
- {
- if (a & 1) /* If current bit is set, */
- i++; /* increment bit count. */
- a >>= 1U; /* Next bit. */
- }
-
- /* Set ST_OP bit. */
- /*if (i & 1)
- cpustate->STATUS |= ST_OP;
- else
- cpustate->STATUS &= ~ ST_OP;*/
-
- /* Jump accordingly. */
- if (i & 1) /*(cpustate->STATUS & ST_OP)*/
- {
- cpustate->PC += (offset + offset);
- CYCLES(3, 10, 3);
- }
- else
- CYCLES(2, 8, 3);
- }
-
- break;
- case 13: /* SBO */
- /* SBO --- Set Bit to One */
- /* CRU Bit = 1 */
- #if HAS_PRIVILEGE
- if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1) == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- #else
- writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1);
- #endif
-
- CYCLES(4, 12, 8);
- break;
-
- case 14: /* SBZ */
- /* SBZ --- Set Bit to Zero */
- /* CRU Bit = 0 */
- #if HAS_PRIVILEGE
- if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0) == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- #else
- writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0);
- #endif
-
- CYCLES(4, 12, 8);
- break;
-
- case 15: /* TB */
- /* TB ---- Test Bit */
- /* EQ = (CRU Bit == 1) */
- #if HAS_PRIVILEGE
- {
- int value;
-
- value = readCRU(cpustate, (READREG(R12)>> 1) + offset, 1);
- if (value == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- else
- setst_e(cpustate, value & 1, 1);
- }
- #else
- setst_e(cpustate, readCRU(cpustate, (READREG(R12)>> 1) + offset, 1) & 1, 1);
- #endif
- CYCLES(5, 12, 8);
- break;
- }
-}
-
-
-/*==========================================================================
- General and One-Register instructions >2000->3FFF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ---------------------------------
- | opcode | D |TS | S |
- ---------------------------------
-
- COC, CZC, XOR, LDCR, STCR, XOP, MPY, DIV
-tms9940 : DCA, DCS, LIIM
-==========================================================================*/
-
-/* xop, ldcr and stcr are handled elsewhere */
-static void h2000(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 dest = (opcode & 0x3C0) >> 6;
- register UINT16 src;
- register UINT16 value;
-
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
-#endif
-
- src = decipheraddr(cpustate, opcode) & ~1;
- dest = ((dest+dest) + cpustate->WP) & ~1;
-
- switch ((opcode & 0x1C00) >> 10)
- {
- case 0: /* COC */
- /* COC --- Compare Ones Corresponding */
- /* status E bit = (S&D == S) */
- value = readwordX(cpustate, src, src_map);
- setst_e(cpustate, value & readword(cpustate, dest), value);
- CYCLES(5, 14, 4);
- break;
- case 1: /* CZC */
- /* CZC --- Compare Zeroes Corresponding */
- /* status E bit = (S&~D == S) */
- value = readwordX(cpustate, src, src_map);
- setst_e(cpustate, value & (~ readword(cpustate, dest)), value);
- CYCLES(5, 14, 4);
- break;
- case 2: /* XOR */
- /* XOR --- eXclusive OR */
- /* D ^= S */
- value = readwordX(cpustate, src, src_map);
- value ^= readword(cpustate, dest);
- setst_lae(cpustate, value);
- writeword(cpustate, dest,value);
- CYCLES(3, 14, 4);
- break;
- /*case 3:*/ /* XOP is implemented elsewhere */
- /*case 4:*/ /* LDCR is implemented elsewhere */
- /*case 5:*/ /* STCR is implemented elsewhere */
- case 6: /* MPY */
- /* MPY --- MultiPlY (unsigned) */
- /* Results: D:D+1 = D*S */
- /* Note that early TMS9995 reportedly performs an extra dummy read in PC space */
- {
- unsigned long prod = ((unsigned long) readwordX(cpustate, src, src_map));
- prod = prod * ((unsigned long) readword(cpustate, dest));
- writeword(cpustate, dest, prod >> 16);
- writeword(cpustate, (dest+2)&0xffff, prod);
- }
- /* ti990/10 : from 19 to 35, possibly 19 + (number of bits to 1 in one operand) */
- CYCLES(35, 52, 23);
- break;
- case 7: /* DIV */
- /* DIV --- DIVide (unsigned) */
- /* D = D/S D+1 = D%S */
- {
- UINT16 d = readwordX(cpustate, src, src_map);
- UINT16 hi = readword(cpustate, dest);
- unsigned long divq = (((unsigned long) hi) << 16) | readword(cpustate, (dest+2)&0xffff);
-
- if (d <= hi)
- {
- cpustate->STATUS |= ST_OV;
- CYCLES(4, 16, 6);
- }
- else
- {
- cpustate->STATUS &= ~ST_OV;
- writeword(cpustate, dest, divq/d);
- writeword(cpustate, (dest+2)&0xffff, divq%d);
- /* tms9900 : from 92 to 124, possibly 92 + 2*(number of bits to 1 (or 0?) in quotient) */
- /* tms9995 : 28 is the worst case */
- /* ti990/10 : from 41 to 58, possibly 41 + (number of bits to 1 (or 0?) in quotient) */
- CYCLES(41, 92, 28);
- }
- }
- break;
- }
-}
-
-static void xop(tms99xx_state *cpustate, UINT16 opcode)
-{ /* XOP */
- /* XOP --- eXtended OPeration */
- /* WP = *(40h+D), PC = *(42h+D) */
- /* New R13=old WP, New R14=Old IP, New R15=Old ST */
- /* New R11=S */
- /* Xop bit set */
-
- register UINT16 immediate = (opcode & 0x3C0) >> 6;
- register UINT16 operand;
-
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- switch (immediate)
- {
- case 0: /* DCA */
- /* DCA --- Decimal Correct Addition */
- operand = decipheraddrbyte(cpustate, opcode);
- {
- int value = readbyte(cpustate, operand);
- int X = (value >> 4) & 0xf;
- int Y = value & 0xf;
-
- if (Y >= 10)
- {
- Y -= 10;
- cpustate->STATUS |= ST_DC;
- X++;
- }
- else if (cpustate->STATUS & ST_DC)
- {
- Y += 6;
- }
-
- if (X >= 10)
- {
- X -= 10;
- cpustate->STATUS |= ST_C;
- }
- else if (cpustate->STATUS & ST_C)
- {
- X += 6;
- }
-
- writebyte(cpustate, operand, (X << 4) | Y);
- }
- break;
- case 1: /* DCS */
- /* DCS --- Decimal Correct Substraction */
- operand = decipheraddrbyte(cpustate, opcode);
- {
- int value = readbyte(cpustate, operand);
-
- if (! (cpustate->STATUS & ST_DC))
- {
- value += 10;
- }
-
- if (! (cpustate->STATUS & ST_C))
- {
- value += 10 << 4;
- }
-
- cpustate->STATUS ^= ST_DC;
-
- writebyte(cpustate, operand, value);
- }
- break;
- case 2: /* LIIM */
- case 3: /* LIIM */
- /* LIIM - Load Immediate Interrupt Mask */
- /* Does the same job as LIMI, with a different opcode format. */
- /* Note that, unlike TMS9900, the interrupt mask is only 2-bit long. */
- (void)decipheraddr(cpustate, opcode); /* dummy decode (personnal guess) */
-
- cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (opcode & ST_IM);
- break;
- default: /* normal XOP */
-#endif
-
- /* TODO : emulate 990/10 hardware XOP */
- operand = decipheraddr(cpustate, opcode);
-
- #if ((TMS99XX_MODEL <= TMS9989_ID) && (TMS99XX_MODEL != TI990_10_ID))
- (void)readword(cpustate, operand & ~1); /*dummy read (personnal guess)*/
- #endif
-
- contextswitchX(cpustate, 0x40 + (immediate << 2));
-
- #if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID))
- /* The bit is not set on tms9940 */
- cpustate->STATUS |= ST_X;
- #endif
-
- WRITEREG(R11, operand);
- CYCLES(7, 36, 15);
- cpustate->disable_interrupt_recognition = 1;
-
-#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)
- break;
- }
-#endif
-}
-
-/* LDCR and STCR */
-static void ldcr_stcr(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 cnt = (opcode & 0x3C0) >> 6;
- register UINT16 addr;
- int value;
-
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
-#endif
-
- if (cnt == 0)
- cnt = 16;
-
- if (cnt <= 8)
- addr = decipheraddrbyte(cpustate, opcode);
- else
- addr = decipheraddr(cpustate, opcode) & ~1;
-
- if (opcode < 0x3400)
- { /* LDCR */
- /* LDCR -- LoaD into CRu */
- /* CRU R12--CRU R12+D-1 set to S */
- if (cnt <= 8)
- {
-#if (TMS99XX_MODEL != TMS9995_ID)
- value = readbyteX(cpustate, addr, src_map);
-#else
- /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
- /* this must be because instruction decoding is too complex */
- value = readwordX(cpustate, addr & ~1, src_map);
- if (addr & 1)
- value &= 0xFF;
- else
- value = (value >> 8) & 0xFF;
-#endif
-
- (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
-
- setst_byte_laep(cpustate, value);
- }
- else
- {
- value = readwordX(cpustate, addr, src_map);
-
- (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
-
- setst_lae(cpustate, value);
- }
-
- #if HAS_PRIVILEGE
- if (writeCRU(cpustate, (READREG(R12) >> 1), cnt, value) == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- #else
- writeCRU(cpustate, (READREG(R12) >> 1), cnt, value);
- #endif
-
- CYCLES(4+cnt, 20 + cnt+cnt, 9 + cnt+cnt);
- }
- else
- { /* STCR */
- /* STCR -- STore from CRu */
- /* S = CRU R12--CRU R12+D-1 */
- if (cnt <= 8)
- {
-#if (TMS99XX_MODEL != TMS9995_ID)
-
- (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/
- // MZ: Read before write
- int value2 = readwordX(cpustate, addr & ~1, src_map);
-
- #if HAS_PRIVILEGE
- value = readCRU(cpustate, (READREG(R12) >> 1), cnt);
-
- if (value == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- else
- {
- setst_byte_laep(cpustate, value);
- writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map);
- }
- #else
- value = readCRU(cpustate, (READREG(R12) >> 1), cnt);
- setst_byte_laep(cpustate, value);
-
- writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map);
- #endif
- CYCLES(18+cnt, (cnt != 8) ? 42 : 44, 19 + cnt);
-#else
- /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
- /* this must be because instruction decoding is too complex */
- int value2 = readwordX(cpustate, addr & ~1, src_map);
-
- (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/
-
- value = readCRU(cpustate, (READREG(R12) >> 1), cnt);
- setst_byte_laep(cpustate, value);
-
- if (addr & 1)
- writewordX(cpustate, addr & ~1, (value & 0x00FF) | (value2 & 0xFF00), src_map);
- else
- writewordX(cpustate, addr & ~1, (value2 & 0x00FF) | ((value << 8) & 0xFF00), src_map);
-
- CYCLES(Mooof!, Mooof!, 19 + cnt);
-#endif
- }
- else
- {
- (void)readwordX(cpustate, addr, src_map); /*dummy read*/
-
- (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/
-
- #if HAS_PRIVILEGE
- value = readCRU(cpustate, (READREG(R12) >> 1), cnt);
- if (value == CRU_PRIVILEGE_VIOLATION)
- HANDLE_PRIVILEGE_VIOLATION
- else
- {
- setst_lae(cpustate, value);
- writewordX(cpustate, addr, value, src_map);
- }
- #else
- value = readCRU(cpustate, (READREG(R12) >> 1), cnt);
- setst_lae(cpustate, value);
- writewordX(cpustate, addr, value, src_map);
- #endif
- CYCLES(24+cnt, (cnt != 16) ? 58 : 60, 27 + cnt);
- }
- }
-}
-
-
-/*==========================================================================
- Two-Operand instructions >4000->FFFF
- ---------------------------------------------------------------------------
-
- 0 1 2 3-4 5 6 7+8 9 A B-C D E F
- ----------------------------------
- |opcode|B|TD | D |TS | S |
- ----------------------------------
-
- SZC, SZCB, S, SB, C, CB, A, AB, MOV, MOVB, SOC, SOCB
-============================================================================*/
-
-/* word instructions */
-static void h4000w(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 src;
- register UINT16 dest;
- register UINT16 value;
-
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
- int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map;
-#endif
-
- src = decipheraddr(cpustate, opcode) & ~1;
- dest = decipheraddr(cpustate, opcode >> 6) & ~1;
-
- value = readwordX(cpustate, src, src_map);
-
- switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
- {
- case 2: /* SZC */
- /* SZC --- Set Zeros Corresponding */
- /* D &= ~S */
- value = readwordX(cpustate, dest, dst_map) & (~ value);
- setst_lae(cpustate, value);
- writewordX(cpustate, dest, value, dst_map);
- CYCLES(2, 14, 4);
- break;
- case 3: /* S */
- /* S ----- Subtract */
- /* D -= S */
- value = setst_sub_laeco(cpustate, readwordX(cpustate, dest, dst_map), value);
- writewordX(cpustate, dest, value, dst_map);
- CYCLES(2, 14, 4);
- break;
- case 4: /* C */
- /* C ----- Compare */
- /* ST = (D - S) */
- setst_c_lae(cpustate, readwordX(cpustate, dest, dst_map), value);
- CYCLES(5, 14, 4);
- break;
- case 5: /* A */
- /* A ----- Add */
- /* D += S */
- value = setst_add_laeco(cpustate, readwordX(cpustate, dest, dst_map), value);
- writewordX(cpustate, dest, value, dst_map);
- CYCLES(2, 14, 4);
- break;
- case 6: /* MOV */
- /* MOV --- MOVe */
- /* D = S */
- setst_lae(cpustate, value);
- #if ((TMS99XX_MODEL >= TMS9900_ID) && (TMS99XX_MODEL <= TMS9985_ID))
- /* MOV performs a dummy read with tms9900/9980 (but neither ti990/10 nor tms9995) */
- (void)readwordX(cpustate, dest, dst_map);
- #endif
- writewordX(cpustate, dest, value, dst_map);
- CYCLES(1, 14, 3);
- break;
- case 7: /* SOC */
- /* SOC --- Set Ones Corresponding */
- /* D |= S */
- value = value | readwordX(cpustate, dest, dst_map);
- setst_lae(cpustate, value);
- writewordX(cpustate, dest, value, dst_map);
- CYCLES(2, 14, 4);
- break;
- }
-}
-
-/* byte instruction */
-static void h4000b(tms99xx_state *cpustate, UINT16 opcode)
-{
- register UINT16 src;
- register UINT16 dest;
- register UINT16 value;
-
-#if HAS_MAPPING
- int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map;
- int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map;
-#endif
-
- src = decipheraddrbyte(cpustate, opcode);
- dest = decipheraddrbyte(cpustate, opcode >> 6);
-
- value = readbyteX(cpustate, src, src_map);
-
- switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
- {
- case 2: /* SZCB */
- /* SZCB -- Set Zeros Corresponding, Byte */
- /* D &= ~S */
- value = readbyteX(cpustate, dest, dst_map) & (~ value);
- setst_byte_laep(cpustate, value);
- writebyteX(cpustate, dest, value, dst_map);
- CYCLES(3, 14, 4);
- break;
- case 3: /* SB */
- /* SB ---- Subtract, Byte */
- /* D -= S */
- value = setst_subbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value);
- writebyteX(cpustate, dest, value, dst_map);
- CYCLES(3, 14, 4);
- break;
- case 4: /* CB */
- /* CB ---- Compare Bytes */
- /* ST = (D - S) */
- setst_c_lae(cpustate, readbyteX(cpustate, dest, dst_map)<<8, value<<8);
- cpustate->lastparity = value;
- CYCLES(5, 14, 4);
- break;
- case 5: /* AB */
- /* AB ---- Add, Byte */
- /* D += S */
- value = setst_addbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value);
- writebyteX(cpustate, dest, value, dst_map);
- CYCLES(3, 14, 4);
- break;
- case 6: /* MOVB */
- /* MOVB -- MOVe Bytes */
- /* D = S */
- setst_byte_laep(cpustate, value);
- #if (TMS99XX_MODEL <= TMS9985_ID)
- /* On ti990/10 and tms9900, MOVB needs to read destination, because it cannot actually
- read one single byte. It reads a word, replaces the relevant byte, then write
- the result. A tms9980 should not need to do so, but still does, because it is just
- a tms9900 with a 16 to 8 bit multiplexer (instead of a new chip design, like tms9995). */
- (void)readbyteX(cpustate, dest, dst_map);
- #endif
- writebyteX(cpustate, dest, value, dst_map);
- CYCLES(3, 14, 3);
- break;
- case 7: /* SOCB */
- /* SOCB -- Set Ones Corresponding, Byte */
- /* D |= S */
- value = value | readbyteX(cpustate, dest, dst_map);
- setst_byte_laep(cpustate, value);
- writebyteX(cpustate, dest, value, dst_map);
- CYCLES(3, 14, 4);
- break;
- }
-}
-
-
-INLINE void execute(tms99xx_state *cpustate, UINT16 opcode)
-{
-#if (! HAS_9995_OPCODES)
-
- /* tms9900-like instruction set*/
-
- static void (*const jumptable_short[128])(tms99xx_state *,UINT16) =
- {
- &illegal,&h0200,&h0400,&h0400,&h0800,&h0800,&illegal,&illegal,
- &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
- &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&xop,&xop,
- &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&h2000,&h2000,&h2000,&h2000,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
- };
-
- (* jumptable_short[opcode >> 9])(cpustate, opcode);
-
-#else
-
- /* tms9989 and tms9995 include 4 extra instructions, and one additionnal instruction type */
- /* tms99000 includes yet another additional instruction */
-
- static void (*const jumptable_long[256])(tms99xx_state *,UINT16) =
- {
- &h0040,&h0100,&h0200,&h0200,&h0400,&h0400,&h0400,&h0400,
- &h0800,&h0800,&h0800,&h0800,&illegal,&illegal,&illegal,&illegal,
- &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
- &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
- &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
- &h2000,&h2000,&h2000,&h2000,&xop,&xop,&xop,&xop,
- &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
- &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
- &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
- };
-
- (* jumptable_long[opcode >> 8])(cpustate, opcode);
-
-#endif
-}
-
-/**************************************************************************
- * Generic set_info
- **************************************************************************/
-
-static CPU_SET_INFO( tms99xx )
-{
- tms99xx_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 + INPUT_LINE_NMI: tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, info->i); break;
- case CPUINFO_INT_INPUT_STATE + 0: tms99xx_set_irq_line(cpustate, 0, info->i); break;
- case CPUINFO_INT_INPUT_STATE + 1: tms99xx_set_irq_line(cpustate, 1, info->i); break;
- case CPUINFO_INT_INPUT_STATE + 2: tms99xx_set_irq_line(cpustate, 2, info->i); break;
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- case CPUINFO_INT_PC:
- {
- const unsigned top = (cpustate->cur_map == 0) ? 0xf800 : 0x10000;
-
- if ((cpustate->cur_map == 0) && (info->i >= 0x1ff800))
- /* intercept TPCS and CPU ROM */
- cpustate->PC = info->i - 0x1f0000;
- else if (! cpustate->mapping_on)
- cpustate->PC = (info->i < top) ? info->i : 0;
- else
- {
- if ((info->i >= cpustate->map_files[cpustate->cur_map].bias[0])
- && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[0]+cpustate->map_files[cpustate->cur_map].limit[0])))
- cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[0];
- else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[0]))
- && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[1])))
- cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[1];
- else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[0]))
- && (info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[1]))
- && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[2])))
- cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[2];
- else
- {
- /*if ((info->i < top)
- && (info->i > cpustate->map_files[cpustate->cur_map].limit[0])
- && (info->i > cpustate->map_files[cpustate->cur_map].limit[1])
- && (info->i > cpustate->map_files[cpustate->cur_map].limit[2]))
- cpustate->PC = info->i;
- else*/
- cpustate->PC = 0;
- }
- /*if (info->i >= top)
- cpustate->PC = 0;*/
- }
- cpustate->PC &= 0xfffe;
- }
- break;
-#else
- case CPUINFO_INT_PC:
-#endif
- case CPUINFO_INT_REGISTER + TMS9900_PC: cpustate->PC = info->i & 0xfffe; break;
- case CPUINFO_INT_REGISTER + TMS9900_IR: cpustate->IR = info->i; break;
- case CPUINFO_INT_SP:
- case CPUINFO_INT_REGISTER + TMS9900_WP: cpustate->WP = info->i & 0xfffe; break;
- case CPUINFO_INT_REGISTER + TMS9900_STATUS: cpustate->STATUS = info->i; getstat(cpustate); break;
- case CPUINFO_INT_REGISTER + TMS9900_R0: WRITEREG_DEBUG(cpustate, R0, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R1: WRITEREG_DEBUG(cpustate, R1, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R2: WRITEREG_DEBUG(cpustate, R2, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R3: WRITEREG_DEBUG(cpustate, R3, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R4: WRITEREG_DEBUG(cpustate, R4, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R5: WRITEREG_DEBUG(cpustate, R5, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R6: WRITEREG_DEBUG(cpustate, R6, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R7: WRITEREG_DEBUG(cpustate, R7, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R8: WRITEREG_DEBUG(cpustate, R8, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R9: WRITEREG_DEBUG(cpustate, R9, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R10: WRITEREG_DEBUG(cpustate, R10, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R11: WRITEREG_DEBUG(cpustate, R11, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R12: WRITEREG_DEBUG(cpustate, R12, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R13: WRITEREG_DEBUG(cpustate, R13, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R14: WRITEREG_DEBUG(cpustate, R14, info->i); break;
- case CPUINFO_INT_REGISTER + TMS9900_R15: WRITEREG_DEBUG(cpustate, R15, info->i); break;
- }
-}
-
-
-
-/**************************************************************************
- * Generic get_info
- **************************************************************************/
-
-void TMS99XX_GET_INFO(legacy_cpu_device *device, UINT32 state, cpuinfo *info)
-{
- tms99xx_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(tms99xx_state); break;
- case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
- case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
- case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break;
- case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
- case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
- case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
- case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6;/*8 with 990/12, 99105, 99110*/break;
- case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
- case CPUINFO_INT_MAX_CYCLES: info->i = 10;/*TODO: compute this value*/break;
-
-#if (USE_16_BIT_ACCESSORS)
- case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break;
-#else
- case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
-#endif
- case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM:
-#if (TMS99XX_MODEL == TI990_10_ID)
- /* this CPU has a mapper to expand the address space */
- info->i = 21;
-#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
- /* basic 16-bit address bus */
- info->i = 16;
-#elif (TMS99XX_MODEL == TMS9980_ID)
- /* 2 address MSBits are unconnected */
- info->i = 14;
-#else
- #warning "Please check how many address bits your CPU has."
- info->i = 16;
-#endif
- break;
- case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break;
- case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
- case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
- case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO:
-#if (TMS99XX_MODEL == TI990_10_ID)
- /* 3 MSBs do exist, although they are not connected (don't ask...) */
- info->i = 15;
-#elif (TMS99XX_MODEL == TMS9900_ID)
- /* 3 MSBs are external instruction code */
- info->i = 12;
-#elif (TMS99XX_MODEL == TMS9980_ID)
- /* 2 bits unused, and 2 MSBs are external instruction code */
- info->i = 13;
-#elif (TMS99XX_MODEL == TMS9940_ID)
- /* 9 internal address lines (8 external) */
- info->i = 9;
-#elif (TMS99XX_MODEL == TMS9995_ID)
- /* 15-bit address and data bus lines D0-D2 provide the external instruction code */
- info->i = 15+3;
-#else
- #warning "I don't know how your processor handles CRU."
- info->i = 15;
-#endif
- break;
- case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
-
-/* not implemented */
-/* case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = get_irq_line(INPUT_LINE_NMI); break;
- case CPUINFO_INT_INPUT_STATE + 0: info->i = get_irq_line(0); break;
- case CPUINFO_INT_INPUT_STATE + 1: info->i = get_irq_line(1); break;
- case CPUINFO_INT_INPUT_STATE + 2: info->i = get_irq_line(2); break;*/
-
- case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break;
-
-#if (TMS99XX_MODEL == TI990_10_ID)
- case CPUINFO_INT_PC:
- if ((cpustate->cur_map == 0) && (cpustate->PC >= 0xf800))
- /* intercept TPCS and CPU ROM */
- info->i = 0x1f0000+cpustate->PC;
- else if (! cpustate->mapping_on)
- info->i = cpustate->PC;
- else
- {
- int map_index;
-
- if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[0])
- map_index = 0;
- else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[1])
- map_index = 1;
- else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[2])
- map_index = 2;
- else
- {
- info->i = cpustate->PC;
- break;
- }
-
- info->i = cpustate->map_files[cpustate->cur_map].bias[map_index]+cpustate->PC;
- }
- break;
-#else
- case CPUINFO_INT_PC:
-#endif
- case CPUINFO_INT_REGISTER + TMS9900_PC: info->i = cpustate->PC; break;
- case CPUINFO_INT_REGISTER + TMS9900_IR: info->i = cpustate->IR; break;
- case CPUINFO_INT_SP:
- case CPUINFO_INT_REGISTER + TMS9900_WP: info->i = cpustate->WP; break;
- case CPUINFO_INT_REGISTER + TMS9900_STATUS: setstat(cpustate); info->i = cpustate->STATUS; break;
- case CPUINFO_INT_REGISTER + TMS9900_R0: info->i = READREG_DEBUG(cpustate, R0); break;
- case CPUINFO_INT_REGISTER + TMS9900_R1: info->i = READREG_DEBUG(cpustate, R1); break;
- case CPUINFO_INT_REGISTER + TMS9900_R2: info->i = READREG_DEBUG(cpustate, R2); break;
- case CPUINFO_INT_REGISTER + TMS9900_R3: info->i = READREG_DEBUG(cpustate, R3); break;
- case CPUINFO_INT_REGISTER + TMS9900_R4: info->i = READREG_DEBUG(cpustate, R4); break;
- case CPUINFO_INT_REGISTER + TMS9900_R5: info->i = READREG_DEBUG(cpustate, R5); break;
- case CPUINFO_INT_REGISTER + TMS9900_R6: info->i = READREG_DEBUG(cpustate, R6); break;
- case CPUINFO_INT_REGISTER + TMS9900_R7: info->i = READREG_DEBUG(cpustate, R7); break;
- case CPUINFO_INT_REGISTER + TMS9900_R8: info->i = READREG_DEBUG(cpustate, R8); break;
- case CPUINFO_INT_REGISTER + TMS9900_R9: info->i = READREG_DEBUG(cpustate, R9); break;
- case CPUINFO_INT_REGISTER + TMS9900_R10: info->i = READREG_DEBUG(cpustate, R10); break;
- case CPUINFO_INT_REGISTER + TMS9900_R11: info->i = READREG_DEBUG(cpustate, R11); break;
- case CPUINFO_INT_REGISTER + TMS9900_R12: info->i = READREG_DEBUG(cpustate, R12); break;
- case CPUINFO_INT_REGISTER + TMS9900_R13: info->i = READREG_DEBUG(cpustate, R13); break;
- case CPUINFO_INT_REGISTER + TMS9900_R14: info->i = READREG_DEBUG(cpustate, R14); break;
- case CPUINFO_INT_REGISTER + TMS9900_R15: info->i = READREG_DEBUG(cpustate, R15); 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(tms99xx); break;
- case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(tms99xx); break;
- case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(tms99xx); break;
- case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(tms99xx); break;
- case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(tms99xx); break;
- case CPUINFO_FCT_BURN: info->burn = NULL; break;
- case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(tms99xx); break;
- case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break;
-
- /* --- the following bits of info are returned as NULL-terminated strings --- */
- case CPUINFO_STR_NAME: strcpy(info->s, TMS99XX_device_get_name); break;
- case CPUINFO_STR_SHORTNAME: strcpy(info->s, TMS99XX_device_get_shortname); break;
-
- case CPUINFO_STR_FAMILY: strcpy(info->s, "Texas Instruments 9900L"); break;
- case CPUINFO_STR_VERSION: strcpy(info->s, "2.0"); break;
- case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
- case CPUINFO_STR_CREDITS: strcpy(info->s, "C TMS9900 emulator by Edward Swartz, initially converted for Mame by M.Coates, updated by R. Nabet"); break;
-
- case CPUINFO_STR_FLAGS:
- sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
- cpustate->WP & 0x8000 ? 'L':'.',
- cpustate->WP & 0x4000 ? 'A':'.',
- cpustate->WP & 0x2000 ? 'E':'.',
- cpustate->WP & 0x1000 ? 'C':'.',
- cpustate->WP & 0x0800 ? 'V':'.',
- cpustate->WP & 0x0400 ? 'P':'.',
- cpustate->WP & 0x0200 ? 'X':'.',
- cpustate->WP & 0x0100 ? '?':'.',
- cpustate->WP & 0x0080 ? '?':'.',
- cpustate->WP & 0x0040 ? '?':'.',
- cpustate->WP & 0x0020 ? '?':'.',
- cpustate->WP & 0x0010 ? '?':'.',
- cpustate->WP & 0x0008 ? 'I':'.',
- cpustate->WP & 0x0004 ? 'I':'.',
- cpustate->WP & 0x0002 ? 'I':'.',
- cpustate->WP & 0x0001 ? 'I':'.');
- break;
-
- case CPUINFO_STR_REGISTER + TMS9900_PC: sprintf(info->s, "PC :%04X", cpustate->PC); break;
- case CPUINFO_STR_REGISTER + TMS9900_IR: sprintf(info->s, "IR :%04X", cpustate->IR); break;
- case CPUINFO_STR_REGISTER + TMS9900_WP: sprintf(info->s, "WP :%04X", cpustate->WP); break;
- case CPUINFO_STR_REGISTER + TMS9900_STATUS: sprintf(info->s, "ST :%04X", cpustate->STATUS); break;
-
- case CPUINFO_STR_REGISTER + TMS9900_R0: sprintf(info->s, "R0 :%04X", READREG_DEBUG(cpustate, R0)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R1: sprintf(info->s, "R1 :%04X", READREG_DEBUG(cpustate, R1)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R2: sprintf(info->s, "R2 :%04X", READREG_DEBUG(cpustate, R2)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R3: sprintf(info->s, "R3 :%04X", READREG_DEBUG(cpustate, R3)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R4: sprintf(info->s, "R4 :%04X", READREG_DEBUG(cpustate, R4)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R5: sprintf(info->s, "R5 :%04X", READREG_DEBUG(cpustate, R5)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R6: sprintf(info->s, "R6 :%04X", READREG_DEBUG(cpustate, R6)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R7: sprintf(info->s, "R7 :%04X", READREG_DEBUG(cpustate, R7)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R8: sprintf(info->s, "R8 :%04X", READREG_DEBUG(cpustate, R8)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R9: sprintf(info->s, "R9 :%04X", READREG_DEBUG(cpustate, R9)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R10: sprintf(info->s, "R10:%04X", READREG_DEBUG(cpustate, R10)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R11: sprintf(info->s, "R11:%04X", READREG_DEBUG(cpustate, R11)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R12: sprintf(info->s, "R12:%04X", READREG_DEBUG(cpustate, R12)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R13: sprintf(info->s, "R13:%04X", READREG_DEBUG(cpustate, R13)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R14: sprintf(info->s, "R14:%04X", READREG_DEBUG(cpustate, R14)); break;
- case CPUINFO_STR_REGISTER + TMS9900_R15: sprintf(info->s, "R15:%04X", READREG_DEBUG(cpustate, R15)); break;
- }
-}
diff --git a/src/emu/cpu/tms9900/ti990_10.c b/src/emu/cpu/tms9900/ti990_10.c
deleted file mode 100644
index b6cd8d32d41..00000000000
--- a/src/emu/cpu/tms9900/ti990_10.c
+++ /dev/null
@@ -1,148 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-
-/*
- Texas Instruments TI990/10 CPU board
-
- The first member of the family was actually the ti990/10 minicomputer,
- released in 1975. tms9900 was released in 1976, and has the same
- instruction set as ti990/10: however, tms9900 is slower, it does not
- support privileges and memory mapping, and illegal instructions do not
- cause an error interrupt.
-
- The ti990 family later evoluted into the huge ti990/12 system, with support
- for 144 different instructions, and microcode programming in case some user
- found it was not enough. ti990/10 was eventually replaced by a cheaper
- ti990/10a board, built around a tms99000 microprocessor.
-
- tms99000 is the successor to both ti9900 and ti990/10. It supports
- privileges, and has a coprocessor interface which enables the use of an
- external memory mapper. Additionnally, it can use a Macrostore ROM to
- emulate additional instructions.
-
- **** This is WORK IN PROGRESS ****
-*/
-
-#include "ti990_10.h"
-
-/*
- The following defines can be set to 0 or 1 to disable or enable certain
- output in the log.
-*/
-// Emulation setup
-#define TRACE_SETUP 0
-
-// Emulation details
-#define TRACE_EMU 0
-
-/****************************************************************************
- Constructor for TI 990/10
- The CRU mask is related to the bits, not to their addresses which are
- twice their number. Accordingly, the TMS9900 has a CRU bitmask 0x0fff.
-****************************************************************************/
-
-ti990_10_device::ti990_10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : cpu_device(mconfig, TI990_10, "TI990/10 CPU", tag, owner, clock, "ti990_10_cpu", __FILE__),
- m_program_config("program", ENDIANNESS_BIG, 16, 16),
- m_io_config("cru", ENDIANNESS_BIG, 8, 12),
- m_prgspace(NULL),
- m_cru(NULL)
-{
-}
-
-ti990_10_device::~ti990_10_device()
-{
-}
-
-void ti990_10_device::device_start()
-{
- m_prgspace = &space(AS_PROGRAM);
- m_cru = &space(AS_IO);
-
- // set our instruction counter
- m_icountptr = &m_icount;
-
- state_add(STATE_GENPC, "curpc", PC).formatstr("%4s").noshow();
- state_add(STATE_GENFLAGS, "status", m_state_any).callimport().callexport().formatstr("%16s").noshow();
-}
-
-void ti990_10_device::device_stop()
-{
- if (TRACE_SETUP) logerror("ti990_10: Deleting lookup tables\n");
-}
-
-/*
- TI990_10 hard reset
- The device reset is just the emulator's trigger for the reset procedure
- which is invoked via the main loop.
-*/
-void ti990_10_device::device_reset()
-{
- if (TRACE_EMU) logerror("ti990_10: Device reset by emulator\n");
-}
-
-const address_space_config *ti990_10_device::memory_space_config(address_spacenum spacenum) const
-{
- switch (spacenum)
- {
- case AS_PROGRAM:
- return &m_program_config;
-
- case AS_IO:
- return &m_io_config;
-
- default:
- return NULL;
- }
-}
-
-void ti990_10_device::execute_run()
-{
- do
- {
- // TODO: Complete the implementation
- m_icount--;
- } while (m_icount>0);
-}
-
-void ti990_10_device::execute_set_input(int irqline, int state)
-{
-}
-
-// ==========================================================================
-
-UINT32 ti990_10_device::execute_min_cycles() const
-{
- return 2;
-}
-
-// TODO: Compute this value, just a wild guess for the average
-UINT32 ti990_10_device::execute_max_cycles() const
-{
- return 10;
-}
-
-UINT32 ti990_10_device::execute_input_lines() const
-{
- return 2;
-}
-
-// device_disasm_interface overrides
-UINT32 ti990_10_device::disasm_min_opcode_bytes() const
-{
- return 2;
-}
-
-UINT32 ti990_10_device::disasm_max_opcode_bytes() const
-{
- return 6;
-}
-
-// TODO: check 9900dasm
-offs_t ti990_10_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
-{
- extern CPU_DISASSEMBLE( tms9900 );
- return CPU_DISASSEMBLE_NAME(tms9900)(this, buffer, pc, oprom, opram, options);
-}
-
-const device_type TI990_10 = &device_creator<ti990_10_device>;
diff --git a/src/emu/cpu/tms9900/ti990_10.h b/src/emu/cpu/tms9900/ti990_10.h
deleted file mode 100644
index f1d4e20ce3a..00000000000
--- a/src/emu/cpu/tms9900/ti990_10.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- TI 990 CPU board
- See ti990_10.c for documentation
-*/
-
-#ifndef __TI990_10_H__
-#define __TI990_10_H__
-
-#include "emu.h"
-#include "debugger.h"
-#include "tms99com.h"
-
-class ti990_10_device : public cpu_device
-{
-public:
- ti990_10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
- ~ti990_10_device();
-
-protected:
- // device-level overrides
- void device_start();
- void device_stop();
- void device_reset();
-
- // device_execute_interface overrides
- UINT32 execute_min_cycles() const;
- UINT32 execute_max_cycles() const;
- UINT32 execute_input_lines() const;
- void execute_set_input(int irqline, int state);
- void execute_run();
-
- // device_disasm_interface overrides
- UINT32 disasm_min_opcode_bytes() const;
- UINT32 disasm_max_opcode_bytes() const;
- offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
-
- const address_space_config* memory_space_config(address_spacenum spacenum) const;
-
- const address_space_config m_program_config;
- const address_space_config m_io_config;
- address_space* m_prgspace;
- address_space* m_cru;
-
- // Cycle counter
- int m_icount;
-
- // Hardware registers
- UINT16 WP; // Workspace pointer
- UINT16 PC; // Program counter
- UINT16 ST; // Status register
-
-private:
- UINT16 m_state_any;
-};
-
-// device type definition
-extern const device_type TI990_10;
-
-#endif /* __TI990_10_H__ */
diff --git a/src/emu/cpu/tms9900/tms9900.c b/src/emu/cpu/tms9900/tms9900.c
deleted file mode 100644
index 0029d9cf392..00000000000
--- a/src/emu/cpu/tms9900/tms9900.c
+++ /dev/null
@@ -1,2736 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- Texas Instruments TMS9900
-
- +--------------------+
- V_BB | 1 o 64| /HOLD
- V_CC | 2 63| /MEMEN
- WAIT | 3 62| READY
- /LOAD | 4 61| /WE
- HOLDA | 5 60| CRUCLK
- /RESET | 6 59| V_CC
- IAQ | 7 58| -
- PHI1 | 8 57| -
- PHI2 | 9 56| D15 -+ LSB
- LSB +- A14 |10 55| D14 |
- | A13 |11 54| D13 |
- | A12 |12 53| D12 |
- | A11 |13 52| D11 |
- Address | A10 |14 +--------+ 51| D10 | Data
- bus | A9 |15 | | 50| D9 | bus
- 32K * | A8 |16 | | 49| D8 | 16 bit
- 16bit | A7 |17 | | 48| D7 |
- | A6 |18 | | 47| D6 |
- | A5 |19 +--------+ 46| D5 |
- | A4 |20 45| D4 |
- | A3 |21 44| D3 |
- | A2 |22 43| D2 |
- | A1 |23 42| D1 |
- MSB +- A0 |24 41| D0 -+ MSB
- PHI4 |25 40| V_SS
- V_SS |26 39| -
- V_DD |27 38| -
- PHI3 |28 37| -
- DBIN |29 36| IC0 -+ MSB
- CRUOUT |30 35| IC1 | Interrupt
- CRUIN |31 34| IC2 | level
- /INTREQ |32 33| IC3 -+ LSB
- +--------------------+
-
- WAIT out Processor in wait state
- /LOAD in Non-maskable interrupt
- HOLDA out Hold acknowledge
- /RESET in Reset
- IAQ out Instruction acquisition
- PHI1-4 in Clock phase inputs
- DBIN out Data bus in input mode
- CRUOUT out Communication register unit data output
- CRUIN in Communication register unit data input
- /INTREQ in Interrupt request
- CRUCLK out Communication register unit clock output
- /WE out Data available for memory write
- READY in Memory ready for access
- /MEMEN out Address bus contains memory address
- /HOLD in External device acquires address and data bus lines
-
- V_BB -5V supply
- V_CC +5V supply (pins 2 and 59 connected in parallel)
- V_DD +12V supply
- V_SS 0V Ground reference (pins 26 and 40 connected in parallel)
-
- A0-A14 out Address bus (32768 words of 16 bit width)
- D0-A15 i/o Data bus
- IC0-IC3 in Interrupt level (0-15)
-
- Note that Texas Instruments' bit numberings define bit 0 as the
- most significant bit (different to most other systems). Also, the
- system uses big-endian memory organisation: Storing the word 0x1234 at
- address 0x0000 means that the byte 0x12 is stored at 0x0000 and byte 0x34
- is stored at 0x0001.
-
- The processor also knows byte-oriented operations (like add byte (AB),
- move byte (MOVB)). This makes it necessary for the CPU to read the word
- from the target memory location first, change the respective byte, and
- write it back.
-
- See the TI-99/4A driver for an application of the TMS9900 processor
- within an 8-bit data bus board layout (using a data bus multiplexer).
-
- Subcycle handling
-
- In this implementation we try to emulate the internal operations as
- precisely as possible, following the technical specifications. We need
- not try to be clock-precise with every tick; it suffices to perform
- the proper number of operations within a given time span.
-
- For each command the CPU executes a microprogram which requires some
- amount of cycles to complete. During this time the external clock continues
- to issue pulses which can be used to control wait state creation. As we
- do not emulate external clocks this implementation offers an extra output
- "clock_out" (which, however, is available for the TMS9995) which pulses
- at a rate of 3 MHz. External devices (e.g. memory controllers) may count
- the pulses and pull down the READY line (with set_ready) as needed.
-
- Another possibility for creating wait states is to pull down the line
- for some time set by a timer. This is done, for example, by circuits like
- GROMs or speech synthesis processors (TMS52xx).
-
- TODO:
- - Fine-tune cycles
- - State save
- - HOLD state should be tested; I don't have test cases yet
-
- Michael Zapf, June 2012
-*/
-
-#include "tms9900.h"
-
-/* tms9900 ST register bits. */
-enum
-{
- ST_LH = 0x8000, // Logical higher (unsigned comparison)
- ST_AGT = 0x4000, // Arithmetical greater than (signed comparison)
- ST_EQ = 0x2000, // Equal
- ST_C = 0x1000, // Carry
- ST_OV = 0x0800, // Overflow (when using signed operations)
- ST_OP = 0x0400, // Odd parity (used with byte operations)
- ST_X = 0x0200, // XOP
- ST_IM = 0x000f // Interrupt mask
-};
-
-/*
- The following defines can be set to 0 or 1 to disable or enable certain
- output in the log.
-*/
-// Emulation setup
-#define TRACE_SETUP 0
-
-// Emulation details
-#define TRACE_EMU 0
-
-// Location and command
-#define TRACE_EXEC 0
-
-// Memory operation
-#define TRACE_MEM 0
-
-// Address bus operation
-#define TRACE_ADDRESSBUS 0
-
-// Cycle count
-#define TRACE_CYCLES 0
-
-// Clock ticks
-#define TRACE_CLOCK 0
-
-// Wait states
-#define TRACE_WAIT 0
-
-// Interrupts
-#define TRACE_INT 0
-
-// CRU operation
-#define TRACE_CRU 0
-
-// Status register
-#define TRACE_STATUS 0
-
-// ALU details
-#define TRACE_ALU 0
-
-// Microinstruction level
-#define TRACE_MICRO 0
-
-/****************************************************************************
- Common constructor for TMS9900 and TMS9980A
- The CRU mask is related to the bits, not to their addresses which are
- twice their number. Accordingly, the TMS9900 has a CRU bitmask 0x0fff.
-****************************************************************************/
-
-tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, int databus_width, int prg_addr_bits, int cru_addr_bits, device_t *owner, UINT32 clock, const char *shortname, const char *source)
- : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source),
- m_program_config("program", ENDIANNESS_BIG, databus_width, prg_addr_bits),
- m_io_config("cru", ENDIANNESS_BIG, 8, cru_addr_bits),
- m_prgspace(NULL),
- m_cru(NULL),
- m_prgaddr_mask((1<<prg_addr_bits)-1),
- m_cruaddr_mask((1<<cru_addr_bits)-1),
- m_clock_out_line(*this),
- m_wait_line(*this),
- m_holda_line(*this),
- m_iaq_line(*this),
- m_get_intlevel(*this),
- m_dbin_line(*this),
- m_external_operation(*this)
-{
-}
-
-tms99xx_device::~tms99xx_device()
-{
-}
-
-/****************************************************************************
- Constructor for TMS9900
-****************************************************************************/
-
-tms9900_device::tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms99xx_device(mconfig, TMS9900, "TMS9900", tag, 16, 16, 12, owner, clock, "tms9900", __FILE__)
-{
-}
-
-enum
-{
- TMS9900_PC=0, TMS9900_WP, TMS9900_STATUS, TMS9900_IR,
- TMS9900_R0, TMS9900_R1, TMS9900_R2, TMS9900_R3,
- TMS9900_R4, TMS9900_R5, TMS9900_R6, TMS9900_R7,
- TMS9900_R8, TMS9900_R9, TMS9900_R10, TMS9900_R11,
- TMS9900_R12, TMS9900_R13, TMS9900_R14, TMS9900_R15
-};
-
-void tms99xx_device::device_start()
-{
- // TODO: Restore state save feature
- resolve_lines();
- m_prgspace = &space(AS_PROGRAM);
- m_cru = &space(AS_IO);
-
- // set our instruction counter
- m_icountptr = &m_icount;
-
- m_state_any = 0;
- PC = 0;
- m_hold_state = false;
-
- // add the states for the debugger
- for (int i=0; i < 20; i++)
- {
- // callimport = need to use the state_import method to write to the state variable
- // callexport = need to use the state_export method to read the state variable
- state_add(i, s_statename[i], m_state_any).callimport().callexport().formatstr("%04X");
- }
- state_add(STATE_GENPC, "curpc", PC).formatstr("%4s").noshow();
- state_add(STATE_GENFLAGS, "status", m_state_any).callimport().callexport().formatstr("%16s").noshow();
-
- build_command_lookup_table();
-
- m_program = NULL;
-}
-
-void tms99xx_device::device_stop()
-{
- int k = 0;
- if (TRACE_SETUP) logerror("tms99xx: Deleting lookup tables\n");
- while (m_lotables[k]!=NULL) delete[] m_lotables[k++];
-}
-
-/*
- External connections
-*/
-void tms99xx_device::resolve_lines()
-{
- // Resolve our external connections
- m_external_operation.resolve();
- m_get_intlevel.resolve();
- m_iaq_line.resolve();
- m_clock_out_line.resolve();
- m_wait_line.resolve();
- m_holda_line.resolve();
- m_dbin_line.resolve(); // we need this for the set_address operation
-}
-
-/*
- TMS9900 hard reset
- The device reset is just the emulator's trigger for the reset procedure
- which is invoked via the main loop.
-*/
-void tms99xx_device::device_reset()
-{
- if (TRACE_EMU) logerror("tms99xx: Device reset by emulator\n");
- m_reset = true;
- m_check_ready = false;
- m_wait_state = false;
- ST = 0;
- m_irq_state = false;
-}
-
-const char* tms99xx_device::s_statename[20] =
-{
- "PC", "WP", "ST", "IR",
- "R0", "R1", "R2", "R3",
- "R4", "R5", "R6", "R7",
- "R8", "R9", "R10","R11",
- "R12","R13","R14","R15"
-};
-
-/*
- Write the contents of a register by external input (debugger)
-*/
-void tms99xx_device::state_import(const device_state_entry &entry)
-{
- int index = entry.index();
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- // no action here; we do not allow import, as the flags are all
- // bits of the STATUS register
- break;
- case TMS9900_PC:
- PC = (UINT16)(m_state_any & m_prgaddr_mask & 0xfffe);
- break;
- case TMS9900_WP:
- WP = (UINT16)(m_state_any & m_prgaddr_mask & 0xfffe);
- break;
- case TMS9900_STATUS:
- ST = (UINT16)m_state_any;
- break;
- case TMS9900_IR:
- IR = (UINT16)m_state_any;
- break;
- default:
- // Workspace registers
- if (index <= TMS9900_R15)
- write_workspace_register_debug(index-TMS9900_R0, (UINT16)m_state_any);
- break;
- }
-}
-
-/*
- Reads the contents of a register for display in the debugger.
-*/
-void tms99xx_device::state_export(const device_state_entry &entry)
-{
- int index = entry.index();
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- m_state_any = ST;
- break;
- case TMS9900_PC:
- m_state_any = PC;
- break;
- case TMS9900_WP:
- m_state_any = WP;
- break;
- case TMS9900_STATUS:
- m_state_any = ST;
- break;
- case TMS9900_IR:
- m_state_any = IR;
- break;
- default:
- // Workspace registers
- if (index <= TMS9900_R15)
- m_state_any = read_workspace_register_debug(index-TMS9900_R0);
- break;
- }
-}
-
-/*
- state_string_export - export state as a string for the debugger
-*/
-void tms99xx_device::state_string_export(const device_state_entry &entry, std::string &str)
-{
- static const char *statestr = "LAECOPX-----IIII";
- char flags[17];
- memset(flags, 0x00, ARRAY_LENGTH(flags));
- UINT16 val = 0x8000;
- if (entry.index()==STATE_GENFLAGS)
- {
- for (int i=0; i < 16; i++)
- {
- flags[i] = ((val & ST)!=0)? statestr[i] : '.';
- val = (val >> 1) & 0x7fff;
- }
- }
- str.assign(flags);
-}
-
-/**************************************************************************/
-
-UINT16 tms99xx_device::read_workspace_register_debug(int reg)
-{
- int temp = m_icount;
- m_prgspace->set_debugger_access(true);
- UINT16 value = m_prgspace->read_word((WP+(reg<<1)) & m_prgaddr_mask & 0xfffe);
- m_prgspace->set_debugger_access(false);
- m_icount = temp;
- return value;
-}
-
-void tms99xx_device::write_workspace_register_debug(int reg, UINT16 data)
-{
- int temp = m_icount;
- m_prgspace->set_debugger_access(true);
- m_prgspace->write_word((WP+(reg<<1)) & m_prgaddr_mask & 0xfffe, data);
- m_prgspace->set_debugger_access(false);
- m_icount = temp;
-}
-
-const address_space_config *tms99xx_device::memory_space_config(address_spacenum spacenum) const
-{
- switch (spacenum)
- {
- case AS_PROGRAM:
- return &m_program_config;
-
- case AS_IO:
- return &m_io_config;
-
- default:
- return NULL;
- }
-}
-
-/**************************************************************************
- Microprograms for the CPU instructions
-
- The actions which are specific to the respective instruction are
- invoked by repeated calls of ALU_xxx; each call increases a state
- variable so that on the next call, the next part can be processed.
- This saves us a lot of additional functions.
-**************************************************************************/
-
-/*
- Define the indices for the micro-operation table. This is done for the sake
- of a simpler microprogram definition as an UINT8[].
-*/
-enum
-{
- IAQ = 0,
- MEMORY_READ,
- MEMORY_WRITE,
- REG_READ,
- REG_WRITE,
- CRU_INPUT,
- CRU_OUTPUT,
- DATA_DERIVE,
- RET,
- ABORT,
- END,
-
- ALU_NOP,
- ALU_CLR,
- ALU_SETADDR,
- ALU_ADDONE,
- ALU_SETADDR_ADDONE,
- ALU_PCADDR_ADVANCE,
- ALU_SOURCE,
- ALU_ADDREG,
- ALU_IMM,
- ALU_REG,
- ALU_F1,
- ALU_COMP,
- ALU_F3,
- ALU_MPY,
- ALU_DIV,
- ALU_XOP,
- ALU_CLR_SWPB,
- ALU_ABS,
- ALU_X,
- ALU_B,
- ALU_BLWP,
- ALU_LDCR,
- ALU_STCR,
- ALU_SBZ_SBO,
- ALU_TB,
- ALU_JMP,
- ALU_SHIFT,
- ALU_AI_ORI,
- ALU_CI,
- ALU_LI,
- ALU_LWPI,
- ALU_LIMI,
- ALU_STWP_STST,
- ALU_EXT,
- ALU_RTWP,
- ALU_INT
-};
-
-
-#define MICROPROGRAM(_MP) \
- static const UINT8 _MP[] =
-
-/*
- This is a kind of subroutine with 6 variants. Might be done in countless
- better ways, but will suffice for now. Each variant has at most 8 steps
- RET will return to the caller.
- The padding simplifies the calculation of the start address: We just
- take the Ts field as an index. In the last two cases we add an offset of 8
- if we have an indexed (resp. a byte) operation.
-*/
-MICROPROGRAM(data_derivation)
-{
- REG_READ, RET, 0, 0, 0, 0, 0, 0, // Rx (00)
- 0, 0, 0, 0, 0, 0, 0, 0,
- REG_READ, ALU_SETADDR, MEMORY_READ, RET, 0, 0, 0, 0, // *Rx (01)
- 0, 0, 0, 0, 0, 0, 0, 0,
- ALU_CLR, ALU_PCADDR_ADVANCE, MEMORY_READ, ALU_ADDREG, MEMORY_READ, RET, 0, 0, // @sym (10)
- REG_READ, ALU_PCADDR_ADVANCE, MEMORY_READ, ALU_ADDREG, MEMORY_READ, RET, 0, 0, // @sym(Rx) (10)
- REG_READ, ALU_SETADDR_ADDONE, ALU_ADDONE, REG_WRITE, MEMORY_READ, RET, 0, 0, // *Rx+ (word) (11)
- REG_READ, ALU_SETADDR_ADDONE, REG_WRITE, MEMORY_READ, RET, 0, 0, 0 // *Rx+ (byte) (11)
-};
-
-MICROPROGRAM(f1_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_SOURCE, // Store the word
- DATA_DERIVE,
- ALU_F1,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(comp_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_SOURCE,
- DATA_DERIVE,
- ALU_COMP,
- ALU_NOP, // Compare operations do not write back any data
- END
-};
-
-MICROPROGRAM(f3_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_F3,
- MEMORY_READ, // We have to distinguish this from the C/CB microprogram above
- ALU_F3,
- ALU_NOP, // Compare operations do not write back any data
- END
-};
-
-MICROPROGRAM(xor_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_F3,
- MEMORY_READ,
- ALU_F3,
- MEMORY_WRITE, // XOR again must write back data, cannot reuse f3_mp
- END
-};
-
-MICROPROGRAM(mult_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_MPY, // Save the value; put register number in m_regnumber
- MEMORY_READ,
- ALU_MPY, // 18 cycles for multiplication
- MEMORY_WRITE, // Write the high word
- ALU_MPY, // Get low word, increase m_address
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(div_mp)
-{
- ALU_NOP,
- DATA_DERIVE, // Get divisor
- ALU_DIV, // 0 Store divisor and get register number
- MEMORY_READ, // Read register
- ALU_DIV, // 1 Check overflow, increase address (or abort here)
- ABORT,
- MEMORY_READ, // Read subsequent word (if reg=15 this is behind the workspace)
- ALU_DIV, // 2 Calculate quotient (takes variable amount of cycles; at least 32 machine cycles), set register number
- MEMORY_WRITE, // Write quotient into register
- ALU_DIV, // 3 Get remainder
- MEMORY_WRITE, // Write remainder
- END
-};
-
-MICROPROGRAM(xop_mp)
-{
- ALU_NOP,
- DATA_DERIVE, // Get argument
- ALU_XOP, // 0 Save the address of the source operand, set address = 0x0040 + xopNr*4, 6 cycles
- MEMORY_READ, // Read the new WP
- ALU_XOP, // 1 Save old WP, set new WP, get the source operand address
- MEMORY_WRITE, // Write the address of the source operand into the new R11
- ALU_XOP, // 2
- MEMORY_WRITE, // Write the ST into the new R15
- ALU_XOP, // 3
- MEMORY_WRITE, // Write the PC into the new R14
- ALU_XOP, // 4
- MEMORY_WRITE, // Write the WP into the new R13
- ALU_XOP, // 5 Set the X bit in the ST
- MEMORY_READ, // Read the new PC
- ALU_XOP, // 6 Set the new PC
- END
-};
-
-MICROPROGRAM(clr_swpb_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_CLR_SWPB,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(abs_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_ABS, // two cycles
- MEMORY_WRITE, // skipped when ABS is not performed
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(x_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_X,
- END
-};
-
-MICROPROGRAM(b_mp) // Branch
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_B,
- END
-};
-
-MICROPROGRAM(bl_mp) // Branch and Link
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_B,
- ALU_NOP,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(blwp_mp) // Branch and Load WP
-{
- ALU_NOP,
- DATA_DERIVE, // Get argument
- ALU_BLWP, // 0 Save old WP, set new WP, save position
- ALU_NOP,
- MEMORY_WRITE, // write ST to R15
- ALU_BLWP, // 1
- MEMORY_WRITE, // write PC to R14
- ALU_BLWP, // 2
- MEMORY_WRITE, // write WP to R13
- ALU_BLWP, // 3 Get saved position
- MEMORY_READ, // Read new PC
- ALU_BLWP, // 4 Set new PC
- END
-};
-
-MICROPROGRAM(ldcr_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_SOURCE,
- ALU_NOP,
- ALU_LDCR,
- ALU_NOP,
- MEMORY_READ,
- ALU_LDCR,
- CRU_OUTPUT,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(stcr_mp)
-{
- ALU_NOP,
- DATA_DERIVE,
- ALU_SOURCE, // Store address and value
- ALU_STCR, // 0 Set register_number = 12; 0 cycles (already done before)
- MEMORY_READ,
- ALU_STCR, // 1 Prepare CRU access
- ALU_NOP,
- CRU_INPUT,
- ALU_STCR, // 2 Create result; Cycles = 5 + (8-#C-1) or + (16-#C)
- ALU_NOP,
- ALU_NOP,
- ALU_NOP,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(sbz_sbo_mp)
-{
- ALU_SBZ_SBO,
- ALU_NOP,
- MEMORY_READ,
- ALU_SBZ_SBO,
- CRU_OUTPUT,
- END
-};
-
-MICROPROGRAM(tb_mp)
-{
- ALU_TB,
- MEMORY_READ,
- ALU_TB,
- CRU_INPUT,
- ALU_TB,
- END
-};
-
-MICROPROGRAM(jmp_mp)
-{
- ALU_NOP,
- ALU_JMP,
- ALU_JMP,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(shift_mp)
-{
- ALU_SHIFT,
- MEMORY_READ,
- ALU_SHIFT, // 2 cycles if count != 0, else 4
- MEMORY_READ, // skipped if count != 0
- ALU_SHIFT, // skipped if count != 0 (4 cycles)
- ALU_SHIFT,
- MEMORY_WRITE,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(ai_ori_mp)
-{
- ALU_REG,
- MEMORY_READ,
- ALU_IMM,
- MEMORY_READ,
- ALU_AI_ORI,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(ci_mp)
-{
- ALU_REG,
- MEMORY_READ,
- ALU_IMM,
- MEMORY_READ,
- ALU_CI,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(li_mp)
-{
- ALU_IMM,
- MEMORY_READ,
- ALU_LI, // sets status bits
- ALU_REG, // set register number
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(lwpi_mp)
-{
- ALU_IMM,
- MEMORY_READ,
- ALU_NOP,
- ALU_LWPI, // sets WP
- END
-};
-
-MICROPROGRAM(limi_mp)
-{
- ALU_IMM,
- MEMORY_READ,
- ALU_NOP,
- ALU_LIMI, // sets interrupt mask in ST
- ALU_NOP,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(stwp_stst_mp)
-{
- ALU_STWP_STST,
- ALU_REG,
- MEMORY_WRITE,
- END
-};
-
-MICROPROGRAM(external_mp)
-{
- ALU_NOP,
- ALU_NOP,
- ALU_EXT,
- ALU_NOP,
- ALU_NOP,
- END
-};
-
-MICROPROGRAM(rtwp_mp)
-{
- ALU_NOP,
- ALU_RTWP,
- MEMORY_READ,
- ALU_RTWP, // no cycles
- MEMORY_READ,
- ALU_RTWP, // no cycles
- MEMORY_READ,
- ALU_RTWP,
- END
-};
-
-MICROPROGRAM(int_mp)
-{
- ALU_NOP,
- ALU_INT, // 0 Set address = 0
- MEMORY_READ,
- ALU_INT, // 1 Save old WP, set new WP, save position
- MEMORY_WRITE, // write ST to R15
- ALU_INT, // 2
- MEMORY_WRITE, // write PC to R14
- ALU_INT, // 3
- MEMORY_WRITE, // write WP to R13
- ALU_INT, // 4 Get saved position
- MEMORY_READ, // Read new PC
- ALU_INT, // 5 Set new PC
- END
-};
-
-const tms99xx_device::ophandler tms99xx_device::s_microoperation[] =
-{
- &tms99xx_device::acquire_instruction,
- &tms99xx_device::mem_read,
- &tms99xx_device::mem_write,
- &tms99xx_device::register_read,
- &tms99xx_device::register_write,
- &tms99xx_device::cru_input_operation,
- &tms99xx_device::cru_output_operation,
- &tms99xx_device::data_derivation_subprogram,
- &tms99xx_device::return_from_subprogram,
- &tms99xx_device::abort_operation,
- &tms99xx_device::command_completed,
-
- &tms99xx_device::alu_nop,
- &tms99xx_device::alu_clear,
- &tms99xx_device::alu_setaddr,
- &tms99xx_device::alu_addone,
- &tms99xx_device::alu_setaddr_addone,
- &tms99xx_device::alu_pcaddr_advance,
- &tms99xx_device::alu_source,
- &tms99xx_device::alu_add_register,
- &tms99xx_device::alu_imm,
- &tms99xx_device::alu_reg,
-
- &tms99xx_device::alu_f1,
- &tms99xx_device::alu_comp,
- &tms99xx_device::alu_f3,
- &tms99xx_device::alu_multiply,
- &tms99xx_device::alu_divide,
- &tms99xx_device::alu_xop,
- &tms99xx_device::alu_clr_swpb,
- &tms99xx_device::alu_abs,
- &tms99xx_device::alu_x,
- &tms99xx_device::alu_b,
- &tms99xx_device::alu_blwp,
- &tms99xx_device::alu_ldcr,
- &tms99xx_device::alu_stcr,
- &tms99xx_device::alu_sbz_sbo,
- &tms99xx_device::alu_tb,
- &tms99xx_device::alu_jmp,
- &tms99xx_device::alu_shift,
- &tms99xx_device::alu_ai_ori,
- &tms99xx_device::alu_ci,
- &tms99xx_device::alu_li,
- &tms99xx_device::alu_lwpi,
- &tms99xx_device::alu_limi,
- &tms99xx_device::alu_stwp_stst,
- &tms99xx_device::alu_external,
- &tms99xx_device::alu_rtwp,
- &tms99xx_device::alu_int
-};
-
-/*****************************************************************************
- CPU instructions
-*****************************************************************************/
-
-/*
- Available instructions
-*/
-enum
-{
- ILL=0, A, AB, ABS, AI, ANDI, B, BL, BLWP, C,
- CB, CI, CKOF, CKON, CLR, COC, CZC, DEC, DECT, DIV,
- IDLE, INC, INCT, INV, JEQ, JGT, JH, JHE, JL, JLE,
- JLT, JMP, JNC, JNE, JNO, JOC, JOP, LDCR, LI, LIMI,
- LREX, LWPI, MOV, MOVB, MPY, NEG, ORI, RSET, RTWP, S,
- SB, SBO, SBZ, SETO, SLA, SOC, SOCB, SRA, SRC, SRL,
- STCR, STST, STWP, SWPB, SZC, SZCB, TB, X, XOP, XOR,
- INTR
-};
-
-/*
- Formats:
-
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- ----+------------------------------------------------+
- 1 | Opcode | B | Td | RegNr | Ts | RegNr |
- +--------+---+----+------------+----+------------+
- 2 | Opcode | Displacement |
- +-----------------------+------------------------+
- 3 | Opcode | RegNr | Ts | RegNr |
- +-----------------+------------+----+------------+
- 4 | Opcode | Count | Ts | RegNr |
- +-----------------+------------+----+------------+
- 5 | Opcode | Count | RegNr |
- +-----------------------+-----------+------------+
- 6 | Opcode | Ts | RegNr |
- +------------------------------+----+------------+
- 7 | Opcode |0| 0| 0| 0| 0 |
- +---------------------------------+-+--+--+--+---+
- 8 | Opcode |0| RegNr |
- +---------------------------------+-+------------+
- 9 | Opcode | Reg/Nr | Ts | RegNr |
- +-----------------+------------+----+------------+
-*/
-
-/*
- Defines the number of bits from the left which are significant for the
- command in the respective format.
-*/
-static const int format_mask_len[] =
-{
- 0, 4, 8, 6, 6, 8, 10, 16, 12, 6
-};
-
-const tms99xx_device::tms_instruction tms99xx_device::s_command[] =
-{
- // Opcode, ID, format, microprg
- { 0x0200, LI, 8, li_mp },
- { 0x0220, AI, 8, ai_ori_mp },
- { 0x0240, ANDI, 8, ai_ori_mp },
- { 0x0260, ORI, 8, ai_ori_mp },
- { 0x0280, CI, 8, ci_mp },
- { 0x02a0, STWP, 8, stwp_stst_mp },
- { 0x02c0, STST, 8, stwp_stst_mp },
- { 0x02e0, LWPI, 8, lwpi_mp },
- { 0x0300, LIMI, 8, limi_mp },
- { 0x0340, IDLE, 7, external_mp },
- { 0x0360, RSET, 7, external_mp },
- { 0x0380, RTWP, 7, rtwp_mp },
- { 0x03a0, CKON, 7, external_mp },
- { 0x03c0, CKOF, 7, external_mp },
- { 0x03e0, LREX, 7, external_mp },
- { 0x0400, BLWP, 6, blwp_mp },
- { 0x0440, B, 6, b_mp },
- { 0x0480, X, 6, x_mp },
- { 0x04c0, CLR, 6, clr_swpb_mp },
- { 0x0500, NEG, 6, clr_swpb_mp },
- { 0x0540, INV, 6, clr_swpb_mp },
- { 0x0580, INC, 6, clr_swpb_mp },
- { 0x05c0, INCT, 6, clr_swpb_mp },
- { 0x0600, DEC, 6, clr_swpb_mp },
- { 0x0640, DECT, 6, clr_swpb_mp },
- { 0x0680, BL, 6, bl_mp },
- { 0x06c0, SWPB, 6, clr_swpb_mp },
- { 0x0700, SETO, 6, clr_swpb_mp },
- { 0x0740, ABS, 6, abs_mp },
- { 0x0800, SRA, 5, shift_mp },
- { 0x0900, SRL, 5, shift_mp },
- { 0x0a00, SLA, 5, shift_mp },
- { 0x0b00, SRC, 5, shift_mp },
- { 0x1000, JMP, 2, jmp_mp },
- { 0x1100, JLT, 2, jmp_mp },
- { 0x1200, JLE, 2, jmp_mp },
- { 0x1300, JEQ, 2, jmp_mp },
- { 0x1400, JHE, 2, jmp_mp },
- { 0x1500, JGT, 2, jmp_mp },
- { 0x1600, JNE, 2, jmp_mp },
- { 0x1700, JNC, 2, jmp_mp },
- { 0x1800, JOC, 2, jmp_mp },
- { 0x1900, JNO, 2, jmp_mp },
- { 0x1a00, JL, 2, jmp_mp },
- { 0x1b00, JH, 2, jmp_mp },
- { 0x1c00, JOP, 2, jmp_mp },
- { 0x1d00, SBO, 2, sbz_sbo_mp },
- { 0x1e00, SBZ, 2, sbz_sbo_mp },
- { 0x1f00, TB, 2, tb_mp },
- { 0x2000, COC, 3, f3_mp },
- { 0x2400, CZC, 3, f3_mp },
- { 0x2800, XOR, 3, xor_mp },
- { 0x2c00, XOP, 3, xop_mp },
- { 0x3000, LDCR, 4, ldcr_mp },
- { 0x3400, STCR, 4, stcr_mp },
- { 0x3800, MPY, 9, mult_mp },
- { 0x3c00, DIV, 9, div_mp },
- { 0x4000, SZC, 1, f1_mp },
- { 0x5000, SZCB, 1, f1_mp },
- { 0x6000, S, 1, f1_mp },
- { 0x7000, SB, 1, f1_mp },
- { 0x8000, C, 1, comp_mp },
- { 0x9000, CB, 1, comp_mp },
- { 0xa000, A, 1, f1_mp },
- { 0xb000, AB, 1, f1_mp },
- { 0xc000, MOV, 1, f1_mp },
- { 0xd000, MOVB, 1, f1_mp },
- { 0xe000, SOC, 1, f1_mp },
- { 0xf000, SOCB, 1, f1_mp }
-};
-
-/*
- Create a B-tree for looking up the commands. Each node can carry up to
- 16 entries, indexed by 4 consecutive bits in the opcode.
-
- Works as follows:
-
- Opcode = 0201 (Load immediate value into register 1)
- Opcode = 0284 (Compare immediate value with register 4)
-
- Table: [ Table0, table1, table2, ... tableF ]
- |
- +-------+
- v
- table0: [ table00, table01, table02, ... table0f ]
- |
- +-------------------------+
- v
- table02: [ table020, table021, ... table028, ... table02f ]
- | | |
- v v v
- Entry NULL Entry
- for LI for CI
-
- For each level in the tree, four more bits are compared. The search
- terminates when the number of compared bits is equal or higher than
- the number of significant bits of the format of this opcode. The entry
- points to the respective line in s_command.
-
- This way we can decode all format 1 commands by a single pass (including the
- most frequent command MOV), and almost all commands by less than four passes.
-
- The disadvantage is that we have to build these tables from the opcode
- list at runtime, and many positions are empty. But we do not need more
- than 20 tables for the TMS command set.
-*/
-void tms99xx_device::build_command_lookup_table()
-{
- int i = 0;
- int cmdindex = 0;
- int bitcount;
- const tms_instruction *inst;
- UINT16 opcode;
- int k = 0;
-
- m_command_lookup_table = new lookup_entry[16];
- // We use lotables as a list of allocated tables - to be able to delete them
- // at the end.
- m_lotables[k++] = m_command_lookup_table;
-
- lookup_entry* table = m_command_lookup_table;
- for (int j=0; j < 16; j++)
- {
- table[j].entry = NULL;
- table[j].next_digit = NULL;
- }
-
- do
- {
- inst = &s_command[i];
- table = m_command_lookup_table;
- if (TRACE_SETUP) logerror("tms99xx: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
- bitcount = 4;
- opcode = inst->opcode;
- cmdindex = (opcode>>12) & 0x000f;
-
- while (bitcount < format_mask_len[inst->format])
- {
- // Descend
- if (table[cmdindex].next_digit == NULL)
- {
- if (TRACE_SETUP) logerror("tms99xx: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
- table[cmdindex].next_digit = new lookup_entry[16];
- m_lotables[k++] = table[cmdindex].next_digit;
- for (int j=0; j < 16; j++)
- {
- table[cmdindex].next_digit[j].next_digit = NULL;
- table[cmdindex].next_digit[j].entry = NULL;
- }
- }
- else
- {
- if (TRACE_SETUP) logerror("tms99xx: found a table at bitcount=%d\n", bitcount);
- }
-
- table = table[cmdindex].next_digit;
-
- bitcount = bitcount+4;
- opcode <<= 4;
- cmdindex = (opcode>>12) & 0x000f;
- if (TRACE_SETUP) logerror("tms99xx: next index=%x\n", cmdindex);
- }
-
- if (TRACE_SETUP) logerror("tms99xx: bitcount=%d\n", bitcount);
- // We are at the target level
- // Need to fill in the same entry for all values in the bitcount
- // (if a command needs 10 bits we have to copy it four
- // times for all combinations with 12 bits)
- for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++)
- {
- if (TRACE_SETUP) logerror("tms99xx: opcode=%04x at position %d\n", inst->opcode, cmdindex+j);
- table[cmdindex+j].entry = inst;
- }
-
- i++;
- } while (inst->opcode != 0xf000);
-
- m_lotables[k++] = NULL;
- if (TRACE_SETUP) logerror("tms99xx: Allocated %d tables\n", k);
-}
-
-/*
- Main execution loop
-
- For each invocation of execute_run, a number of loop iterations has been
- calculated before (m_icount). Each loop iteration is one clock cycle.
- The loop must be executed for the number of times that corresponds to the
- time until the next timer event.
-
- In this implementation, each loop iteration also causes the clock line to
- pulse once. External devices may use this pulse to decrement counters
- which control the READY line.
-
- Machine cycles to clock input:
-
- +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
- | | | | | | | | | | | | | | | | | | clock (1 of 4 phases)
- +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +
- |-------|-------|-------|-------|---- cycles (2 clock pulses each)
-
- Wait states only have effect for memory operations. They are processed as
- follows:
-
- 1) The CPU sets the address bus for reading. If READY is low, the CPU
- waits for the next clock tick repeatedly until READY is high again.
- When this is the case, the data bus is sampled on the next clock tick
- and the read operation is complete.
-
- As we do not have a split-phase read operation in this emulation
- we actually read the data bus instantly but wait for the READY line to
- be high again.
-
- 2) The CPU sets the address bus for writing. In the same moment, the data
- bus is loaded with the word to be written. On the next clock tick,
- the CPU checks the READY line and waits until it is high. When READY
- is high at a clock tick, the operation is complete on the next clock tick.
-*/
-void tms99xx_device::execute_run()
-{
- if (m_reset) service_interrupt();
-
- if (TRACE_EMU) logerror("tms99xx: calling execute_run for %d cycles\n", m_icount);
- do
- {
- // Only when last instruction has completed
- if (m_program == NULL)
- {
- if (m_load_state)
- {
- logerror("tms99xx: LOAD interrupt\n");
- m_irq_level = LOAD_INT;
- m_irq_state = false;
- service_interrupt();
- }
- else
- {
- // Interrupts are serviced when
- // - an interrupt condition is signaled over INTREQ and
- // - the level indicated by IC0-IC3 is lower than the interrupt mask value and
- // - the previous instruction is not an XOP or BLWP
- if (m_irq_state && (m_irq_level <= (ST & 0x000f)) && (m_command != XOP && m_command != BLWP))
- service_interrupt();
- }
- }
-
- if (m_program == NULL && m_idle_state)
- {
- if (TRACE_WAIT) logerror("tms99xx: idle state\n");
- pulse_clock(1);
- if (!m_external_operation.isnull())
- {
- m_external_operation(IDLE_OP, 0, 0xff);
- m_external_operation(IDLE_OP, 1, 0xff);
- }
- }
- else
- {
- // Handle HOLD
- // A HOLD request is signalled through the input line HOLD.
- // The hold state will be entered with the next non-memory access cycle.
- if (m_hold_state &&
- (m_program==NULL ||
- (m_program[MPC] != IAQ &&
- m_program[MPC] != MEMORY_READ && m_program[MPC] != MEMORY_WRITE &&
- m_program[MPC] != REG_READ && m_program[MPC] != REG_WRITE)))
- {
- if (TRACE_WAIT) logerror("tms99xx: hold\n");
- if (!m_hold_acknowledged) acknowledge_hold();
- pulse_clock(1);
- }
- else
- {
- // Normal operation
- if (m_check_ready && m_ready == false)
- {
- // We are in a wait state
- set_wait_state(true);
- if (TRACE_WAIT) logerror("tms99xx: wait\n");
- // The clock output should be used to change the state of an outer
- // device which operates the READY line
- pulse_clock(1);
- }
- else
- {
- set_wait_state(false);
- m_check_ready = false;
-
- if (m_program==NULL) m_op = IAQ;
- else
- {
- m_op = m_program[MPC];
- }
- if (TRACE_MICRO) logerror("tms99xx: MPC = %d, m_op = %d\n", MPC, m_op);
- // Call the operation of the microprogram
- (this->*s_microoperation[m_op])();
- // If we have multiple passes (as in the TMS9980)
- m_pass--;
- if (m_pass<=0)
- {
- m_pass = 1;
- MPC++;
- m_mem_phase = 1;
- if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE);
- }
- }
- }
- }
- } while (m_icount>0 && !m_reset);
- if (TRACE_EMU) logerror("tms99xx: cycles expired; will return soon.\n");
-}
-
-/**************************************************************************/
-
-/*
- Interrupt input
-*/
-void tms99xx_device::execute_set_input(int irqline, int state)
-{
- if (irqline==INT_9900_RESET && state==ASSERT_LINE)
- {
- m_reset = true;
- }
- else
- {
- if (irqline == INT_9900_LOAD)
- {
- m_load_state = (state==ASSERT_LINE);
- m_irq_level = -1;
- m_reset = false;
- }
- else
- {
- m_irq_state = (state==ASSERT_LINE);
- if (state==ASSERT_LINE)
- {
- m_irq_level = get_intlevel(state);
- if (TRACE_INT) logerror("tms99xx: /INT asserted, level=%d, ST=%04x\n", m_irq_level, ST);
- }
- else
- {
- if (TRACE_INT) logerror("tms99xx: /INT cleared\n");
- }
- }
- }
-}
-
-/*
- This can be overloaded by variants of TMS99xx.
-*/
-int tms99xx_device::get_intlevel(int state)
-{
- if (!m_get_intlevel.isnull()) return m_get_intlevel(0);
- return 0;
-}
-
-void tms99xx_device::service_interrupt()
-{
- m_program = int_mp;
- m_command = INTR;
- m_idle_state = false;
- if (!m_external_operation.isnull()) m_external_operation(IDLE_OP, 0, 0xff);
-
- m_state = 0;
-
- if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
-
- // If reset, we just start with execution, otherwise we put the MPC
- // on the first microinstruction, which also means that the main loop shall
- // leave it where it is. So we pretend we have another pass to do.
- m_pass = m_reset? 1 : 2;
-
- if (m_reset)
- {
- m_irq_level = RESET_INT;
-
- m_ready_bufd = true;
- m_ready = true;
- m_load_state = false;
- m_hold_state = false;
- m_hold_acknowledged = false;
- m_wait_state = false;
- IR = 0;
- ST = 0;
- m_mem_phase = 1;
-
- m_reset = false;
- }
- if (TRACE_INT)
- {
- switch (m_irq_level)
- {
- case RESET_INT: logerror("tms99xx: **** triggered a RESET interrupt\n"); break;
- case LOAD_INT: logerror("tms99xx: **** triggered a LOAD (NMI) interrupt\n"); break;
- default: logerror("tms99xx: ** triggered an interrupt on level %d\n", m_irq_level); break;
- }
- }
-
- MPC = 0;
- m_first_cycle = m_icount;
-}
-
-/*
- Issue a pulse on the clock line.
-*/
-void tms99xx_device::pulse_clock(int count)
-{
- for (int i=0; i < count; i++)
- {
- if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE);
- m_ready = m_ready_bufd; // get the latched READY state
- if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE);
- m_icount--; // This is the only location where we count down the cycles.
- if (TRACE_CLOCK)
- {
- if (m_check_ready) logerror("tms99xx: pulse_clock, READY=%d\n", m_ready? 1:0);
- else logerror("tms99xx: pulse_clock\n");
- }
- }
-}
-
-/*
- Enter the hold state.
-*/
-void tms99xx_device::set_hold(int state)
-{
- m_hold_state = (state==ASSERT_LINE);
- if (!m_hold_state)
- {
- m_hold_acknowledged = false;
- if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE);
- }
-}
-
-/*
- Acknowledge the HOLD request.
-*/
-inline void tms99xx_device::acknowledge_hold()
-{
- m_hold_acknowledged = true;
- if (!m_holda_line.isnull()) m_holda_line(ASSERT_LINE);
-}
-
-/*
- Signal READY to the CPU. When cleared, the CPU enters wait states. This
- becomes effective on a clock pulse.
-*/
-void tms99xx_device::set_ready(int state)
-{
- m_ready_bufd = (state==ASSERT_LINE);
-}
-
-void tms99xx_device::abort_operation()
-{
- command_completed();
-}
-
-/*
- Enter or leave the wait state. We only operate the WAIT line when there is a change.
-*/
-inline void tms99xx_device::set_wait_state(bool state)
-{
- if (m_wait_state != state)
- if (!m_wait_line.isnull()) m_wait_line(state? ASSERT_LINE : CLEAR_LINE);
- m_wait_state = state;
-}
-
-/*
- Acquire the next word as an instruction. The program counter advances by
- one word.
-*/
-void tms99xx_device::decode(UINT16 inst)
-{
- int index = 0;
- lookup_entry* table = m_command_lookup_table;
- UINT16 opcode = inst;
- bool complete = false;
- const tms_instruction *decoded;
-
- m_state = 0;
- IR = inst;
- m_get_destination = false;
- m_byteop = false;
-
- while (!complete)
- {
- index = (opcode >> 12) & 0x000f;
- if (TRACE_MICRO) logerror("tms99xx: Check next hex digit of instruction %x\n", index);
- if (table[index].next_digit != NULL)
- {
- table = table[index].next_digit;
- opcode = opcode << 4;
- }
- else complete = true;
- }
- decoded = table[index].entry;
- if (decoded == NULL)
- {
- // not found
- logerror("tms99xx: Illegal opcode %04x\n", inst);
- IR = 0;
- // This will cause another instruction acquisition in the next machine cycle
- // with an asserted IAQ line (can be used to indicate this illegal opcode detection).
- m_program = NULL;
- }
- else
- {
- m_program = decoded->prog;
- MPC = -1;
- m_command = decoded->id;
- if (TRACE_MICRO) logerror("tms99xx: Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded->opcode);
- // Byte operations are either format 1 with the byte flag set
- // or format 4 (CRU multi bit operations) with 1-8 bits to transfer.
- m_byteop = ((decoded->format==1 && ((IR & 0x1000)!=0))
- || (decoded->format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9)));
- }
- m_pass = 1;
-}
-
-inline bool tms99xx_device::byte_operation()
-{
- return (IR & 0x1000)!=0;
-}
-
-void tms99xx_device::acquire_instruction()
-{
- if (m_mem_phase == 1)
- {
- if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE);
- m_address = PC;
- m_first_cycle = m_icount;
- }
-
- mem_read();
-
- if (m_mem_phase == 1)
- {
- decode(m_current_value);
- if (TRACE_EXEC) logerror("tms99xx: %04x: %04x (%s)\n", PC, IR, opname[m_command]);
- debugger_instruction_hook(this, PC);
- PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
- // IAQ will be cleared in the main loop
- }
-}
-
-/*
- Memory read
- Clock cycles: 2 + W, W = number of wait states
-*/
-void tms99xx_device::mem_read()
-{
- // After set_address, any device attached to the address bus may pull down
- // READY in order to put the CPU into wait state before the read_word
- // operation will be performed
- // set_address and read_word should pass the same address as argument
- if (m_mem_phase==1)
- {
- if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
- m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe);
- m_check_ready = true;
- m_mem_phase = 2;
- m_pass = 2;
- if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (r) %04x\n", m_address);
-
- pulse_clock(1); // Concludes the first cycle
- // If READY has been found to be low, the CPU will now stay in the wait state loop
- }
- else
- {
- // Second phase (after READY was raised again)
- m_current_value = m_prgspace->read_word(m_address & m_prgaddr_mask & 0xfffe);
- pulse_clock(1);
- if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
- m_mem_phase = 1; // reset to phase 1
- if (TRACE_MEM) logerror("tms99xx: mem r %04x -> %04x\n", m_address, m_current_value);
- }
-}
-
-void tms99xx_device::mem_write()
-{
- if (m_mem_phase==1)
- {
- if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
- // When writing, the data bus is asserted immediately after the address bus
- if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (w) %04x\n", m_address);
- m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe);
- if (TRACE_MEM) logerror("tms99xx: mem w %04x <- %04x\n", m_address, m_current_value);
- m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value);
- m_check_ready = true;
- m_mem_phase = 2;
- m_pass = 2;
- pulse_clock(1);
- }
- else
- {
- // Second phase (we arrive here when the wait states are over)
- pulse_clock(1);
- }
-}
-
-void tms99xx_device::register_read()
-{
- // Need to set m_address for F1/F3 (we don't know what the data_derive did)
- if (m_mem_phase==1)
- {
- m_address = WP + (m_regnumber<<1);
- }
-
- mem_read();
-
- if (m_mem_phase==1)
- {
- m_register_contents = m_current_value;
- }
-}
-
-/*
- Memory write:
-
- Clock cycles: 2 + W, W = number of wait states
-*/
-void tms99xx_device::register_write()
-{
- // This will be called twice; m_pass is set by the embedded mem_write
- UINT16 addr_save = m_address;
- m_address = (WP + (m_regnumber<<1)) & m_prgaddr_mask & 0xfffe;
- mem_write();
- m_address = addr_save;
-}
-
-/*
- CRU support code
-
- The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address.
- Special instructions are dedicated to reading and writing one or several consecutive bits.
-
- The CRU uses the same address bus as the normal memory access. For writing,
- the CRUCLK line is pulsed, but not for reading where CRUCLK stays cleared.
- This means that each normal memory access also causes read accesses on the
- CRU side. The /MEMEN line may be used to distinguish the kinds of accesses
- as it stays cleared during CRU operations.
-
- We do not emulate this here as it seems there are no real applications of
- this side effect. Real designs must ensure that CRU read operations are
- idempotent (i.e. they must not change the state of the queried device).
-
- Read returns the number of consecutive CRU bits, with increasing CRU address
- from the least significant to the most significant bit; right-aligned
-
- There seems to be no handling of wait states during CRU operations on the
- TMS9900. The TMS9995, in contrast, respects wait states during the transmission
- of each single bit.
-
- Usage of this method:
- CRU write: First bit is at rightmost position of m_value.
-*/
-
-void tms99xx_device::cru_input_operation()
-{
- int value, value1;
- int offset, location;
-
- location = (m_cru_address >> 4) & (m_cruaddr_mask>>3);
- offset = (m_cru_address>>1) & 0x07;
-
- // Read 8 bits (containing the desired bits)
- value = m_cru->read_byte(location);
-
- if ((offset + m_count) > 8) // spans two 8 bit cluster
- {
- // Read next 8 bits
- location = (location + 1) & (m_cruaddr_mask>>3);
- value1 = m_cru->read_byte(location);
- value |= (value1 << 8);
-
- if ((offset + m_count) > 16) // spans three 8 bit cluster
- {
- // Read next 8 bits
- location = (location + 1) & (m_cruaddr_mask>>3);
- value1 = m_cru->read_byte(location);
- value |= (value1 << 16);
- }
- }
-
- // On each machine cycle (2 clocks) only one CRU bit is transmitted
- pulse_clock(m_count<<1);
-
- // Shift back the bits so that the first bit is at the rightmost place
- m_value = (value >> offset);
-
- // Mask out what we want
- m_value &= (0x0000ffff >> (16-m_count));
-}
-
-void tms99xx_device::cru_output_operation()
-{
- int value;
- int location;
- location = (m_cru_address >> 1) & m_cruaddr_mask;
- value = m_value;
-
- // Write m_count bits from cru_address
- for (int i=0; i < m_count; i++)
- {
- if (TRACE_CRU) logerror("tms99xx: CRU output operation, address %04x, value %d\n", location<<1, value & 0x01);
- m_cru->write_byte(location, (value & 0x01));
- value >>= 1;
- location = (location + 1) & m_cruaddr_mask;
- pulse_clock(2);
- }
-}
-
-void tms99xx_device::return_from_subprogram()
-{
- // Return from data derivation
- // The result should be in m_current_value
- // and the address in m_address
- m_program = m_caller;
- MPC = m_caller_MPC; // will be increased on return
-}
-
-void tms99xx_device::command_completed()
-{
- // Pseudo state at the end of the current instruction cycle sequence
- if (TRACE_CYCLES)
- {
- logerror("tms99xx: ------");
- int cycles = m_first_cycle - m_icount;
- // Avoid nonsense values due to expired and resumed main loop
- if (cycles > 0 && cycles < 10000) logerror(" %d cycles", cycles);
- logerror("\n");
- }
- m_program = NULL;
-}
-
-/*
- This is a switch to a subprogram; there is only one, the data
- derivation. In terms of cycles, it does not take any time; execution
- continues with the first instruction of the subprogram.
-*/
-void tms99xx_device::data_derivation_subprogram()
-{
- UINT16 ircopy = IR;
-
- // Save the return program and position
- m_caller = m_program;
- m_caller_MPC = MPC;
-
- // Source or destination argument?
- if (m_get_destination) ircopy >>= 6;
-
- m_regnumber = ircopy & 0x000f;
-
- m_program = (UINT8*)data_derivation;
- MPC = ircopy & 0x0030;
-
- if (((MPC == 0x0020) && (m_regnumber != 0)) // indexed
- || ((MPC == 0x0030) && m_byteop)) // byte operation
- {
- MPC += 8; // the second option
- }
- m_get_destination = true; // when we call this the second time before END it's the destination
- m_pass = 2;
-}
-
-
-/**************************************************************************
- Status bit operations
-**************************************************************************/
-
-inline void tms99xx_device::set_status_bit(int bit, bool state)
-{
- if (state) ST |= bit;
- else ST &= ~bit;
-}
-
-void tms99xx_device::set_status_parity(UINT8 value)
-{
- int count = 0;
- for (int i=0; i < 8; i++)
- {
- if ((value & 0x80)!=0) count++;
- value <<= 1;
- }
- set_status_bit(ST_OP, (count & 1)!=0);
-}
-
-inline void tms99xx_device::compare_and_set_lae(UINT16 value1, UINT16 value2)
-{
- set_status_bit(ST_EQ, value1 == value2);
- set_status_bit(ST_LH, value1 > value2);
- set_status_bit(ST_AGT, (INT16)value1 > (INT16)value2);
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x (val1=%04x, val2=%04x)\n", ST, value1, value2);
-}
-
-/**************************************************************************
- ALU operations
-**************************************************************************/
-
-void tms99xx_device::alu_nop()
-{
- // Do nothing (or nothing that is externally visible)
- pulse_clock(2);
- return;
-}
-
-void tms99xx_device::alu_source()
-{
- // Copy the current value into the source data register
- m_source_even = ((m_address & 1)==0);
- m_source_value = m_current_value;
- m_source_address = m_address;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_clear()
-{
- // Clears the register contents
- m_register_contents = 0;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_setaddr()
-{
- // Load the current value into the address register
- m_address = m_current_value;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_addone()
-{
- m_current_value++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_setaddr_addone()
-{
- // Set the address register and increase the recent value
- m_address = m_current_value;
- m_current_value++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_pcaddr_advance()
-{
- // Set PC as new read address, increase by 2
- m_address = PC;
- PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_add_register()
-{
- // Add the register contents to the current value and set as address
- m_address = m_current_value + m_register_contents;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_imm()
-{
- m_value_copy = m_current_value;
- m_address_copy = m_address;
- m_address = PC;
- PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_reg()
-{
- m_address = (WP + ((IR & 0x000f)<<1)) & m_prgaddr_mask;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_f1()
-{
- UINT32 dest_new = 0;
-
- // Save the destination value
- UINT16 prev_dest_value = m_current_value;
-
- m_destination_even = ((m_address & 1)==0); // this is the destination address; the source address has already been saved
- bool byteop = byte_operation();
-
- if (byteop)
- {
- if (!m_destination_even) m_current_value <<= 8;
- if (!m_source_even) m_source_value <<= 8;
- // We have to strip away the low byte, or byte operations may fail
- // e.g. 0x10ff + 0x0101 = 0x1200
- // or 0x2000 - 0x0101 = 0x1eff
- m_source_value &= 0xff00;
- m_current_value &= 0xff00;
- }
-
- switch (m_command)
- {
- case A:
- case AB:
- // Add the contents of the source data to the destination data
- // May exceed 0xffff (for carry check)
- dest_new = m_current_value + m_source_value;
-
- // 1000 + e000 = f000 (L)
- // c000 + c000 = 8000 (LC)
- // 7000 + 4000 = b000 (LO)
- // 2000 + f000 = 1000 (LAC)
- // c000 + b000 = 7000 (LACO)
- // 2000 + e000 = 0000 (EC)
- // 8000 + 8000 = 0000 (ECO)
-
- // When adding, a carry occurs when we exceed the 0xffff value.
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
- // If the result has a sign bit that is different from both arguments, we have an overflow
- // (i.e. getting a negative value from two positive values and vice versa)
- set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0);
- break;
-
- case S:
- case SB:
- // Subtract the contents of the source data from the destination data
- dest_new = m_current_value + ((~m_source_value) & 0xffff) + 1;
- // LAECO(P)
- // 8000 - 8000 = 0000 (EC)
- // 2000 - 8000 = a000 (LO)
- // 8000 - 2000 = 6000 (LACO)
- // 2000 - 1000 = 1000 (LAC)
- // 1000 - 2000 = f000 (L)
- // 1000 - 1000 = 0000 (EC)
- // 1000 - f000 = 2000 (LA)
- // f000 - 2000 = d000 (LC)
-
- // Subtraction means adding the 2s complement, so the carry bit
- // is set whenever adding the 2s complement exceeds ffff
- // In fact the CPU adds the one's complement, then adds a one. This
- // explains why subtracting 0 sets the carry bit.
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
-
- // If the arguments have different sign bits and the result has a
- // sign bit different from the destination value, we have an overflow
- // e.g. value1 = 0x7fff, value2 = 0xffff; value1-value2 = 0x8000
- // or value1 = 0x8000, value2 = 0x0001; value1-value2 = 0x7fff
- // value1 is the destination value
- set_status_bit(ST_OV, (m_current_value ^ m_source_value) & (m_current_value ^ dest_new) & 0x8000);
- break;
-
- case SOC:
- case SOCB:
- // OR the contents of the source data on the destination data
- dest_new = m_current_value | m_source_value;
- break;
-
- case SZC:
- case SZCB:
- // AND the one's complement of the contents of the source data on the destination data
- dest_new = m_current_value & ~m_source_value;
- break;
-
- case MOV:
- case MOVB:
- // Copy the source data to the destination data
- dest_new = m_source_value;
- break;
- }
-
- if (byteop)
- {
- set_status_parity((UINT8)(dest_new>>8));
-
- // destnew is the new value to be written (high byte); needs to be
- // merged with the existing word
- if (m_destination_even)
- m_current_value = (prev_dest_value & 0x00ff) | (dest_new & 0xff00);
- else
- m_current_value = (prev_dest_value & 0xff00) | ((dest_new >> 8) & 0x00ff);
- compare_and_set_lae((UINT16)(dest_new & 0xff00), 0);
- }
- else
- {
- m_current_value = (UINT16)(dest_new & 0xffff);
- compare_and_set_lae((UINT16)(dest_new & 0xffff), 0);
- }
-
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_comp()
-{
- m_destination_even = ((m_address & 1)==0); // this is the destination address; the source address has already been saved
- if (byte_operation())
- {
- if (!m_destination_even) m_current_value <<= 8;
- if (!m_source_even) m_source_value <<= 8;
- set_status_parity((UINT8)(m_source_value>>8));
- compare_and_set_lae(m_source_value & 0xff00, m_current_value & 0xff00);
- }
- else
- compare_and_set_lae(m_source_value, m_current_value);
-
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_f3()
-{
- switch (m_state)
- {
- case 0:
- // Get register address
- m_address = WP + ((IR >> 5) & 0x001e);
- m_source_value = m_current_value;
- break;
- case 1:
- if (m_command == COC)
- {
- set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value);
- }
- else
- {
- if (m_command == CZC)
- {
- set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value);
- }
- else
- {
- // XOR
- // The workspace register address is still in m_address
- m_current_value = (m_current_value ^ m_source_value);
- compare_and_set_lae(m_current_value, 0);
- }
- }
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST);
- break;
- }
-
- m_state++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_multiply()
-{
- UINT32 result = 0;
-
- switch (m_state)
- {
- case 0: // After data derivation
- m_source_value = m_current_value;
- m_address = ((IR >> 5) & 0x001e) + WP;
- break;
- case 1: // After reading the register (multiplier)
- if (TRACE_ALU) logerror("tms99xx: Multiply %04x by %04x\n", m_current_value, m_source_value);
- result = (m_source_value & 0x0000ffff) * (m_current_value & 0x0000ffff);
- m_current_value = (result >> 16) & 0xffff;
- m_value_copy = result & 0xffff;
- pulse_clock(34); // add 36 clock cycles (18 machine cycles); last one in main loop
- break;
- case 2: // After writing the high word to the destination register
- m_current_value = m_value_copy; // Prepare to save low word
- m_address = (m_address + 2) & m_prgaddr_mask;
- break;
- }
- pulse_clock(2);
- m_state++;
-}
-
-void tms99xx_device::alu_divide()
-{
- // Format is DIV Divisor,REG(dividend)
- UINT32 uval32;
- bool overflow = true;
- UINT16 value1;
-
- switch (m_state)
- {
- case 0:
- m_source_value = m_current_value; // store divisor
- // Set address of register
- m_address = WP + ((IR >> 5) & 0x001e);
- m_address_copy = m_address;
- break;
- case 1:
- // We have an overflow when the quotient cannot be stored in 16 bits
- // This is the case when the dividend / divisor >= 0x10000,
- // or equivalently, dividend / 0x10000 >= divisor
-
- if (m_current_value < m_source_value) // also if source=0
- {
- MPC++; // skip the abort
- overflow = false;
- }
- set_status_bit(ST_OV, overflow);
- m_value_copy = m_current_value; // Save the high word
- m_address = (m_address + 2) & m_prgaddr_mask; // Read next word
- break;
- case 2:
- // W2 is in m_current_value
- // Create full word and perform division
- uval32 = (m_value_copy << 16) | m_current_value;
-
- if (TRACE_ALU) logerror("tms99xx: Dividing %08x by %04x\n", uval32, m_source_value);
- m_current_value = uval32 / m_source_value;
- m_value_copy = uval32 % m_source_value;
-
- if (TRACE_ALU) logerror("tms99xx: Quotient %04x, remainder %04x\n", m_current_value, m_value_copy);
-
- m_address = m_address_copy;
-
- // The number of ALU cycles depends on the number of steps in
- // the division algorithm. The number of cycles is between 32 and
- // 48 (*2 for clock cycles)
- // As I don't have a description of the actual algorithm, I'll use
- // the following heuristic: We use 32 ALU cycles in general, then
- // we need as many cycles as it takes to
- // shift away the dividend. Thus, bigger dividends need more cycles.
-
- pulse_clock(62); // one pulse is at the start, one at the end
- value1 = m_value_copy & 0xffff;
-
- while (value1 != 0)
- {
- value1 = (value1 >> 1) & 0xffff;
- pulse_clock(2);
- }
- // We still have m_regnumber; this is where m_current_value will go to
- break;
- case 3:
- // Prepare to write the remainder
- m_current_value = m_value_copy;
- m_address = m_address + 2;
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x (div)\n", ST);
- break;
- }
- pulse_clock(2);
- m_state++;
-}
-
-void tms99xx_device::alu_xop()
-{
- switch (m_state)
- {
- case 0:
- // We have the effective address of the source operand in m_address
- m_address_saved = m_address;
- // Now we take the XOP number from the instruction register
- // and calculate the vector location
- // [0010 11xx xx tt SSSS] shift 6 right, then *4 => shift 4 right
- m_address = 0x0040 + ((IR >> 4) & 0x003c);
- // Takes some additional cycles
- pulse_clock(4);
- break;
- case 1:
- m_value_copy = WP; // save the old WP
- WP = m_current_value & m_prgaddr_mask & 0xfffe; // the new WP has been read in the previous microoperation
- m_current_value = m_address_saved; // we saved the address of the source operand; retrieve it
- m_address = WP + 0x0016; // Next register is R11
- break;
- case 2:
- m_address = WP + 0x001e;
- m_current_value = ST;
- break;
- case 3:
- m_address = WP + 0x001c;
- m_current_value = PC;
- break;
- case 4:
- m_address = WP + 0x001a;
- m_current_value = m_value_copy; // old WP into new R13
- break;
- case 5:
- m_address = 0x0042 + ((IR >> 4) & 0x003c); // location of new PC
- set_status_bit(ST_X, true);
- break;
- case 6:
- PC = m_current_value & m_prgaddr_mask & 0xfffe;
- break;
- }
- pulse_clock(2);
- m_state++;
-}
-
-void tms99xx_device::alu_clr_swpb()
-{
- UINT32 dest_new = 0;
- UINT32 src_val = m_current_value & 0x0000ffff;
- UINT16 sign = 0;
-
- bool setstatus = true;
- bool check_ov = true;
-
- switch (m_command)
- {
- case CLR:
- // no status bits
- m_current_value = 0x0000;
- setstatus = false;
- break;
- case SETO:
- // no status bits
- m_current_value = 0xffff;
- setstatus = false;
- break;
- case INV:
- // LAE
- dest_new = ~src_val & 0xffff;
- check_ov = false;
- break;
- case NEG:
- // LAECO
- // Overflow occurs for value=0x8000
- dest_new = ((~src_val) & 0x0000ffff) + 1;
- check_ov = false;
- set_status_bit(ST_OV, src_val == 0x8000);
- break;
- case INC:
- // LAECO
- // Overflow for result value = 0x8000
- // Carry for result value = 0x0000
- dest_new = src_val + 1;
- break;
- case INCT:
- // LAECO
- // Overflow for result value = 0x8000 / 0x8001
- // Carry for result value = 0x0000 / 0x0001
- dest_new = src_val + 2;
- break;
- case DEC:
- // LAECO
- // Carry for result value != 0xffff
- // Overflow for result value == 0x7fff
- dest_new = src_val + 0xffff;
- sign = 0x8000;
- break;
- case DECT:
- // Carry for result value != 0xffff / 0xfffe
- // Overflow for result value = 0x7fff / 0x7ffe
- dest_new = src_val + 0xfffe;
- sign = 0x8000;
- break;
- case SWPB:
- m_current_value = ((m_current_value << 8) | (m_current_value >> 8)) & 0xffff;
- setstatus = false;
- break;
- }
-
- if (setstatus)
- {
- if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign));
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
- m_current_value = dest_new & 0xffff;
- compare_and_set_lae(m_current_value, 0);
- }
-
- pulse_clock(2);
- // No states here
-}
-
-void tms99xx_device::alu_abs()
-{
- // LAECO (from original word!)
- // O if >8000
- // C is alwas reset
- set_status_bit(ST_OV, m_current_value == 0x8000);
- set_status_bit(ST_C, false);
- compare_and_set_lae(m_current_value, 0);
-
- if ((m_current_value & 0x8000)!=0)
- {
- m_current_value = (((~m_current_value) & 0x0000ffff) + 1) & 0xffff;
- pulse_clock(2); // If ABS is performed it takes one machine cycle more
- }
- else
- {
- MPC++; // skips over the next micro operation (MEMORY_WRITE)
- }
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_x()
-{
- if (TRACE_ALU) logerror("tms99xx: Substituting current command by %04x\n", m_current_value);
- decode(m_current_value);
- pulse_clock(2);
-}
-
-/*
- Also used by other microprograms
-*/
-void tms99xx_device::alu_b()
-{
- // no status bits
- // Although we got the contents of the source data, we do not use them
- // but directly branch there. That is, we are only interested in the
- // address of the source data.
- // If we have a B *R5 and R5 contains the value 0xa000, the CPU actually
- // retrieves the value at 0xa000, but in fact it will load the PC
- // with the address 0xa000
- m_current_value = PC;
- PC = m_address & m_prgaddr_mask & 0xfffe;
- m_address = WP + 22;
- if (TRACE_ALU) logerror("tms99xx: Set new PC = %04x\n", PC);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_blwp()
-{
- switch (m_state)
- {
- case 0:
- m_value_copy = WP;
- WP = m_current_value & m_prgaddr_mask & 0xfffe; // set new WP (*m_destination)
- m_address_saved = (m_address + 2) & m_prgaddr_mask; // Save the location of the WP
- m_address = WP + 30;
- m_current_value = ST; // get status register
- break;
- case 1:
- m_current_value = PC; // get program counter
- m_address = m_address - 2;
- break;
- case 2:
- m_current_value = m_value_copy; // retrieve the old WP
- m_address = m_address - 2;
- break;
- case 3:
- m_address = m_address_saved; // point to PC component of branch vector
- break;
- case 4:
- PC = m_current_value & m_prgaddr_mask & 0xfffe;
- if (TRACE_ALU) logerror("tms9900: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
- break;
- }
- pulse_clock(2);
- m_state++;
-}
-
-void tms99xx_device::alu_ldcr()
-{
- UINT16 value;
-
- // Spec: "If the source operand address is odd, the address is truncated
- // to an even address prior to data transfer."
- // (Editor/Assembler, page 151)
- // This refers to transfers with more than 8 bits. In this case, for
- // LDCR the first bit is taken from the least significant bit of the
- // source word. If the address is odd (e.g. 0x1001), it is
- // treated as 0x1000, that is, truncated to an even address.
- // For transfers with 1-8 bits, the first bit is the least significant
- // bit of the source byte (any address).
-
- if (m_state == 0)
- {
- m_address = WP + 24;
- }
- else
- {
- value = m_source_value; // copied by ALU_SOURCE
- m_count = (IR >> 6) & 0x000f;
- if (m_count == 0) m_count = 16;
- if (m_count <= 8)
- {
- if (m_source_even) value>>=8;
- set_status_parity((UINT8)(value & 0xff));
- compare_and_set_lae(value<<8, 0);
- }
- else
- {
- compare_and_set_lae(value, 0);
- }
- m_cru_address = m_current_value;
- m_value = value;
- if (TRACE_CRU) logerror("tms99xx: Load CRU address %04x (%d bits), value = %04x\n", m_cru_address, m_count, m_value);
- }
- m_state++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_stcr()
-{
- UINT16 value;
- int n = 2;
- // For STCR transfers with more than 8 bits, the first CRU bit is
- // always put into the least significant bit of the destination word.
- // If the address is odd (e.g. 0x1001), it is treated as 0x1000, that is,
- // truncated to an even boundary.
- // For transfers with 1-8 bits, the destination address is handled as
- // in MOVB operations, i.e. the other byte of the word is kept unchanged.
-
- switch (m_state)
- {
- case 0: // After getting the destination operand and saving the address/value
- m_address = WP + 24;
- n = 0;
- break;
- case 1: // After getting R12
- m_cru_address = m_current_value;
- m_count = (IR >> 6) & 0x000f;
- if (m_count == 0) m_count = 16;
- break;
- case 2: // After the cru operation; value starts at LSB of m_value
- value = m_value & 0xffff;
- if (m_count < 9)
- {
- if (TRACE_CRU) logerror("tms99xx: Store CRU at %04x (%d bits) in %04x, result = %02x\n", m_cru_address, m_count, m_source_address, value);
- set_status_parity((UINT8)(value & 0xff));
- compare_and_set_lae(value<<8, 0);
- if (m_source_even)
- m_current_value = (m_source_value & 0x00ff) | (value<<8);
- else
- m_current_value = (m_source_value & 0xff00) | (value & 0xff);
-
- pulse_clock(2*(5 + (8-m_count)));
- }
- else
- {
- if (TRACE_CRU) logerror("tms99xx: Store CRU at %04x (%d bits) in %04x, result = %04x\n", m_cru_address, m_count, m_source_address, value);
- m_current_value = value;
- compare_and_set_lae(value, 0);
- pulse_clock(2*(5 + (16-m_count)));
- }
- m_address = m_source_address;
- break;
- }
-
- m_state++;
- pulse_clock(n);
-}
-
-void tms99xx_device::alu_sbz_sbo()
-{
- INT8 displacement;
- if (m_state==0)
- {
- m_address = WP + 24;
- }
- else
- {
- m_value = (m_command==SBO)? 1 : 0;
- displacement = (INT8)(IR & 0xff);
- m_cru_address = m_current_value + (displacement<<1);
- m_count = 1;
- }
- m_state++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_tb()
-{
- INT8 displacement;
- switch (m_state)
- {
- case 0:
- m_address = WP + 24;
- break;
- case 1:
- displacement = (INT8)(IR & 0xff);
- m_cru_address = m_current_value + (displacement<<1);
- m_count = 1;
- break;
- case 2:
- set_status_bit(ST_EQ, m_value!=0);
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST);
- break;
- }
- m_state++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_jmp()
-{
- INT8 displacement;
- bool cond = false;
-
- if (m_state==0)
- {
- switch (m_command)
- {
- case JMP:
- cond = true;
- break;
- case JLT: // LAECOP == x00xxx
- cond = ((ST & (ST_AGT | ST_EQ))==0);
- break;
- case JLE: // LAECOP == 0xxxxx
- cond = ((ST & ST_LH)==0);
- break;
- case JEQ: // LAECOP == xx1xxx
- cond = ((ST & ST_EQ)!=0);
- break;
- case JHE: // LAECOP == 1x0xxx, 0x1xxx
- cond = ((ST & (ST_LH | ST_EQ)) != 0);
- break;
- case JGT: // LAECOP == x1xxxx
- cond = ((ST & ST_AGT)!=0);
- break;
- case JNE: // LAECOP == xx0xxx
- cond = ((ST & ST_EQ)==0);
- break;
- case JNC: // LAECOP == xxx0xx
- cond = ((ST & ST_C)==0);
- break;
- case JOC: // LAECOP == xxx1xx
- cond = ((ST & ST_C)!=0);
- break;
- case JNO: // LAECOP == xxxx0x
- cond = ((ST & ST_OV)==0);
- break;
- case JL: // LAECOP == 0x0xxx
- cond = ((ST & (ST_LH | ST_EQ)) == 0);
- break;
- case JH: // LAECOP == 1xxxxx
- cond = ((ST & ST_LH)!=0);
- break;
- case JOP: // LAECOP == xxxxx1
- cond = ((ST & ST_OP)!=0);
- break;
- }
- if (!cond)
- {
- if (TRACE_ALU) logerror("tms99xx: Jump condition false\n");
- MPC+=1; // skip next ALU call
- }
- else
- if (TRACE_ALU) logerror("tms99xx: Jump condition true\n");
- }
- else
- {
- displacement = (IR & 0xff);
- PC = (PC + (displacement<<1)) & m_prgaddr_mask & 0xfffe;
- }
- m_state++;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_shift()
-{
- bool carry = false;
- bool overflow = false;
- UINT16 sign = 0;
- UINT32 value;
- int count;
-
- switch (m_state)
- {
- case 0:
- m_address = WP + ((IR & 0x000f)<<1);
- pulse_clock(2);
- break;
- case 1:
- // we have the value of the register in m_current_value
- // Save it (we may have to read R0)
- m_value_copy = m_current_value;
- m_address_saved = m_address;
- m_address = WP;
- m_current_value = (IR >> 4) & 0x000f;
-
- if (m_current_value != 0)
- {
- // skip the next read and ALU operation
- MPC = MPC+2;
- m_state++;
- }
- else
- {
- if (TRACE_ALU) logerror("tms99xx: Shift operation gets count from R0\n");
- pulse_clock(2);
- }
- pulse_clock(2);
- break;
- case 2:
- // after READ
- pulse_clock(2);
- pulse_clock(2);
- break;
- case 3:
- count = m_current_value & 0x000f; // from the instruction or from R0
- if (count==0) count = 16;
-
- value = m_value_copy;
-
- // we are re-implementing the shift operations because we have to pulse
- // the clock at each single shift anyway.
- // Also, it is easier to implement the status bit setting.
- // Note that count is never 0
- if (m_command == SRA) sign = value & 0x8000;
-
- for (int i=0; i < count; i++)
- {
- switch (m_command)
- {
- case SRL:
- case SRA:
- carry = ((value & 1)!=0);
- value = (value >> 1) | sign;
- break;
- case SLA:
- carry = ((value & 0x8000)!=0);
- value <<= 1;
- if (carry != ((value&0x8000)!=0)) overflow = true;
- break;
- case SRC:
- carry = ((value & 1)!=0);
- value = (value>>1) | (carry? 0x8000 : 0x0000);
- break;
- }
- pulse_clock(2);
- }
-
- m_current_value = value & 0xffff;
- set_status_bit(ST_C, carry);
- set_status_bit(ST_OV, overflow);
- compare_and_set_lae(m_current_value, 0);
- m_address = m_address_saved; // Register address
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x (val=%04x)\n", ST, m_current_value);
- break;
- }
- m_state++;
-}
-
-void tms99xx_device::alu_ai_ori()
-{
- UINT32 dest_new = 0;
- switch (m_command)
- {
- case AI:
- dest_new = m_current_value + m_value_copy;
- // See status bit handling for Add
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
- set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_value_copy) & 0x8000)!=0);
- break;
- case ANDI:
- dest_new = m_current_value & m_value_copy;
- break;
- case ORI:
- dest_new = m_current_value | m_value_copy;
- break;
- }
- m_current_value = dest_new & 0xffff;
- m_address = m_address_copy;
- compare_and_set_lae(m_current_value, 0);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_ci()
-{
- compare_and_set_lae(m_value_copy, m_current_value);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_li()
-{
- compare_and_set_lae(m_current_value, 0);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_lwpi()
-{
- WP = m_current_value & m_prgaddr_mask & 0xfffe;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_limi()
-{
- ST = (ST & 0xfff0) | (m_current_value & 0x000f);
- if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_stwp_stst()
-{
- if (m_command==STST) m_current_value = ST;
- else m_current_value = WP;
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_external()
-{
- // Call some possibly attached external device
- // We pass the bit pattern of the address bus to the external function
-
- // IDLE = 0000 0011 0100 0000
- // RSET = 0000 0011 0110 0000
- // CKON = 0000 0011 1010 0000
- // CKOF = 0000 0011 1100 0000
- // LREX = 0000 0011 1110 0000
- // ---
- if (m_command == IDLE)
- m_idle_state = true;
-
- if (!m_external_operation.isnull()) m_external_operation((IR >> 5) & 0x07, 1, 0xff);
- pulse_clock(2);
-}
-
-void tms99xx_device::alu_rtwp()
-{
- switch (m_state)
- {
- case 0:
- m_address = WP + 30; // R15
- pulse_clock(2);
- break;
- case 1:
- ST = m_current_value;
- m_address -= 2; // R14
- break;
- case 2:
- PC = m_current_value & m_prgaddr_mask & 0xfffe;
- m_address -= 2; // R13
- break;
- case 3:
- WP = m_current_value & m_prgaddr_mask & 0xfffe;
- pulse_clock(2);
- break;
- }
- m_state++;
-}
-
-
-void tms99xx_device::alu_int()
-{
- if (TRACE_EMU) logerror("tms99xx: INT state %d; irq_level %d\n", m_state, m_irq_level);
- switch (m_state)
- {
- case 0:
- if (m_irq_level == RESET_INT)
- {
- m_address = 0;
- pulse_clock(2);
- }
- else
- {
- if (m_irq_level == LOAD_INT) m_address = 0xfffc; // will be truncated for TMS9980
- else
- {
- m_address = (m_irq_level << 2);
- }
- }
- break;
- case 1:
- m_address_copy = m_address;
- m_value_copy = WP; // old WP
- WP = m_current_value & m_prgaddr_mask & 0xfffe; // new WP
- m_current_value = ST;
- m_address = (WP + 30) & m_prgaddr_mask;
- break;
- case 2:
- m_current_value = PC;
- m_address = (WP + 28) & m_prgaddr_mask;
- break;
- case 3:
- m_current_value = m_value_copy; // old WP
- m_address = (WP + 26) & m_prgaddr_mask;
- break;
- case 4:
- m_address = (m_address_copy + 2) & 0xfffe & m_prgaddr_mask;
- if (TRACE_ALU) logerror("tms99xx: read from %04x\n", m_address);
- break;
- case 5:
- PC = m_current_value & m_prgaddr_mask & 0xfffe;
- if (m_irq_level > 0 )
- {
- ST = (ST & 0xfff0) | (m_irq_level - 1);
- }
- break;
- }
- m_state++;
- pulse_clock(2);
-}
-
-/**************************************************************************/
-UINT32 tms99xx_device::execute_min_cycles() const
-{
- return 2;
-}
-
-// TODO: Compute this value, just a wild guess for the average
-UINT32 tms99xx_device::execute_max_cycles() const
-{
- return 10;
-}
-
-UINT32 tms99xx_device::execute_input_lines() const
-{
- return 2;
-}
-
-// clocks to cycles, cycles to clocks = id
-// execute_default_irq_vector = 0
-// execute_burn = nop
-
-// device_disasm_interface overrides
-UINT32 tms99xx_device::disasm_min_opcode_bytes() const
-{
- return 2;
-}
-
-UINT32 tms99xx_device::disasm_max_opcode_bytes() const
-{
- return 6;
-}
-
-offs_t tms99xx_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
-{
- extern CPU_DISASSEMBLE( tms9900 );
- return CPU_DISASSEMBLE_NAME(tms9900)(this, buffer, pc, oprom, opram, options);
-}
-
-
-const device_type TMS9900 = &device_creator<tms9900_device>;
diff --git a/src/emu/cpu/tms9900/tms9900.h b/src/emu/cpu/tms9900/tms9900.h
deleted file mode 100644
index 8e7f19042c6..00000000000
--- a/src/emu/cpu/tms9900/tms9900.h
+++ /dev/null
@@ -1,403 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- TMS9900 processor
- This is a re-implementation of the TMS9900 featuring a cycle-precise
- behaviour.
-
- See tms9900.c for documentation
-*/
-
-#ifndef __TMS9900_H__
-#define __TMS9900_H__
-
-#include "emu.h"
-#include "debugger.h"
-#include "tms99com.h"
-
-enum
-{
- INT_9900_RESET = 0,
- INT_9900_LOAD = 1,
- INT_9900_INTREQ = 2
-};
-
-enum
-{
- LOAD_INT = -1,
- RESET_INT = -2
-};
-
-static const char opname[][5] =
-{ "ILL ", "A ", "AB ", "ABS ", "AI ", "ANDI", "B ", "BL ", "BLWP", "C ",
- "CB ", "CI ", "CKOF", "CKON", "CLR ", "COC ", "CZC ", "DEC ", "DECT", "DIV ",
- "IDLE", "INC ", "INCT", "INV ", "JEQ ", "JGT ", "JH ", "JHE ", "JL ", "JLE ",
- "JLT ", "JMP ", "JNC ", "JNE ", "JNO ", "JOC ", "JOP ", "LDCR", "LI ", "LIMI",
- "LREX", "LWPI", "MOV ", "MOVB", "MPY ", "NEG ", "ORI ", "RSET", "RTWP", "S ",
- "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ", "SOCB", "SRA ", "SRC ", "SRL ",
- "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB", "TB ", "X ", "XOP ", "XOR ",
- "*int"
-};
-
-class tms99xx_device : public cpu_device
-{
-public:
- tms99xx_device(const machine_config &mconfig, device_type type, const char *name,
- const char *tag, int databus_width, int prg_addr_bits, int cru_addr_bits,
- device_t *owner, UINT32 clock, const char *shortname, const char *source);
-
- ~tms99xx_device();
-
- // READY input line. When asserted (high), the memory is ready for data exchange.
- void set_ready(int state);
-
- // HOLD input line. When asserted (low), the CPU is requested to release the
- // data and address bus and enter the HOLD state. The entrance of this state
- // is acknowledged by the HOLDA output line.
- void set_hold(int state);
-
- // Callbacks
- template<class _Object> static devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_external_operation.set_callback(object); }
- template<class _Object> static devcb_base &static_set_intlevel_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_get_intlevel.set_callback(object); }
- template<class _Object> static devcb_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_iaq_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_clock_out_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_wait_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_wait_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_holda_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_holda_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast<tms99xx_device &>(device).m_dbin_line.set_callback(object); }
-
-protected:
- // device-level overrides
- virtual void device_start();
- virtual void device_stop();
- virtual void device_reset();
-
- virtual void resolve_lines();
-
- // device_execute_interface overrides
- virtual UINT32 execute_min_cycles() const;
- virtual UINT32 execute_max_cycles() const;
- virtual UINT32 execute_input_lines() const;
- virtual void execute_set_input(int irqline, int state);
- virtual void execute_run();
-
- // device_disasm_interface overrides
- virtual UINT32 disasm_min_opcode_bytes() const;
- virtual UINT32 disasm_max_opcode_bytes() const;
- virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
-
- const address_space_config* memory_space_config(address_spacenum spacenum) const;
-
- // Let these methods be overloaded by the TMS9980.
- virtual void mem_read(void);
- virtual void mem_write(void);
- virtual void acquire_instruction(void);
- void decode(UINT16 inst);
-
- const address_space_config m_program_config;
- const address_space_config m_io_config;
- address_space* m_prgspace;
- address_space* m_cru;
-
- virtual UINT16 read_workspace_register_debug(int reg);
- virtual void write_workspace_register_debug(int reg, UINT16 data);
-
- // Cycle counter
- int m_icount;
-
- // TMS9900 hardware registers
- UINT16 WP; // Workspace pointer
- UINT16 PC; // Program counter
- UINT16 ST; // Status register
-
- // Internal register
- UINT16 IR; // Instruction register
-
- // Stored address
- UINT16 m_address;
-
- // Stores the recently read word or the word to be written
- UINT16 m_current_value;
-
- // Decoded command
- UINT16 m_command;
-
- // Is it a byte operation? Only format 1 commands with the byte flag set
- // and CRU commands with less than 9 bits to transfer are byte operations.
- bool m_byteop;
-
- // Issue clock pulses. Note that each machine cycle has two clock cycles.
- void pulse_clock(int count);
-
- // For multi-pass operations. For instance, memory word accesses are
- // executed as two consecutive byte accesses. CRU accesses are repeated
- // single-bit accesses. (Needed for TMS9980)
- int m_pass;
-
- // Data bus width. Needed for TMS9980.
- int m_databus_width;
-
- // Check the READY line?
- bool m_check_ready;
-
- // Phase of the memory access
- int m_mem_phase;
-
- // Max address
- const UINT16 m_prgaddr_mask;
- const UINT16 m_cruaddr_mask;
-
- bool m_load_state;
- bool m_irq_state;
- bool m_reset;
-
- // Determine the interrupt level using the IC0-IC3 lines
- int get_intlevel(int state);
-
- // Interrupt level as acquired from input lines (TMS9900: IC0-IC3, TMS9980: IC0-IC2)
- // We assume all values right-justified, i.e. TMS9980 also counts up by one
- int m_irq_level;
-
- // Used to display the number of consumed cycles in the log.
- int m_first_cycle;
-
- /************************************************************************/
-
- // Clock output. This is not a pin of the TMS9900 because the TMS9900
- // needs an external clock, and usually one of those external lines is
- // used for this purpose.
- devcb_write_line m_clock_out_line;
-
- // Wait output. When asserted (high), the CPU is in a wait state.
- devcb_write_line m_wait_line;
-
- // HOLD Acknowledge line. When asserted (high), the CPU is in HOLD state.
- devcb_write_line m_holda_line;
-
- // Signal to the outside world that we are now getting an instruction
- devcb_write_line m_iaq_line;
-
- // Get the value of the interrupt level lines
- devcb_read8 m_get_intlevel;
-
- // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers.
- devcb_write_line m_dbin_line;
-
- // Trigger external operation. This is achieved by putting a special value in
- // the most significant three bits of the address bus (TMS9995: data bus) and
- // pulsing the CRUCLK line.
- // Accordingly, we have
- //
- // A0 A1 A2 A3 A4 A5 ... A12 A13 A14 A15
- // 0 0 0 x x x x x x - normal CRU access
- // 0 1 0 x x x x x x - IDLE
- // 0 1 1 x x x x x x - RSET
- // 1 0 1 x x x x x x - CKON
- // 1 1 0 x x x x x x - CKOF
- // 1 1 1 x x x x x x - LREX
- //
- // so the TMS9900 can only use CRU addresses 0 - 1ffe for CRU operations.
- // By moving these three bits to the data bus, the TMS9995 can allow for the
- // full range 0000-fffe for its CRU operations.
- //
- // We could realize this via the CRU access as well, but the data bus access
- // is not that simple to emulate. For the sake of homogenity between the
- // chip emulations we use a dedicated callback.
- devcb_write8 m_external_operation;
-
-
-private:
- // Indicates if this is a byte-oriented command
- inline bool byte_operation();
-
- // Processor states
- bool m_idle_state;
-
- // READY handling. The READY line is operated before the phi1 clock
- // pulse rises. As the ready line is only set once in this emulation we
- // keep the level in a buffer (like a latch)
- bool m_ready_bufd; // buffered state
- bool m_ready; // sampled value
-
- bool m_wait_state;
- bool m_hold_state;
-
- // State / debug management
- UINT16 m_state_any;
- static const char* s_statename[];
- void state_import(const device_state_entry &entry);
- void state_export(const device_state_entry &entry);
- void state_string_export(const device_state_entry &entry, std::string &str);
-
- // Interrupt handling
- void service_interrupt();
-
- // ================ Microprogram support ========================
-
- // Set up lookup table
- void build_command_lookup_table();
-
- // Sequence of micro-operations
- typedef const UINT8* microprogram;
-
- // Method pointer
- typedef void (tms99xx_device::*ophandler)(void);
-
- // Opcode list entry
- struct tms_instruction
- {
- UINT16 opcode;
- int id;
- int format;
- microprogram prog; // Microprogram
- };
-
- // Lookup table entry
- struct lookup_entry
- {
- lookup_entry *next_digit;
- const tms_instruction *entry;
- };
-
- // Pointer to the lookup table
- lookup_entry* m_command_lookup_table;
-
- // List of allocated tables (used for easy clean-up on exit)
- lookup_entry* m_lotables[32];
-
- // List of pointers for micro-operations
- static const tms99xx_device::ophandler s_microoperation[];
-
- // Opcode table
- static const tms99xx_device::tms_instruction s_command[];
-
- // Micro-operation declarations
- void register_read(void);
- void register_write(void);
- void cru_input_operation(void);
- void cru_output_operation(void);
- void data_derivation_subprogram(void);
- void return_from_subprogram(void);
- void command_completed(void);
-
- void alu_nop(void);
- void alu_clear(void);
- void alu_source(void);
- void alu_setaddr(void);
- void alu_addone(void);
- void alu_setaddr_addone(void);
- void alu_pcaddr_advance(void);
- void alu_add_register(void);
-
- void alu_imm(void);
- void alu_reg(void);
-
- void alu_f1(void);
- void alu_comp(void);
- void alu_f3(void);
- void alu_multiply(void);
- void alu_divide(void);
- void alu_xop(void);
- void alu_clr_swpb(void);
- void alu_abs(void);
- void alu_x(void);
- void alu_b(void);
- void alu_bl(void);
- void alu_blwp(void);
- void alu_ldcr(void);
- void alu_stcr(void);
- void alu_sbz_sbo(void);
- void alu_tb(void);
- void alu_jmp(void);
- void alu_shift(void);
- void alu_ai_ori(void);
- void alu_ci(void);
- void alu_li(void);
- void alu_lwpi(void);
- void alu_limi(void);
- void alu_stwp_stst(void);
- void alu_external(void);
- void alu_rtwp(void);
- void alu_int(void);
-
- void abort_operation(void);
-
- // Micro-operation
- UINT8 m_op;
-
- // Micro-operation program counter (as opposed to the program counter PC)
- int MPC;
-
- // Current microprogram
- const UINT8* m_program;
-
- // Calling microprogram (used when data derivation is called)
- const UINT8* m_caller;
- int m_caller_MPC;
-
- // State of the micro-operation. Needed for repeated ALU calls.
- int m_state;
-
- // Has HOLD been acknowledged yet?
- bool m_hold_acknowledged;
-
- // Signal the wait state via the external line
- inline void set_wait_state(bool state);
-
- // Used to acknowledge HOLD and enter the HOLD state
- inline void acknowledge_hold();
-
- // Was the source operand a byte from an even address?
- bool m_source_even;
-
- // Was the destination operand a byte from an even address?
- bool m_destination_even;
-
- // Intermediate storage for the source operand
- UINT16 m_source_address;
- UINT16 m_source_value;
- UINT16 m_address_saved;
-
- // Another copy of the address
- UINT16 m_address_copy;
-
- // Stores the recently read register contents
- UINT16 m_register_contents;
-
- // Stores the register number for the next register access
- int m_regnumber;
-
- // CRU support: Stores the CRU address
- UINT16 m_cru_address;
-
- // CRU support: Stores the number of bits to be transferred
- int m_count;
-
- // Copy of the value
- UINT16 m_value_copy;
-
- // Another internal register, storing intermediate values
- // Using 32 bits to support MPY
- UINT32 m_value;
-
- // For two-argument commands. Indicates whether this is the second operand.
- bool m_get_destination;
-
- // Status register update
- inline void set_status_bit(int bit, bool state);
- inline void compare_and_set_lae(UINT16 value1, UINT16 value2);
- void set_status_parity(UINT8 value);
-};
-
-/*****************************************************************************/
-
-class tms9900_device : public tms99xx_device
-{
-public:
- tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
-};
-
-
-// device type definition
-extern const device_type TMS9900;
-
-#endif /* __TMS9900_H__ */
diff --git a/src/emu/cpu/tms9900/tms9980a.c b/src/emu/cpu/tms9900/tms9980a.c
deleted file mode 100644
index 054a293a403..00000000000
--- a/src/emu/cpu/tms9900/tms9980a.c
+++ /dev/null
@@ -1,300 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- Cycle-precise implementation of the TMS9980A.
- Subclassed from tms99xx_device in tms9900.c.
-
- +----------------+
- /HOLD | 1 \/ 40| /MEMEN
- HOLDA | 2 39| READY
- IAQ | 3 38| /WE
- LSB +- A13,CRUOUT | 4 37| CRUCLK
- | A12 | 5 36| Vdd
- | A11 | 6 35| Vss
- | A10 | 7 34| CKIN
- Address A9 | 8 33| D7 --+
- bus A8 | 9 32| D6 |
- | A7 |10 31| D5 Data
- 16KiB A6 |11 30| D4 bus
- | A5 |12 29| D3 |
- | A4 |13 28| D2 2 * 8 bit
- | A3 |14 27| D1 |
- | A2 |15 26| D0 --+
- | A1 |16 25| INT0 --+
- MSB +-- A0 |17 24| INT1 | Interrupt levels
- DBIN |18 23| INT2 --+
- CRUIN |19 22| /PHI3
- Vcc |20 21| Vbb
- +----------------+
-
- The TMS9980A is similar to the TMS9900, with the following differences:
-
- - Address bus is only 14 bit wide (16 KiB)
- - Data bus is 16 bit wide and multiplexed on 8 lines (2 bytes per access)
- - CRU space is limited to 2048 bits (due to fewer address lines)
- - Only three interrupt level lines, for a maximum of 8 levels.
- - No INTREQ, RESET, and LOAD lines. All interrupts are signaled via INT0 -
- INT2. Reset=00x, Load=010, Level1=011, Level2=100, Level3=101, Level4=110,
- all interrupts cleared=111.
- - Memory accesses are always 2 bytes (even address byte, odd address byte)
- even for byte operations. Thus the 9980A, like the TMS9900, needs to
- pre-fetch the word at the destination before overwriting it.
- - On the cycle level both TMS9900 and TMS9980A are equal, except for the
- additional cycles needed for memory read and write access. Accordingly,
- the emulation shares the core and the microprograms and redefines the
- memory access and the interrupt handling only.
- - The 9980A has the same external instructions as the TMS9900, but it
- indicates the command via A0, A1, and A13 (instead of A0-A2).
-
- For pin definitions see tms9900.c
-
- Michael Zapf, 2012
-*/
-
-#include "tms9980a.h"
-
-/*
- The following defines can be set to 0 or 1 to disable or enable certain
- output in the log.
-*/
-
-// Memory operation
-#define TRACE_MEM 0
-
-// Address bus operation
-#define TRACE_ADDRESSBUS 0
-
-// Log operation
-#define TRACE_OP 0
-
-// Interrupts
-#define TRACE_INT 0
-
-/****************************************************************************
- Constructor
-****************************************************************************/
-
-tms9980a_device::tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms99xx_device(mconfig, TMS9980A, "TMS9980A", tag, 8, 14, 11, owner, clock, "tms9980a", __FILE__)
-{
-}
-
-/*
- External connections
-*/
-void tms9980a_device::resolve_lines()
-{
- // Resolve our external connections
- m_external_operation.resolve();
- m_iaq_line.resolve();
- m_clock_out_line.resolve();
- m_holda_line.resolve();
- m_dbin_line.resolve();
-}
-
-UINT16 tms9980a_device::read_workspace_register_debug(int reg)
-{
- int temp = m_icount;
- int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask;
- UINT16 value = (m_prgspace->read_byte(addr) << 8) | (m_prgspace->read_byte(addr+1) & 0xff);
- m_icount = temp;
- return value;
-}
-
-void tms9980a_device::write_workspace_register_debug(int reg, UINT16 data)
-{
- int temp = m_icount;
- int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask;
- m_prgspace->write_byte(addr, data>>8);
- m_prgspace->write_byte(addr+1, data & 0xff);
- m_icount = temp;
-}
-
-/*
- Interrupt input. Keep in mind that the TMS9980A does not have any INTREQ
- line but signals interrupts via IC0-IC2 only. Thus we cannot take down any
- single interrupt; only all interrupts can be cleared at once using level 7.
- The state parameter is actually not needed.
-*/
-void tms9980a_device::execute_set_input(int irqline, int state)
-{
- // We model the three lines IC0-IC2 as 8 separate input lines, although we
- // cannot assert more than one at a time. The state value is not needed,
- // as level 7 means to clean all interrupts, but we consider it for the
- // sake of consistency.
-
- int level = irqline;
-
- // Just to stay consistent.
- if (state==CLEAR_LINE) level = INT_9980A_CLEAR;
-
- switch (level)
- {
- case INT_9980A_RESET:
- case 1:
- level = RESET_INT;
- m_reset = true;
- break;
- case INT_9980A_LOAD:
- level = LOAD_INT;
- break;
- case INT_9980A_LEVEL1:
- case INT_9980A_LEVEL2:
- case INT_9980A_LEVEL3:
- case INT_9980A_LEVEL4:
- level = level - 2;
- break;
- case INT_9980A_CLEAR:
- // Clear all interrupts
- m_load_state = false;
- m_irq_state = false;
- if (TRACE_INT) logerror("tms9980a: clear interrupts\n");
- break;
- }
-
- m_irq_level = level;
-
- if (m_irq_level != INT_9980A_CLEAR)
- {
- if (m_irq_level == LOAD_INT)
- {
- // Some boards start up with LOAD interrupt, so we clear the reset flag
- m_reset = false;
- m_load_state = true;
- }
- else m_irq_state = true;
- if (TRACE_INT) logerror("tms9980a: interrupt level=%d, ST=%04x\n", m_irq_level, ST);
- }
-}
-
-/*****************************************************************************/
-
-/*
- Memory read:
- Clock cycles: 4 + 2W, W = number of wait states
-*/
-void tms9980a_device::mem_read()
-{
- UINT8 value;
- switch (m_mem_phase)
- {
- case 1:
- m_pass = 4; // make the CPU visit this method more than once
- if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
- m_prgspace->set_address(m_address & m_prgaddr_mask & ~1);
- if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1);
- m_check_ready = true;
- break;
- case 2:
- // Sample the value on the data bus (high byte)
- value = m_prgspace->read_byte(m_address & m_prgaddr_mask & ~1);
- if (TRACE_MEM) logerror("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask & ~1, value);
- m_current_value = (value << 8) & 0xff00;
- break;
- case 3:
- m_prgspace->set_address((m_address & m_prgaddr_mask) | 1);
- if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1);
- break;
- case 4:
- // Sample the value on the data bus (low byte)
- value = m_prgspace->read_byte((m_address & m_prgaddr_mask) | 1);
- m_current_value = m_current_value | (value & 0x00ff);
- if (TRACE_MEM) logerror("tms9980a: memory read low byte %04x -> %02x -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, value, m_current_value);
- break;
- }
- pulse_clock(1);
- m_mem_phase = (m_mem_phase % 4) +1;
-}
-
-
-void tms9980a_device::mem_write()
-{
- switch (m_mem_phase)
- {
- case 1:
- m_pass = 4; // make the CPU visit this method once more
- if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
- m_prgspace->set_address(m_address & m_prgaddr_mask & ~1);
- if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1);
- m_prgspace->write_byte(m_address & 0x3ffe & ~1, (m_current_value >> 8)&0xff);
- if (TRACE_MEM) logerror("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask & ~1, (m_current_value >> 8)&0xff);
- m_check_ready = true;
- break;
- case 2:
- // no action here, just wait for READY
- break;
- case 3:
- m_prgspace->set_address((m_address & m_prgaddr_mask) | 1);
- if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1);
- m_prgspace->write_byte((m_address & m_prgaddr_mask) | 1, m_current_value & 0xff);
- if (TRACE_MEM) logerror("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff);
- break;
- case 4:
- // no action here, just wait for READY
- break;
- }
- pulse_clock(1);
- m_mem_phase = (m_mem_phase % 4) +1;
-}
-
-void tms9980a_device::acquire_instruction()
-{
- if (m_mem_phase == 1)
- {
- if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE);
- m_address = PC;
- m_first_cycle = m_icount;
- }
- mem_read();
-
- if (m_mem_phase == 1) // changed by mem_read and wrapped
- {
- decode(m_current_value);
- if (TRACE_OP) logerror("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC);
- debugger_instruction_hook(this, PC);
- PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
- }
- // IAQ will be cleared in the main loop
-}
-
-
-
-/**************************************************************************/
-UINT32 tms9980a_device::execute_min_cycles() const
-{
- return 2;
-}
-
-// TODO: Compute this value, just a wild guess for the average
-UINT32 tms9980a_device::execute_max_cycles() const
-{
- return 10;
-}
-
-UINT32 tms9980a_device::execute_input_lines() const
-{
- return 8;
-}
-
-// clocks to cycles, cycles to clocks = id
-// execute_default_irq_vector = 0
-// execute_burn = nop
-
-// device_disasm_interface overrides
-UINT32 tms9980a_device::disasm_min_opcode_bytes() const
-{
- return 2;
-}
-
-UINT32 tms9980a_device::disasm_max_opcode_bytes() const
-{
- return 6;
-}
-
-offs_t tms9980a_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
-{
- extern CPU_DISASSEMBLE( tms9980 );
- return CPU_DISASSEMBLE_NAME(tms9980)(this, buffer, pc, oprom, opram, options);
-}
-
-const device_type TMS9980A = &device_creator<tms9980a_device>;
diff --git a/src/emu/cpu/tms9900/tms9980a.h b/src/emu/cpu/tms9900/tms9980a.h
deleted file mode 100644
index 82492d6073a..00000000000
--- a/src/emu/cpu/tms9900/tms9980a.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- TMS9980A.
- See tms9980a.c and tms9900.c for documentation
-*/
-
-#ifndef __TMS9980A_H__
-#define __TMS9980A_H__
-
-#include "emu.h"
-#include "debugger.h"
-#include "tms9900.h"
-
-enum
-{
- INT_9980A_RESET = 0,
- INT_9980A_LOAD = 2,
- INT_9980A_LEVEL1 = 3,
- INT_9980A_LEVEL2 = 4,
- INT_9980A_LEVEL3 = 5,
- INT_9980A_LEVEL4 = 6,
- INT_9980A_CLEAR= 7
-};
-
-class tms9980a_device : public tms99xx_device
-{
-public:
- tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
-
-protected:
- void mem_read(void);
- void mem_write(void);
- void acquire_instruction(void);
-
- void resolve_lines();
-
- UINT16 read_workspace_register_debug(int reg);
- void write_workspace_register_debug(int reg, UINT16 data);
-
- UINT32 execute_min_cycles() const;
- UINT32 execute_max_cycles() const;
- UINT32 execute_input_lines() const;
- void execute_set_input(int irqline, int state);
-
- UINT32 disasm_min_opcode_bytes() const;
- UINT32 disasm_max_opcode_bytes() const;
- offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
- address_space_config m_program_config80;
- address_space_config m_io_config80;
-};
-
-// device type definition
-extern const device_type TMS9980A;
-
-#endif /* __TMS9980A_H__ */
diff --git a/src/emu/cpu/tms9900/tms9995.c b/src/emu/cpu/tms9900/tms9995.c
deleted file mode 100644
index ae9248fd82d..00000000000
--- a/src/emu/cpu/tms9900/tms9995.c
+++ /dev/null
@@ -1,3466 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- Texas Instruments TMS9995
-
- +----------------+
- XTAL1 | 1 \/ 40| A15,CRUOUT
- XTAL2,CLKIN | 2 39| A14
- CLKOUT | 3 38| A13
- D7 | 4 37| A12
- D6 | 5 36| A11
- D5 | 6 35| A10
- D4 | 7 34| A9
- D3 | 8 33| A8
- D2 | 9 32| A7
- Vcc |10 31| Vss
- D1 |11 30| A6
- D0 |12 29| A5
- CRUIN |13 28| A4
- /INT4,/EC |14 27| A3
- /INT1 |15 26| A2
- IAQ,HOLDA |16 25| A1
- /DBIN |17 24| A0
- /HOLD |18 23| READY
- /WE,/CRUCLK |19 22| /RESET
- /MEMEN |20 21| /NMI
- +----------------+
-
- XTAL1 in Crystal input pin for internal oscillator
- XTAL2 in Crystal input pin for internal oscillator, or
- CLKIN in Input pin for external oscillator
- CLKOUT out Clock output signal (1:4 of the input signal frequency)
- CRUIN in CRU input data
- /INT4 in Interrupt level 4 input
- /EC in Event counter
- /INT1 in Interrupt level 1 input
- IAQ out Instruction acquisition
- HOLDA out Hold acknowledge
- /WE out Data available for memory write
- /CRUCLK out Communication register unit clock output
- /MEMEN out Address bus contains memory address
- /NMI in Non-maskable interrupt (/LOAD on TMS9900)
- /RESET in Reset interrupt
- READY in Memory/External CRU device ready for access
- CRUOUT out Communication register unit data output
-
- Vcc +5V supply
- Vss 0V Ground reference
-
- A0-A15 out Address bus
- D0-D7 in/out Data bus
-
- Note that Texas Instruments' bit numberings define bit 0 as the
- most significant bit (different to most other systems). Also, the
- system uses big-endian memory organisation: Storing the word 0x1234 at
- address 0x0000 means that the byte 0x12 is stored at 0x0000 and byte 0x34
- is stored at 0x0001.
-
- The TMS9995 is a 16 bit microprocessor like the TMS9900, operating on
- 16-bit words and using 16-bit opcodes. Memory transfer of 16-bit words
- is achieved by a transfer of the most significant byte, followed by
- the least significant byte.
-
- The 8-bit databus width allows the processor to exchange single bytes with
- the external memory.
-
- See tms9900.c for some more details on the cycle-precise implementation.
-
- This implementation also features all control lines and the instruction
- prefetch mechanism. Prefetching is explicitly triggered within the
- microprograms. The TMS9995 specification does not reveal the exact
- operations during the microprogram execution, so we have to look at the
- required cycle numbers to guess what is happening.
-
- Auto wait state:
-
- In order to enable automatic wait state creation, the READY line must be
- cleared on reset time. A good position to do this is MACHINE_RESET in
- the driver.
-
-
- References (see comments below)
- ----------
- [1] Texas Instruments 9900 Microprocessor series: TMS9995 16-bit Microcomputer
-
- TODO:
- - State save
- - Test HOLD
-
- Michael Zapf, June 2012
-*/
-
-#include "tms9995.h"
-
-/* tms9995 ST register bits. */
-enum
-{
- ST_LH = 0x8000, // Logical higher (unsigned comparison)
- ST_AGT = 0x4000, // Arithmetical greater than (signed comparison)
- ST_EQ = 0x2000, // Equal
- ST_C = 0x1000, // Carry
- ST_OV = 0x0800, // Overflow (when using signed operations)
- ST_OP = 0x0400, // Odd parity (used with byte operations)
- ST_X = 0x0200, // XOP
- ST_OE = 0x0020, // Overflow interrupt enabled
- ST_IM = 0x000f // Interrupt mask
-};
-
-enum
-{
- PENDING_NMI = 1,
- PENDING_MID = 2,
- PENDING_LEVEL1 = 4,
- PENDING_OVERFLOW = 8,
- PENDING_DECR = 16,
- PENDING_LEVEL4 = 32
-};
-
-/*****************************************************************
- Debugging
- Set to 0 (disable) or 1 (enable)
-******************************************************************/
-
-// Log addresses of executed opcodes
-#define TRACE_EXEC 0
-
-// Log cycles
-#define TRACE_CYCLES 0
-
-// Log configuration
-#define TRACE_CONFIG 1
-
-// Log emulation details
-#define TRACE_EMU 0
-
-// Log wait/hold states
-#define TRACE_WAITHOLD 0
-
-// Log microinstruction processing
-#define TRACE_MICRO 0
-
-// Log interrupts
-#define TRACE_INT 0
-
-// Log interrupts (detailed phases)
-#define TRACE_INTD 0
-
-// Log clock pulses
-#define TRACE_CLOCK 0
-
-// Log READY line input
-#define TRACE_READY 0
-
-// Log memory access
-#define TRACE_MEM 0
-
-// Log address bus operation
-#define TRACE_ADDRESSBUS 0
-
-// Log CRU operations
-#define TRACE_CRU 0
-
-// Log status register
-#define TRACE_STATUS 0
-
-// Log operation
-#define TRACE_OP 0
-
-// Log decrementer operation
-#define TRACE_DEC 0
-
-// Log with max detail
-#define TRACE_DETAIL 0
-
-/****************************************************************************
- Constructor
-****************************************************************************/
-
-tms9995_device::tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : cpu_device(mconfig, TMS9995, "TMS9995", tag, owner, clock, "tms9995", __FILE__),
- m_state_any(0),
- PC(0),
- PC_debug(0),
- m_program_config("program", ENDIANNESS_BIG, 8, 16),
- m_io_config("cru", ENDIANNESS_BIG, 8, 16),
- m_prgspace(NULL),
- m_cru(NULL),
- m_external_operation(*this),
- m_iaq_line(*this),
- m_clock_out_line(*this),
- m_holda_line(*this),
- m_dbin_line(*this)
-{
- m_mp9537 = false;
- m_check_overflow = false;
-}
-
-/*
- Called from subclass.
-*/
-tms9995_device::tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
- : cpu_device(mconfig, TMS9995, name, tag, owner, clock, shortname, source),
- m_state_any(0),
- PC(0),
- PC_debug(0),
- m_program_config("program", ENDIANNESS_BIG, 8, 16),
- m_io_config("cru", ENDIANNESS_BIG, 8, 16),
- m_prgspace(NULL),
- m_cru(NULL),
- m_external_operation(*this),
- m_iaq_line(*this),
- m_clock_out_line(*this),
- m_holda_line(*this),
- m_dbin_line(*this)
-{
- m_check_overflow = false;
-}
-
-
-enum
-{
- TMS9995_PC=0, TMS9995_WP, TMS9995_STATUS, TMS9995_IR,
- TMS9995_R0, TMS9995_R1, TMS9995_R2, TMS9995_R3,
- TMS9995_R4, TMS9995_R5, TMS9995_R6, TMS9995_R7,
- TMS9995_R8, TMS9995_R9, TMS9995_R10, TMS9995_R11,
- TMS9995_R12, TMS9995_R13, TMS9995_R14, TMS9995_R15
-};
-
-void tms9995_device::device_start()
-{
- // TODO: Restore save state suport
-
- m_prgspace = &space(AS_PROGRAM); // dimemory.h
- m_cru = &space(AS_IO);
-
- // Resolve our external connections
- m_external_operation.resolve();
- m_iaq_line.resolve();
- m_clock_out_line.resolve();
- m_holda_line.resolve();
- m_dbin_line.resolve();
-
- // set our instruction counter
- m_icountptr = &m_icount;
-
- // Clear the interrupt flags
- m_int_pending = 0;
-
- m_mid_flag = false;
- m_mid_active = false;
- m_nmi_active = false;
- m_int_overflow = false;
- m_int_decrementer = false;
-
- m_idle_state = false;
-
- m_source_value = 0;
-
- // add the states for the debugger
- for (int i=0; i < 20; i++)
- {
- // callimport = need to use the state_import method to write to the state variable
- // callexport = need to use the state_export method to read the state variable
- state_add(i, s_statename[i], m_state_any).callimport().callexport().formatstr("%04X");
- }
- state_add(STATE_GENPC, "curpc", PC_debug).formatstr("%4s").noshow();
- state_add(STATE_GENFLAGS, "status", m_state_any).callimport().callexport().formatstr("%16s").noshow();
-
- // Set up the lookup table for command decoding
- build_command_lookup_table();
-
- if (TRACE_CONFIG) logerror("%s: Variant = %s, Overflow int = %s\n", tag(), m_mp9537? "MP9537 (no on-chip RAM)" : "with on-chip RAM", m_check_overflow? "check" : "no check");
-}
-
-void tms9995_device::device_stop()
-{
- int k = 0;
- if (TRACE_CONFIG) logerror("%s: Deleting lookup tables\n", tag());
- while (m_lotables[k]!=NULL) delete[] m_lotables[k++];
-}
-
-/*
- TMS9995 hard reset
- The device reset is just the emulator's trigger for the reset procedure
- which is invoked via the main loop.
-
- This also allows us to check the READY line at reset time, which is used
- to enable automatic wait state creation.
-*/
-void tms9995_device::device_reset()
-{
- m_reset = true; // for the main loop
- m_servicing_interrupt = false; // only for debugging
- m_request_auto_wait_state = false;
- memset(m_flag, 0, sizeof(m_flag));
-}
-
-const char* tms9995_device::s_statename[20] =
-{
- "PC ", "WP ", "ST ", "IR ",
- "R0 ", "R1 ", "R2 ", "R3 ",
- "R4 ", "R5 ", "R6 ", "R7 ",
- "R8 ", "R9 ", "R10", "R11",
- "R12", "R13", "R14", "R15"
-};
-
-/*
- Write the contents of a register by external input (debugger)
- Note: this is untested any may fail because of the prefetch feature of the CPU.
- In particular it may be required to adjust the PC.
-*/
-void tms9995_device::state_import(const device_state_entry &entry)
-{
- int index = entry.index();
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- // no action here; we do not allow import, as the flags are all
- // bits of the STATUS register
- break;
- case TMS9995_PC:
- PC = (UINT16)m_state_any & 0xfffe;
- break;
- case TMS9995_WP:
- WP = (UINT16)m_state_any & 0xfffe;
- break;
- case TMS9995_STATUS:
- ST = (UINT16)m_state_any;
- break;
- case TMS9995_IR:
- m_instruction->IR = (UINT16)m_state_any;
- break;
- default:
- // Workspace registers
- if (index <= TMS9995_R15)
- write_workspace_register_debug(index-TMS9995_R0, (UINT16)m_state_any);
- break;
- }
-}
-
-/*
- Reads the contents of a register for display in the debugger.
-*/
-void tms9995_device::state_export(const device_state_entry &entry)
-{
- int index = entry.index();
- switch (entry.index())
- {
- case STATE_GENFLAGS:
- m_state_any = ST;
- break;
- case TMS9995_PC:
- m_state_any = PC_debug;
- break;
- case TMS9995_WP:
- m_state_any = WP;
- break;
- case TMS9995_STATUS:
- m_state_any = ST;
- break;
- case TMS9995_IR:
- m_state_any = m_instruction->IR;
- break;
- default:
- // Workspace registers
- if (index <= TMS9995_R15)
- m_state_any = read_workspace_register_debug(index-TMS9995_R0);
- break;
- }
-}
-
-/*
- state_string_export - export state as a string for the debugger
-*/
-void tms9995_device::state_string_export(const device_state_entry &entry, std::string &str)
-{
- static const char *statestr = "LAECOPX-----IIII";
- char flags[17];
- memset(flags, 0x00, ARRAY_LENGTH(flags));
- UINT16 val = 0x8000;
- if (entry.index()==STATE_GENFLAGS)
- {
- for (int i=0; i < 16; i++)
- {
- flags[i] = ((val & ST)!=0)? statestr[i] : '.';
- val = (val >> 1) & 0x7fff;
- }
- }
- str.assign(flags);
-}
-
-/*
- Provide access to the workspace registers via the debugger. We have to
- take care whether this is in onchip RAM or outside.
-*/
-UINT16 tms9995_device::read_workspace_register_debug(int reg)
-{
- int temp = m_icount;
- UINT16 value;
-
- int addrb = (WP + (reg << 1)) & 0xfffe;
-
- if (is_onchip(addrb))
- {
- value = (m_onchip_memory[addrb & 0x00fe]<<8) | m_onchip_memory[(addrb & 0x00fe) + 1];
- }
- else
- {
- m_prgspace->set_debugger_access(true);
- value = (m_prgspace->read_byte(addrb) << 8) & 0xff00;
- value |= m_prgspace->read_byte(addrb+1);
- m_prgspace->set_debugger_access(false);
- }
- m_icount = temp;
- return value;
-}
-
-void tms9995_device::write_workspace_register_debug(int reg, UINT16 data)
-{
- int temp = m_icount;
- int addrb = (WP + (reg << 1)) & 0xfffe;
-
- if (is_onchip(addrb))
- {
- m_onchip_memory[addrb & 0x00fe] = (data >> 8) & 0xff;
- m_onchip_memory[(addrb & 0x00fe) + 1] = data & 0xff;
- }
- else
- {
- m_prgspace->set_debugger_access(true);
- m_prgspace->write_byte(addrb, (data >> 8) & 0xff);
- m_prgspace->write_byte(addrb+1, data & 0xff);
- m_prgspace->set_debugger_access(false);
- }
- m_icount = temp;
-}
-
-const address_space_config *tms9995_device::memory_space_config(address_spacenum spacenum) const
-{
- switch (spacenum)
- {
- case AS_PROGRAM:
- return &m_program_config;
-
- case AS_IO:
- return &m_io_config;
-
- default:
- return NULL;
- }
-}
-
-/**************************************************************************
- Microprograms for the CPU instructions
-
- The actions which are specific to the respective instruction are
- invoked by repeated calls of ALU_xxx; each call increases a state
- variable so that on the next call, the next part can be processed.
- This saves us a lot of additional functions.
-**************************************************************************/
-
-/*
- Define the indices for the micro-operation table. This is done for the sake
- of a simpler microprogram definition as an UINT8[].
-*/
-enum
-{
- PREFETCH,
- PREFETCH_NO_INT,
- MEMORY_READ,
- MEMORY_WRITE,
- WORD_READ,
- WORD_WRITE,
- OPERAND_ADDR,
- INCREG,
- INDX,
- SET_IMM,
- RETADDR,
- RETADDR1,
- CRU_INPUT,
- CRU_OUTPUT,
- ABORT,
- END,
-
- ALU_NOP,
- ALU_ADD_S_SXC,
- ALU_B,
- ALU_BLWP,
- ALU_C,
- ALU_CI,
- ALU_CLR_SETO,
- ALU_DIV,
- ALU_DIVS,
- ALU_EXTERNAL,
- ALU_F3,
- ALU_IMM_ARITHM,
- ALU_JUMP,
- ALU_LDCR,
- ALU_LI,
- ALU_LIMIWP,
- ALU_LSTWP,
- ALU_MOV,
- ALU_MPY,
- ALU_RTWP,
- ALU_SBO_SBZ,
- ALU_SHIFT,
- ALU_SINGLE_ARITHM,
- ALU_STCR,
- ALU_STSTWP,
- ALU_TB,
- ALU_X,
- ALU_XOP,
- ALU_INT
-};
-
-#define MICROPROGRAM(_MP) \
- static const UINT8 _MP[] =
-
-/*
- Cycles:
- XXXX 1 => needs one cycle
- xxxx 1 (1) => needs one cycle when accessing internal memory, two for external mem
- PREFETCH 0 (1) => occurs during the last step in parallel, needs one more when fetching from outside
- DECODE not shown here; assumed to happen during the next memory cycle; if there is none,
- add another cycle
-
- OPERAND_ADDR x => needs x cycles for address derivation; see the separate table
-
- Prefetch always needs 1 or 2 cycles; the previous command occurs in parallel
- to the prefetch, so we assign a 0 to the previous microprogram step
-*/
-
-MICROPROGRAM(operand_address_derivation)
-{
- RETADDR, 0, 0, 0, // Register direct 0
- WORD_READ, RETADDR, 0, 0, // Register indirect 1 (1)
- WORD_READ, RETADDR, 0, 0, // Symbolic 1 (1)
- WORD_READ, INCREG, WORD_WRITE, RETADDR1, // Reg indirect auto-increment 3 (1) (1)
- WORD_READ, INDX, WORD_READ, RETADDR // Indexed 3 (1) (1)
-};
-
-MICROPROGRAM(add_s_sxc_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- OPERAND_ADDR, // y
- MEMORY_READ, // 1 (1)
- ALU_ADD_S_SXC, // 0 (see above, occurs in parallel with PREFETCH)
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1) + decode in parallel (0)
- END
-};
-
-MICROPROGRAM(b_mp)
-{
- OPERAND_ADDR, // x
- ALU_NOP, // 1 Don't read, just use the address
- ALU_B, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1 Don't save the return address
- END
-};
-
-MICROPROGRAM(bl_mp)
-{
- OPERAND_ADDR, // x
- ALU_NOP, // 1 Don't read, just use the address
- ALU_B, // 0 Re-use the alu operation from B
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- MEMORY_WRITE, // 1 (1) Write R11
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(blwp_mp)
-{
- OPERAND_ADDR, // x Determine source address
- MEMORY_READ, // 1 (1)
- ALU_BLWP, // 1 Got new WP, save it; increase address, save
- MEMORY_WRITE, // 1 (1) save old ST to new R15
- ALU_BLWP, // 1
- MEMORY_WRITE, // 1 (1) save old PC to new R14
- ALU_BLWP, // 1
- MEMORY_WRITE, // 1 (1) save old WP to new R13
- ALU_BLWP, // 1 retrieve address
- MEMORY_READ, // 1 (1) Read new PC
- ALU_BLWP, // 0 Set new PC
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(c_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- OPERAND_ADDR, // y
- MEMORY_READ, // 1 (1)
- ALU_C, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1 decode
- END
-};
-
-MICROPROGRAM(ci_mp)
-{
- MEMORY_READ, // 1 (1) (reg)
- SET_IMM, // 0 belongs to next cycle
- MEMORY_READ, // 1 (1) (imm)
- ALU_CI, // 0 set status
- PREFETCH, // 1 (1)
- ALU_NOP, // 1 decode
- END
-};
-
-MICROPROGRAM(coc_czc_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- ALU_F3, // 0
- MEMORY_READ, // 1 (1)
- ALU_F3, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1 decode
- END
-};
-
-MICROPROGRAM(clr_seto_mp)
-{
- OPERAND_ADDR, // x
- ALU_NOP, // 1
- ALU_CLR_SETO, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(divide_mp) // TODO: Verify cycles on the real machine
-{
- OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S
- MEMORY_READ, // 1 (1) Get S
- ALU_DIV, // 1
- MEMORY_READ, // 1 (1) Get W1
- ALU_DIV, // 1 Check for overflow; skip next instruction if not
- ABORT, // 1
- MEMORY_READ, // 1 (1) Get W2
- ALU_DIV, // d Calculate quotient
- MEMORY_WRITE, // 1 (1) Write quotient to &W1
- ALU_DIV, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1) Write remainder to &W2
- END
-};
-
-MICROPROGRAM(divide_signed_mp) // TODO: Verify cycles on the real machine
-{
- OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S
- MEMORY_READ, // 1 (1) Get S
- ALU_DIVS, // 1
- MEMORY_READ, // 1 (1) Get W1
- ALU_DIVS, // 1
- MEMORY_READ, // 1 (1) Get W2
- ALU_DIVS, // 1 Check for overflow, skip next instruction if not
- ABORT, // 1
- ALU_DIVS, // d Calculate quotient
- MEMORY_WRITE, // 1 (1) Write quotient to &W1
- ALU_DIVS, // 0
- PREFETCH, // 1
- MEMORY_WRITE, // 1 (1) Write remainder to &W2
- END
-};
-
-MICROPROGRAM(external_mp)
-{
- ALU_NOP, // 1
- ALU_NOP, // 1
- ALU_NOP, // 1
- ALU_NOP, // 1
- ALU_NOP, // 1
- ALU_EXTERNAL, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(imm_arithm_mp)
-{
- MEMORY_READ, // 1 (1)
- SET_IMM, // 0
- MEMORY_READ, // 1 (1)
- ALU_IMM_ARITHM, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(jump_mp)
-{
- ALU_NOP, // 1
- ALU_JUMP, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(ldcr_mp) // TODO: Verify cycles
-{
- ALU_LDCR, // 1
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1) Get source data
- ALU_LDCR, // 1 Save it, point to R12
- WORD_READ, // 1 (1) Get R12
- ALU_LDCR, // 1 Prepare CRU operation
- CRU_OUTPUT, // c
- ALU_NOP, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(li_mp)
-{
- SET_IMM, // 0
- MEMORY_READ, // 1 (1)
- ALU_LI, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(limi_lwpi_mp)
-{
- SET_IMM, // 0
- MEMORY_READ, // 1 (1)
- ALU_NOP, // 1
- ALU_LIMIWP, // 0 lwpi, 1 limi
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(lst_lwp_mp)
-{
- MEMORY_READ, // 1 (1)
- ALU_NOP, // 1
- ALU_LSTWP, // 0 lwp, 1 lst
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(mov_mp)
-{
- OPERAND_ADDR, // 0
- MEMORY_READ, // 1 (1)
- OPERAND_ADDR, // 0
- ALU_MOV, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(multiply_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- ALU_MPY, // 1
- MEMORY_READ, // 1 (1)
- ALU_MPY, // 17
- MEMORY_WRITE, // 1 (1)
- ALU_MPY, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(rtwp_mp)
-{
- ALU_RTWP, // 1
- MEMORY_READ, // 1 (1)
- ALU_RTWP, // 0
- MEMORY_READ, // 1 (1)
- ALU_RTWP, // 0
- MEMORY_READ, // 1 (1)
- ALU_RTWP, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(sbo_sbz_mp)
-{
- ALU_SBO_SBZ, // 1 Set address = &R12
- WORD_READ, // 1 (1) Read R12
- ALU_SBO_SBZ, // 1 Add offset
- CRU_OUTPUT, // 1 output via CRU
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(shift_mp)
-{
- MEMORY_READ, // 1 (1)
- ALU_SHIFT, // 2 skip next operation if count != 0
- MEMORY_READ, // 1 (1) if count=0 we must read R0
- ALU_SHIFT, // c do the shift
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(single_arithm_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- ALU_SINGLE_ARITHM, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(stcr_mp) // TODO: Verify on real machine
-{
- ALU_STCR, // 1 Check for byte operation
- OPERAND_ADDR, // x Source operand
- ALU_STCR, // 1 Save, set R12
- WORD_READ, // 1 (1) Read R12
- ALU_STCR, // 1
- CRU_INPUT, // c
- ALU_STCR, // 13
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(stst_stwp_mp)
-{
- ALU_STSTWP, // 0
- ALU_NOP, // 1
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(tb_mp)
-{
- ALU_TB, // 1
- WORD_READ, // 1 (1)
- ALU_TB, // 1
- CRU_INPUT, // 2
- ALU_TB, // 0
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(x_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- ALU_X, // 1
- END // should not be reached
-};
-
-MICROPROGRAM(xop_mp)
-{
- OPERAND_ADDR, // x Determine source address
- ALU_XOP, // 1 Save it; determine XOP number
- MEMORY_READ, // 1 (1) Read new WP
- ALU_XOP, // 1
- MEMORY_WRITE, // 1 (1) save source address to new R11
- ALU_XOP, // 1
- MEMORY_WRITE, // 1 (1) save old ST to new R15
- ALU_XOP, // 1
- MEMORY_WRITE, // 1 (1) save old PC to new R14
- ALU_XOP, // 1
- MEMORY_WRITE, // 1 (1) save old WP to new R13
- ALU_XOP, // 1
- MEMORY_READ, // 1 (1) Read new PC
- ALU_XOP, // 0 set new PC, set X flag
- PREFETCH, // 1 (1)
- ALU_NOP, // 1
- ALU_NOP, // 1
- END
-};
-
-MICROPROGRAM(xor_mp)
-{
- OPERAND_ADDR, // x
- MEMORY_READ, // 1 (1)
- ALU_F3, // 0
- MEMORY_READ, // 1 (1)
- ALU_F3, // 0
- PREFETCH, // 1 (1)
- MEMORY_WRITE, // 1 (1)
- END
-};
-
-MICROPROGRAM(int_mp)
-{
- ALU_INT, // 1
- MEMORY_READ, // 1 (1)
- ALU_INT, // 2
- MEMORY_WRITE, // 1 (1)
- ALU_INT, // 1
- MEMORY_WRITE, // 1 (1)
- ALU_INT, // 1
- MEMORY_WRITE, // 1 (1)
- ALU_INT, // 1
- MEMORY_READ, // 1 (1)
- ALU_INT, // 0
- PREFETCH_NO_INT, // 1 (1) (prefetch happens in parallel to the previous operation)
- ALU_NOP, // 1 (+decode in parallel; actually performed right after prefetch)
- ALU_NOP, // 1
- END
-};
-
-const tms9995_device::ophandler tms9995_device::s_microoperation[] =
-{
- &tms9995_device::int_prefetch_and_decode,
- &tms9995_device::prefetch_and_decode,
- &tms9995_device::mem_read,
- &tms9995_device::mem_write,
- &tms9995_device::word_read,
- &tms9995_device::word_write,
- &tms9995_device::operand_address_subprogram,
- &tms9995_device::increment_register,
- &tms9995_device::indexed_addressing,
- &tms9995_device::set_immediate,
- &tms9995_device::return_with_address,
- &tms9995_device::return_with_address_copy,
- &tms9995_device::cru_input_operation,
- &tms9995_device::cru_output_operation,
- &tms9995_device::abort_operation,
- &tms9995_device::command_completed,
-
- &tms9995_device::alu_nop,
- &tms9995_device::alu_add_s_sxc,
- &tms9995_device::alu_b,
- &tms9995_device::alu_blwp,
- &tms9995_device::alu_c,
- &tms9995_device::alu_ci,
- &tms9995_device::alu_clr_seto,
- &tms9995_device::alu_divide,
- &tms9995_device::alu_divide_signed,
- &tms9995_device::alu_external,
- &tms9995_device::alu_f3,
- &tms9995_device::alu_imm_arithm,
- &tms9995_device::alu_jump,
- &tms9995_device::alu_ldcr,
- &tms9995_device::alu_li,
- &tms9995_device::alu_limi_lwpi,
- &tms9995_device::alu_lst_lwp,
- &tms9995_device::alu_mov,
- &tms9995_device::alu_multiply,
- &tms9995_device::alu_rtwp,
- &tms9995_device::alu_sbo_sbz,
- &tms9995_device::alu_shift,
- &tms9995_device::alu_single_arithm,
- &tms9995_device::alu_stcr,
- &tms9995_device::alu_stst_stwp,
- &tms9995_device::alu_tb,
- &tms9995_device::alu_x,
- &tms9995_device::alu_xop,
- &tms9995_device::alu_int
-};
-
-/*****************************************************************************
- CPU instructions
-*****************************************************************************/
-
-/*
- Available instructions
- MID is not a real instruction but stands for an invalid operation which
- triggers a "macro instruction detect" interrupt. Neither is INTR which
- indicates an interrupt handling in progress.
-*/
-enum
-{
- MID=0, A, AB, ABS, AI, ANDI, B, BL, BLWP, C,
- CB, CI, CKOF, CKON, CLR, COC, CZC, DEC, DECT, DIV,
- DIVS, IDLE, INC, INCT, INV, JEQ, JGT, JH, JHE, JL,
- JLE, JLT, JMP, JNC, JNE, JNO, JOC, JOP, LDCR, LI,
- LIMI, LREX, LST, LWP, LWPI, MOV, MOVB, MPY, MPYS, NEG,
- ORI, RSET, RTWP, S, SB, SBO, SBZ, SETO, SLA, SOC,
- SOCB, SRA, SRC, SRL, STCR, STST, STWP, SWPB, SZC, SZCB,
- TB, X, XOP, XOR, INTR
-};
-
-static const char opname[][5] =
-{ "MID ", "A ", "AB ", "ABS ", "AI ", "ANDI", "B ", "BL ", "BLWP", "C ",
- "CB ", "CI ", "CKOF", "CKON", "CLR ", "COC ", "CZC ", "DEC ", "DECT", "DIV ",
- "DIVS", "IDLE", "INC ", "INCT", "INV ", "JEQ ", "JGT ", "JH ", "JHE ", "JL ",
- "JLE ", "JLT ", "JMP ", "JNC ", "JNE ", "JNO ", "JOC ", "JOP ", "LDCR", "LI ",
- "LIMI", "LREX", "LST ", "LWP ", "LWPI", "MOV ", "MOVB", "MPY ", "MPYS", "NEG ",
- "ORI ", "RSET", "RTWP", "S ", "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ",
- "SOCB", "SRA ", "SRC ", "SRL ", "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB",
- "TB ", "X ", "XOP ", "XOR ", "*int"
-};
-
-/*
- Formats:
-
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- ----+------------------------------------------------+
- 1 | Opcode | B | Td | RegNr | Ts | RegNr |
- +--------+---+----+------------+----+------------+
- 2 | Opcode | Displacement |
- +-----------------------+------------------------+
- 3 | Opcode | RegNr | Ts | RegNr |
- +-----------------+------------+----+------------+
- 4 | Opcode | Count | Ts | RegNr |
- +-----------------+------------+----+------------+
- 5 | Opcode | Count | RegNr |
- +-----------------------+-----------+------------+
- 6 | Opcode | Ts | RegNr |
- +------------------------------+----+------------+
- 7 | Opcode |0| 0| 0| 0| 0 |
- +---------------------------------+-+--+--+--+---+
- 8 | Opcode |0| RegNr |
- +---------------------------------+-+------------+
- 9 | Opcode | Reg/Nr | Ts | RegNr |
- +-----------------+------------+----+------------+
- 10 | Opcode | Ts | RegNr | (DIVS, MPYS)
- +------------------------------+----+------------+
- 11 | Opcode | RegNr | (LST, LWP)
- +-----------------------------------+------------+
-*/
-
-/*
- Defines the number of bits from the left which are significant for the
- command in the respective format.
-*/
-static const int format_mask_len[] =
-{
- 0, 4, 8, 6, 6, 8, 10, 16, 12, 6, 10, 12
-};
-
-const tms9995_device::tms_instruction tms9995_device::s_command[] =
-{
- // Base opcode list
- // Opcode, ID, format, microprg
- { 0x0080, LST, 11, lst_lwp_mp },
- { 0x0090, LWP, 11, lst_lwp_mp },
- { 0x0180, DIVS, 10, divide_signed_mp },
- { 0x01C0, MPYS, 10, multiply_mp },
- { 0x0200, LI, 8, li_mp },
- { 0x0220, AI, 8, imm_arithm_mp },
- { 0x0240, ANDI, 8, imm_arithm_mp },
- { 0x0260, ORI, 8, imm_arithm_mp },
- { 0x0280, CI, 8, ci_mp },
- { 0x02a0, STWP, 8, stst_stwp_mp },
- { 0x02c0, STST, 8, stst_stwp_mp },
- { 0x02e0, LWPI, 8, limi_lwpi_mp },
- { 0x0300, LIMI, 8, limi_lwpi_mp },
- { 0x0340, IDLE, 7, external_mp },
- { 0x0360, RSET, 7, external_mp },
- { 0x0380, RTWP, 7, rtwp_mp },
- { 0x03a0, CKON, 7, external_mp },
- { 0x03c0, CKOF, 7, external_mp },
- { 0x03e0, LREX, 7, external_mp },
- { 0x0400, BLWP, 6, blwp_mp },
- { 0x0440, B, 6, b_mp },
- { 0x0480, X, 6, x_mp },
- { 0x04c0, CLR, 6, clr_seto_mp },
- { 0x0500, NEG, 6, single_arithm_mp },
- { 0x0540, INV, 6, single_arithm_mp },
- { 0x0580, INC, 6, single_arithm_mp },
- { 0x05c0, INCT, 6, single_arithm_mp },
- { 0x0600, DEC, 6, single_arithm_mp },
- { 0x0640, DECT, 6, single_arithm_mp },
- { 0x0680, BL, 6, bl_mp },
- { 0x06c0, SWPB, 6, single_arithm_mp },
- { 0x0700, SETO, 6, clr_seto_mp },
- { 0x0740, ABS, 6, single_arithm_mp },
- { 0x0800, SRA, 5, shift_mp },
- { 0x0900, SRL, 5, shift_mp },
- { 0x0a00, SLA, 5, shift_mp },
- { 0x0b00, SRC, 5, shift_mp },
- { 0x1000, JMP, 2, jump_mp },
- { 0x1100, JLT, 2, jump_mp },
- { 0x1200, JLE, 2, jump_mp },
- { 0x1300, JEQ, 2, jump_mp },
- { 0x1400, JHE, 2, jump_mp },
- { 0x1500, JGT, 2, jump_mp },
- { 0x1600, JNE, 2, jump_mp },
- { 0x1700, JNC, 2, jump_mp },
- { 0x1800, JOC, 2, jump_mp },
- { 0x1900, JNO, 2, jump_mp },
- { 0x1a00, JL, 2, jump_mp },
- { 0x1b00, JH, 2, jump_mp },
- { 0x1c00, JOP, 2, jump_mp },
- { 0x1d00, SBO, 2, sbo_sbz_mp },
- { 0x1e00, SBZ, 2, sbo_sbz_mp },
- { 0x1f00, TB, 2, tb_mp },
- { 0x2000, COC, 3, coc_czc_mp },
- { 0x2400, CZC, 3, coc_czc_mp },
- { 0x2800, XOR, 3, xor_mp },
- { 0x2c00, XOP, 3, xop_mp },
- { 0x3000, LDCR, 4, ldcr_mp },
- { 0x3400, STCR, 4, stcr_mp },
- { 0x3800, MPY, 9, multiply_mp },
- { 0x3c00, DIV, 9, divide_mp },
- { 0x4000, SZC, 1, add_s_sxc_mp },
- { 0x5000, SZCB, 1, add_s_sxc_mp },
- { 0x6000, S, 1, add_s_sxc_mp },
- { 0x7000, SB, 1, add_s_sxc_mp },
- { 0x8000, C, 1, c_mp },
- { 0x9000, CB, 1, c_mp },
- { 0xa000, A, 1, add_s_sxc_mp },
- { 0xb000, AB, 1, add_s_sxc_mp },
- { 0xc000, MOV, 1, mov_mp },
- { 0xd000, MOVB, 1, mov_mp },
- { 0xe000, SOC, 1, add_s_sxc_mp },
- { 0xf000, SOCB, 1, add_s_sxc_mp }
-};
-
-/*
- Create a B-tree for looking up the commands. Each node can carry up to
- 16 entries, indexed by 4 consecutive bits in the opcode.
-
- See tms9900.c for a detailed description.
-*/
-void tms9995_device::build_command_lookup_table()
-{
- int i = 0;
- int cmdindex = 0;
- int bitcount;
- const tms_instruction *inst;
- UINT16 opcode;
- int k = 0;
-
- m_command_lookup_table = new lookup_entry[16];
- // We use lotables as a list of allocated tables - to be able to delete them
- // at the end.
- m_lotables[k++] = m_command_lookup_table;
-
- lookup_entry* table = m_command_lookup_table;
- for (int j=0; j < 16; j++)
- {
- table[j].entry = NULL;
- table[j].next_digit = NULL;
- }
-
- do
- {
- inst = &s_command[i];
- table = m_command_lookup_table;
- if (TRACE_EMU) logerror("tms9995: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]);
- bitcount = 4;
- opcode = inst->opcode;
- cmdindex = (opcode>>12) & 0x000f;
-
- while (bitcount < format_mask_len[inst->format])
- {
- // Descend
- if (table[cmdindex].next_digit == NULL)
- {
- if (TRACE_EMU) logerror("tms9995: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex);
- table[cmdindex].next_digit = new lookup_entry[16];
- m_lotables[k++] = table[cmdindex].next_digit;
- for (int j=0; j < 16; j++)
- {
- table[cmdindex].next_digit[j].next_digit = NULL;
- table[cmdindex].next_digit[j].entry = NULL;
- }
- }
- else
- {
- if (TRACE_EMU) logerror("tms9995: found a table at bitcount=%d\n", bitcount);
- }
-
- table = table[cmdindex].next_digit;
-
- bitcount = bitcount+4;
- opcode <<= 4;
- cmdindex = (opcode>>12) & 0x000f;
- if (TRACE_EMU) logerror("tms9995: next index=%x\n", cmdindex);
- }
-
- if (TRACE_EMU) logerror("tms9995: bitcount=%d\n", bitcount);
- // We are at the target level
- // Need to fill in the same entry for all values in the bitcount
- // (if a command needs 10 bits we have to copy it four
- // times for all combinations with 12 bits)
- for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++)
- {
- if (TRACE_EMU) logerror("tms9995: opcode=%04x at position %d\n", inst->opcode, cmdindex+j);
- table[cmdindex+j].entry = inst;
- }
-
- i++;
- } while (inst->opcode != 0xf000);
-
- m_lotables[k++] = NULL;
- if (TRACE_EMU) logerror("tms9995: Allocated %d tables\n", k);
-}
-
-/*
- Main execution loop
-
- For each invocation of execute_run, a number of loop iterations has been
- calculated before (m_icount). Each loop iteration is one clock cycle.
- The loop must be executed for the number of times that corresponds to the
- time until the next timer event.
-*/
-void tms9995_device::execute_run()
-{
- if (m_reset) service_interrupt();
-
- if (TRACE_EMU) logerror("tms9995: calling execute_run for %d cycles\n", m_icount);
- do
- {
- // Normal operation
- if (m_check_ready && m_ready == false)
- {
- // We are in a wait state
- if (TRACE_WAITHOLD) logerror("tms9995: wait state\n");
- // The clock output should be used to change the state of an outer
- // device which operates the READY line
- pulse_clock(1);
- }
- else
- {
- if (m_check_hold && m_hold_state)
- {
- set_hold_state(true);
- if (TRACE_WAITHOLD) logerror("tms9995: hold state\n");
- pulse_clock(1);
- }
- else
- {
- set_hold_state(false);
-
- m_check_ready = false;
-
- if (TRACE_MICRO) logerror("tms9995: main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC);
- (this->*s_microoperation[m_instruction->program[MPC]])();
-
- // For multi-pass operations where the MPC should not advance
- // or when we have put in a new microprogram
- m_pass--;
- if (m_pass<=0)
- {
- m_pass = 1;
- MPC++;
- }
- }
- }
- } while (m_icount>0 && !m_reset);
- if (TRACE_EMU) logerror("tms9995: cycles expired; will return soon.\n");
-}
-
-/**************************************************************************/
-
-/*
- Interrupt input
- output
- m_nmi_state
- m_irq_level
- flag[2], flag[4]
-*/
-void tms9995_device::execute_set_input(int irqline, int state)
-{
- if (irqline==INT_9995_RESET && state==ASSERT_LINE)
- {
- m_reset = true;
- }
- else
- {
- if (irqline == INPUT_LINE_NMI)
- {
- m_nmi_active = (state==ASSERT_LINE);
- if (TRACE_INT) logerror("tms9995: NMI interrupt line state=%d\n", state);
- }
- else
- {
- if (irqline == INT_9995_INT1)
- {
- m_int1_active = m_flag[2] = (state==ASSERT_LINE);
- if (TRACE_INT) logerror("tms9995: Line INT1 state=%d\n", state);
- }
- else
- {
- if (irqline == INT_9995_INT4)
- {
- if (TRACE_INT) logerror("tms9995: Line INT4/EC state=%d\n", state);
- if (m_flag[0]==false)
- {
- if (TRACE_INT) logerror("tms9995: set as interrupt\n");
- m_int4_active = m_flag[4] = (state==ASSERT_LINE);
- }
- else
- {
- if (TRACE_INT) logerror("tms9995: set as event count\n");
- trigger_decrementer();
- }
- }
- else
- {
- logerror("tms9995: Accessed invalid interrupt line %d\n", irqline);
- }
- }
- }
- }
-}
-
-/*
- Issue a pulse on the clock line.
-*/
-void tms9995_device::pulse_clock(int count)
-{
- for (int i=0; i < count; i++)
- {
- if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE);
- m_ready = m_ready_bufd && !m_request_auto_wait_state; // get the latched READY state
- if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE);
- m_icount--; // This is the only location where we count down the cycles.
- if (TRACE_CLOCK)
- {
- if (m_check_ready) logerror("tms9995: pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0);
- else logerror("tms9995: pulse_clock\n");
- }
- m_request_auto_wait_state = false;
- if (m_flag[0] == false && m_flag[1] == true)
- {
- // Section 2.3.1.2.2: "by decreasing the count in the Decrementing
- // Register by one for each fourth CLKOUT cycle"
- m_decrementer_clkdiv = (m_decrementer_clkdiv+1)%4;
- if (m_decrementer_clkdiv==0) trigger_decrementer();
- }
- }
-}
-
-/*
- Enter the hold state.
-*/
-void tms9995_device::set_hold(int state)
-{
- m_hold_state = (state==ASSERT_LINE);
- if (TRACE_WAITHOLD) logerror("tms9995: set HOLD = %d\n", state);
- if (!m_hold_state)
- {
- if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE);
- }
-}
-
-/*
- Signal READY to the CPU. When cleared, the CPU enters wait states. This
- becomes effective on a clock pulse.
-*/
-void tms9995_device::set_ready(int state)
-{
- m_ready_bufd = (state==ASSERT_LINE);
- if (TRACE_READY) logerror("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0);
-}
-
-/*
- When the divide operations fail, we get to this operation.
-*/
-void tms9995_device::abort_operation()
-{
- int_prefetch_and_decode(); // do not forget to prefetch
- // And don't forget that prefetch is a 2-pass operation, so this method
- // will be called a second time. Only when the lowbyte has been fetched,
- // continue with the next step
- if (m_mem_phase==1) command_completed();
-}
-
-/*
- Enter or leave the hold state. We only operate the HOLDA line when there is a change.
-*/
-inline void tms9995_device::set_hold_state(bool state)
-{
- if (m_hold_state != state)
- if (!m_holda_line.isnull()) m_holda_line(state? ASSERT_LINE : CLEAR_LINE);
- m_hold_state = state;
-}
-
-/*
- Decode the instruction. This is done in parallel to other operations
- so we just do it together with the prefetch.
-*/
-void tms9995_device::decode(UINT16 inst)
-{
- int index = 0;
- lookup_entry* table = m_command_lookup_table;
- UINT16 opcode = inst;
- bool complete = false;
- const tms_instruction *decoded;
-
- int dindex = (m_instindex==0)? 1:0;
-
- m_mid_active = false;
-
- while (!complete)
- {
- index = (opcode >> 12) & 0x000f;
- if (TRACE_EMU) logerror("tms9995: Check next hex digit of instruction %x\n", index);
- if (table[index].next_digit != NULL)
- {
- table = table[index].next_digit;
- opcode = opcode << 4;
- }
- else complete = true;
- }
- decoded = table[index].entry;
- if (decoded == NULL)
- {
- // not found
- logerror("tms9995: Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC);
- m_decoded[dindex].IR = 0;
- m_decoded[dindex].command = MID;
- }
- else
- {
- m_decoded[dindex].IR = inst;
- m_decoded[dindex].command = decoded->id;
- m_decoded[dindex].program = decoded->prog;
- m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0));
- m_decoded[dindex].state = 0;
- if (TRACE_EMU) logerror("tms9995: Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode);
- m_pass = 1;
- }
-}
-
-/*
- Fetch the next instruction and check pending interrupts before.
- Getting an instruction is a normal memory access (plus an asserted IAQ line),
- so this is subject to wait state handling. We have to allow for a two-pass
- handling.
-*/
-void tms9995_device::int_prefetch_and_decode()
-{
- bool check_int = (m_instruction->command != XOP && m_instruction->command != BLWP);
- int intmask = ST & 0x000f;
-
- if (m_mem_phase == 1)
- {
- // Check interrupt lines
- if (m_nmi_active)
- {
- if (TRACE_INT) logerror("tms9995: Checking interrupts ... NMI active\n");
- m_int_pending |= PENDING_NMI;
- m_idle_state = false;
- PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction
- return;
- }
- else
- {
- m_int_pending = 0;
-
- if (check_int)
- {
- if (m_int1_active && intmask >= 1) m_int_pending |= PENDING_LEVEL1;
- if (m_int_overflow && intmask >= 2) m_int_pending |= PENDING_OVERFLOW;
- if (m_int_decrementer && intmask >= 3) m_int_pending |= PENDING_DECR;
- if (m_int4_active && intmask >= 4) m_int_pending |= PENDING_LEVEL4;
- }
-
- if (m_int_pending!=0)
- {
- if (m_idle_state)
- {
- m_idle_state = false;
- if (TRACE_INT) logerror("tms9995: Interrupt occurred, terminate IDLE state\n");
- }
- PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch
- if (TRACE_INT) logerror("tms9995: Interrupts pending; no prefetch; advance PC to %04x\n", PC);
- return;
- }
- else
- {
- if (TRACE_INT) logerror("tms9995: Checking interrupts ... none pending\n");
- // No pending interrupts
- if (m_idle_state)
- {
- if (TRACE_WAITHOLD) logerror("tms9995: IDLE state\n");
- // We are IDLE, stay in the loop and do not advance the PC
- m_pass = 2;
- pulse_clock(1);
- return;
- }
- }
- }
- }
-
- // We reach this point in phase 1 if there is no interrupt and in all other phases
- prefetch_and_decode();
-}
-
-/*
- The actual prefetch operation, but without the interrupt check. This one is
- needed when we complete the interrupt handling and need to get the next
- instruction. According to the flow chart in [1], the prefetch after the
- interrupt handling ignores other pending interrupts.
-*/
-void tms9995_device::prefetch_and_decode()
-{
- if (m_mem_phase==1)
- {
- // Fetch next instruction
- // Save these values; they have been computed during the current instruction execution
- m_address_copy = m_address;
- m_value_copy = m_current_value;
- if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE);
- m_address = PC;
- if (TRACE_OP) logerror("tms9995: **** Prefetching new instruction at %04x ****\n", PC);
- }
-
- word_read(); // changes m_mem_phase
-
- if (m_mem_phase==1)
- {
- // We're back in phase 1, i.e. the whole prefetch is done
- decode(m_current_value); // This is for free; in reality it is in parallel with the next memory operation
- m_address = m_address_copy; // restore m_address
- m_current_value = m_value_copy; // restore m_current_value
- PC = (PC + 2) & 0xfffe; // advance PC
- if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE);
- if (TRACE_OP) logerror("tms9995: ++++ Prefetch done ++++\n");
- }
-}
-
-/*
- Used by the normal command completion as well as by the X operation. We
- assume that we have a fully decoded operation which was previously
- prefetched.
-*/
-void tms9995_device::next_command()
-{
- int next = (m_instindex==0)? 1:0;
-
- if (m_decoded[next].command == MID)
- {
- m_mid_flag = true;
- m_mid_active = true;
- service_interrupt();
- }
- else
- {
- m_instindex = next;
- m_instruction = &m_decoded[m_instindex];
- m_get_destination = false;
- // This is a preset for opcodes which do not need an opcode address derivation
- m_address = WP + ((m_instruction->IR & 0x000f)<<1);
- MPC = -1;
- if (TRACE_OP) logerror("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2);
-
- if (TRACE_EXEC)
- {
- if (m_servicing_interrupt) logerror("i%04x\n", PC-2);
- else logerror("%04x\n", PC-2);
- }
- PC_debug = PC - 2;
- debugger_instruction_hook(this, PC_debug);
- m_first_cycle = m_icount;
- }
-}
-
-/*
- End of command execution
-*/
-void tms9995_device::command_completed()
-{
- // Pseudo state at the end of the current instruction cycle sequence
- if (TRACE_CYCLES)
- {
- logerror("tms9995: +++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]);
- int cycles = m_first_cycle - m_icount;
- // Avoid nonsense values due to expired and resumed main loop
- if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles);
- logerror(" +++++\n");
- }
-
- if (m_int_pending != 0)
- {
- service_interrupt();
- }
- else
- {
- if ((ST & ST_OE)!=0 && (ST & ST_OV)!=0 && (ST & 0x000f)>2)
- {
- service_interrupt();
- }
- else
- {
- next_command();
- }
- }
-}
-
-/*
- Handle pending interrupts.
-*/
-void tms9995_device::service_interrupt()
-{
- int vectorpos = 0;
-
- if (m_reset)
- {
- vectorpos = 0;
- m_intmask = 0; // clear interrupt mask
-
- m_nmi_state = false;
- m_hold_state = false;
- m_mem_phase = 1;
- m_check_hold = false;
- m_word_access = false;
- m_int1_active = false;
- m_int4_active = false;
- m_decrementer_clkdiv = 0;
-
- m_pass = 0;
- m_instindex = 0;
- m_instruction = &m_decoded[m_instindex];
-
- memset(m_flag, 0, sizeof(m_flag));
-
- ST = 0;
-
- // The auto-wait state generation is turned on when the READY line is cleared
- // on RESET.
- m_auto_wait = !m_ready_bufd;
- if (TRACE_CONFIG) logerror("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled");
- // We reset the READY flag, or the CPU will not start
- m_ready_bufd = true;
- }
- else
- {
- if (m_mid_active)
- {
- vectorpos = 0x0008;
- m_intmask = 0x0001;
- PC = (PC + 2) & 0xfffe;
- if (TRACE_INT) logerror("tms9995: ***** MID pending\n");
- m_mid_active = false;
- }
- else
- {
- if ((m_int_pending & PENDING_NMI)!=0)
- {
- vectorpos = 0xfffc;
- m_int_pending &= ~PENDING_NMI;
- m_intmask = 0;
- if (TRACE_INT) logerror("tms9995: ***** NMI pending\n");
- }
- else
- {
- if ((m_int_pending & PENDING_LEVEL1)!=0)
- {
- vectorpos = 0x0004;
- m_int_pending &= ~PENDING_LEVEL1;
- m_flag[2] = false;
- m_intmask = 0;
- if (TRACE_INT) logerror("tms9995: ***** INT1 pending\n");
- }
- else
- {
- if ((m_int_pending & PENDING_OVERFLOW)!=0)
- {
- vectorpos = 0x0008;
- m_int_pending &= ~PENDING_OVERFLOW;
- m_intmask = 0x0001;
- if (TRACE_INT) logerror("tms9995: ***** OVERFL pending\n");
- }
- else
- {
- if ((m_int_pending & PENDING_DECR)!=0)
- {
- vectorpos = 0x000c;
- m_intmask = 0x0002;
- m_int_pending &= ~PENDING_DECR;
- m_flag[3] = false;
- m_int_decrementer = false;
- if (TRACE_DEC) logerror("tms9995: ***** DECR pending\n");
- }
- else
- {
- vectorpos = 0x0010;
- m_intmask = 0x0003;
- m_int_pending &= ~PENDING_LEVEL4;
- m_flag[4] = false;
- if (TRACE_INT) logerror("tms9995: ***** INT4 pending\n");
- }
- }
- }
- }
- }
- }
-
- if (TRACE_INT) logerror("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2);
-
- // just for debugging purposes
- m_servicing_interrupt = true;
-
- // The microinstructions will do the context switch
- m_address = vectorpos;
- m_instruction->program = int_mp;
- m_instruction->state = 0;
- m_instruction->byteop = false;
- m_instruction->command = INTR;
- m_pass = m_reset? 1 : 2;
- m_from_reset = m_reset;
-
- if (m_reset)
- {
- m_instruction->IR = 0x0000;
- m_reset = false;
- }
- MPC = 0;
- m_first_cycle = m_icount;
- m_check_ready = false; // set to default
-}
-
-/*
- Read memory. This method expects as input m_address, and delivers the value
- in m_current_value. For a single byte read, the byte is put into the high byte.
- This method uses the m_pass variable to achieve a two-pass handling for
- getting the complete word (high byte, low byte).
-
- input:
- m_address
- m_lowbyte
- output:
- m_current_value
-
- m_address is unchanged
-
- Make sure that m_lowbyte is false on the first call.
-*/
-void tms9995_device::mem_read()
-{
- // First determine whether the memory is inside the CPU
- // On-chip memory is F000 ... F0F9, F0FA-FFF9 = off-chip, FFFA/B = Decrementer
- // FFFC-FFFF = NMI vector (on-chip)
- // There is a variant of the TMS9995 with no on-chip RAM which was used
- // for the TI-99/8 (9537).
-
- if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
- {
- if (TRACE_DEC) logerror("tms9995: read decrementer\n");
- // Decrementer mapped into the address space
- m_current_value = m_decrementer_value;
- if (m_instruction->byteop)
- {
- if ((m_address & 1)!=1) m_current_value <<= 8;
- m_current_value &= 0xff00;
- }
- pulse_clock(1);
- return;
- }
-
- if (is_onchip(m_address))
- {
- // If we have a word access, we have to align the address
- // This is the case for word operations and for certain phases of
- // byte operations (e.g. when retrieving the index register)
- if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
-
- if (TRACE_MEM) logerror("tms9995: read onchip memory (single pass, address %04x)\n", m_address);
-
- // Ignore the READY state
- m_check_ready = false;
- // We put fffc-ffff back into the f000-f0ff area
- m_current_value = m_onchip_memory[m_address & 0x00ff]<<8;
- if (m_word_access || !m_instruction->byteop)
- {
- // We have a word operation; add the low byte right here (just 1 cycle)
- m_current_value |= (m_onchip_memory[(m_address & 0x00ff)+1] & 0xff);
- }
- pulse_clock(1);
- }
- else
- {
- // This is an off-chip access
- m_check_ready = true;
- UINT8 value;
- UINT16 address = m_address;
-
- switch (m_mem_phase)
- {
- case 1:
- // Set address
- // If this is a word access, 4 passes, else 2 passes
- if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE);
- if (m_word_access || !m_instruction->byteop)
- {
- m_pass = 4;
- // For word accesses, we always start at the even address
- address &= 0xfffe;
- }
- else m_pass = 2;
-
- m_check_hold = false;
- if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address & ~1);
- m_prgspace->set_address(address);
- m_request_auto_wait_state = m_auto_wait;
- pulse_clock(1);
- break;
- case 2:
- // Sample the value on the data bus (high byte)
- if (m_word_access || !m_instruction->byteop) address &= 0xfffe;
- value = m_prgspace->read_byte(address);
- if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x\n", m_address & ~1, value);
- m_current_value = (value << 8) & 0xff00;
- break;
- case 3:
- // Set address + 1 (unless byte command)
- if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1);
- m_prgspace->set_address(m_address | 1);
- pulse_clock(1);
- break;
- case 4:
- // Read low byte
- value = m_prgspace->read_byte(m_address | 1);
- m_current_value |= value;
- if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value);
- m_check_hold = true;
- break;
- }
-
- m_mem_phase = (m_mem_phase % 4) +1;
-
- // Reset to 1 when we are done
- if (m_pass==1) m_mem_phase = 1;
- }
-}
-
-/*
- Read a word. This is independent of the byte flag of the instruction.
- We need this variant especially when we have to retrieve a register value
- in indexed addressing within a byte-oriented operation.
-*/
-inline void tms9995_device::word_read()
-{
- m_word_access = true;
- mem_read();
- m_word_access = false;
-}
-
-/*
- Write memory. This method expects as input m_address and m_current_value.
- For a single byte write, the byte to be written is expected to be in the
- high byte of m_current_value.
- This method uses the m_pass variable to achieve a two-pass handling for
- writing the complete word (high byte, low byte).
-
- input:
- m_address
- m_lowbyte
- m_current_value
-
- output:
- -
- m_address is unchanged
-
- Make sure that m_lowbyte is false on the first call.
-*/
-void tms9995_device::mem_write()
-{
- if ((m_address & 0xfffe)==0xfffa && !m_mp9537)
- {
- if (m_instruction->byteop)
- {
- // According to [1], section 2.3.1.2.2:
- // "The decrementer should always be accessed as a full word. [...]
- // Writing a single byte to either of the bytes of the decrementer
- // will result in the data byte being written into the byte specifically addressed
- // and random bits being written into the other byte of the decrementer."
-
- // So we just don't care about the low byte.
- if (m_address == 0xfffb) m_current_value >>= 8;
-
- // dito: "This also loads the Decrementing Register with the same count."
- m_starting_count_storage_register = m_decrementer_value = m_current_value;
- }
- else
- {
- m_starting_count_storage_register = m_decrementer_value = m_current_value;
- }
- if (TRACE_DEC) logerror("tms9995: Setting decrementer to %04x, PC=%04x\n", m_current_value, PC);
- pulse_clock(1);
- return;
- }
-
- if (is_onchip(m_address))
- {
- // If we have a word access, we have to align the address
- // This is the case for word operations and for certain phases of
- // byte operations (e.g. when retrieving the index register)
- if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe;
-
- if (TRACE_MEM) logerror("tms9995: write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value);
- m_check_ready = false;
- m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff;
- if (m_word_access || !m_instruction->byteop)
- {
- m_onchip_memory[(m_address & 0x00ff)+1] = m_current_value & 0xff;
- }
- pulse_clock(1);
- }
- else
- {
- // This is an off-chip access
- m_check_ready = true;
- UINT16 address = m_address;
- switch (m_mem_phase)
- {
- case 1:
- // Set address
- // If this is a word access, 4 passes, else 2 passes
- if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE);
-
- if (m_word_access || !m_instruction->byteop)
- {
- m_pass = 4;
- address &= 0xfffe;
- }
- else m_pass = 2;
-
- m_check_hold = false;
- if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", address);
- m_prgspace->set_address(address);
- if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff);
- m_prgspace->write_byte(address, (m_current_value >> 8)&0xff);
- pulse_clock(1);
- break;
-
- case 2:
- // no action here, just wait for READY
- break;
- case 3:
- // Set address + 1 (unless byte command)
- if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1);
- m_prgspace->set_address(m_address | 1);
- if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff);
- m_prgspace->write_byte(m_address | 1, m_current_value & 0xff);
- pulse_clock(1);
- break;
- case 4:
- // no action here, just wait for READY
- m_check_hold = true;
- break;
- }
-
- m_mem_phase = (m_mem_phase % 4) +1;
-
- // Reset to 1 when we are done
- if (m_pass==1) m_mem_phase = 1;
- }
-}
-
-/*
- Write a word. This is independent of the byte flag of the instruction.
-*/
-inline void tms9995_device::word_write()
-{
- m_word_access = true;
- mem_write();
- m_word_access = false;
-}
-
-/*
- Returns from the operand address derivation.
-*/
-void tms9995_device::return_with_address()
-{
- // Return from operand address derivation
- // The result should be in m_address
- m_instruction->program = m_caller;
- MPC = m_caller_MPC; // will be increased on return
- m_address = m_current_value + m_address_add;
- if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation +++\n");
- // no clock pulse
-}
-
-/*
- Returns from the operand address derivation, but using the saved address.
- This is required when we use the auto-increment feature.
-*/
-void tms9995_device::return_with_address_copy()
-{
- // Return from operand address derivation
- m_instruction->program = m_caller;
- MPC = m_caller_MPC; // will be increased on return
- m_address = m_address_saved;
- if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation (auto inc) +++\n");
- // no clock pulse
-}
-
-/*
- CRU support code
- See common explanations in tms9900.c
-
- The TMS9995 CRU address space is larger than the CRU space of the TMS9900:
- 0000-fffe (even addresses) instead of 0000-1ffe. Unlike the TMS9900, the
- 9995 uses the data bus lines D0-D2 to indicate external operations.
-
- Internal CRU locations (read/write)
- -----------------------------------
- 1EE0 Flag 0 Decrementer as event counter
- 1EE2 Flag 1 Decrementer enable
- 1EE4 Flag 2 Level 1 interrupt present (read only, also set when interrupt mask disallows interrupts)
- 1EE6 Flag 3 Level 3 interrupt present (see above)
- 1EE8 Flag 4 Level 4 interrupt present (see above)
- ...
- 1EFE Flag 15
- 1FDA MID flag (only indication, does not trigger when set)
-
- The TMS9995 allows for wait states during external CRU access. Therefore
- we read one block of 8 bits in one go (as given by the MESS architecture)
- but we do iterations for each bit, checking every time for the READY line
- in the main loop.
-
- (write)
- m_cru_output
- m_cru_address
- m_cru_value
- m_count
-
-*/
-
-#define CRUREADMASK 0x0fff
-#define CRUWRITEMASK 0x7fff
-
-void tms9995_device::cru_output_operation()
-{
- if (TRACE_CRU) logerror("tms9995: CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01);
-
- if (m_cru_address == 0x1fda)
- {
- // [1], section 2.3.3.2.2: "setting the MID flag to one with a CRU instruction
- // will not cause the MID interrupt to be requested."
- m_check_ready = false;
- m_mid_flag = (m_cru_value & 0x01);
- }
- else
- {
- if ((m_cru_address & 0xffe0) == 0x1ee0)
- {
- m_check_ready = false;
- // FLAG2, FLAG3, and FLAG4 are read-only
- if (TRACE_CRU) logerror("tms9995: set CRU address %04x to %d\n", m_cru_address, m_cru_value&1);
- if ((m_cru_address != 0x1ee4) && (m_cru_address != 0x1ee6) && (m_cru_address != 0x1ee8))
- m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01);
- }
- else
- {
- // External access
- m_check_ready = true;
- }
- }
-
- // All CRU write operations are visible to the outside world, even when we
- // have internal access. This makes it possible to assign special
- // functions to the internal flag bits which are realized outside
- // of the CPU. However, no wait states are generated for internal
- // accesses. ([1], section 2.3.3.2)
-
- m_cru->write_byte((m_cru_address >> 1)& CRUWRITEMASK, (m_cru_value & 0x01));
- m_cru_value >>= 1;
- m_cru_address = (m_cru_address + 2) & 0xfffe;
- m_count--;
-
- // Repeat this operation
- m_pass = (m_count > 0)? 2 : 1;
- pulse_clock(2);
-}
-
-/*
- Input: (read)
- m_cru_multi_first
- m_cru_address
- Output:
- m_cru_value (right-shifted; i.e. first bit is LSB of the 16 bit word,
- also for byte operations)
-*/
-
-void tms9995_device::cru_input_operation()
-{
- UINT16 crubit;
- UINT8 crubyte;
-
- // Reading is different, since MESS uses 8 bit transfers
- // We read 8 bits in one go, then iterate another min(n-1,7) times to allow
- // for wait states.
-
- // read_byte for CRU delivers the first bit on the rightmost position
-
- int offset = (m_cru_address>>1) & 0x07;
-
- if (m_cru_first_read || m_cru_bits_left == 0)
- {
- // Read next 8 bits
- // 00000000 0rrrrrrr r
- // v
- // ........ ........ X....... ........
- //
- crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK);
- if (TRACE_DETAIL) logerror("tms9995: Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte);
- m_cru_read = crubyte << 15;
- m_cru_bits_left = 8;
-
- if (m_cru_first_read)
- {
- m_cru_read >>= offset;
- m_cru_bits_left -= offset;
- m_parity = 0;
- m_cru_value = 0;
- m_cru_first_read = false;
- m_pass = m_count;
- }
- if (TRACE_DETAIL) logerror("tms9995: adjusted value for shift: %06x\n", m_cru_read);
- }
-
- crubit = (m_cru_read & 0x8000);
- m_cru_value = (m_cru_value >> 1) & 0x7fff;
-
- // During internal reading, the CRUIN line will be ignored. We emulate this
- // by overwriting the bit which we got from outside. Also, READY is ignored.
- if (m_cru_address == 0x1fda)
- {
- crubit = m_mid_flag? 0x8000 : 0x0000;
- m_check_ready = false;
- }
- else
- {
- if ((m_cru_address & 0xffe0)==0x1ee0)
- {
- crubit = (m_flag[(m_cru_address>>1)&0x000f]==true)? 0x8000 : 0x0000;
- m_check_ready = false;
- }
- else
- {
- m_check_ready = true;
- }
- }
-
- if (TRACE_CRU) logerror("tms9995: CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15);
-
- m_cru_value |= crubit;
- if (crubit!=0) m_parity++;
-
- m_cru_address = (m_cru_address + 2) & 0xfffe;
- m_cru_bits_left--;
-
- if (m_pass > 1)
- {
- m_cru_read >>= 1;
- }
- else
- {
- // This is the final shift. For both byte and word length transfers,
- // the first bit is always m_cru_value & 0x0001.
- m_cru_value >>= (16 - m_count);
- }
- pulse_clock(2);
-}
-
-/*
- Decrementer.
-*/
-void tms9995_device::trigger_decrementer()
-{
- if (m_starting_count_storage_register>0) // null will turn off the decrementer
- {
- m_decrementer_value--;
- if (m_decrementer_value==0)
- {
- if (TRACE_DEC) logerror("tms9995: decrementer reached 0\n");
- m_decrementer_value = m_starting_count_storage_register;
- if (m_flag[1]==true)
- {
- if (TRACE_DEC) logerror("tms9995: decrementer flags interrupt\n");
- m_flag[3] = true;
- m_int_decrementer = true;
- }
- }
- }
-}
-
-/*
- This is a switch to a subprogram. In terms of cycles
- it does not take any time; execution continues with the first instruction
- of the subprogram.
-
- input:
- m_get_destination
- m_instruction
- WP
- m_current_value
- m_address
- output:
- m_source_value = m_current_value before invocation
- m_current_value = m_address
- m_address_add = 0
- m_lowbyte = false
- m_get_destination = true
- m_regnumber = register number
- m_address = address of register
- */
-void tms9995_device::operand_address_subprogram()
-{
- UINT16 ircopy = m_instruction->IR;
- if (m_get_destination) ircopy = ircopy >> 6;
-
- // Save the return program and position
- m_caller = m_instruction->program;
- m_caller_MPC = MPC;
-
- m_instruction->program = (UINT8*)operand_address_derivation;
- MPC = (ircopy & 0x0030) >> 2;
- m_regnumber = (ircopy & 0x000f);
- m_address = (WP + (m_regnumber<<1)) & 0xffff;
-
- m_source_value = m_current_value; // will be overwritten when reading the destination
- m_current_value = m_address; // needed for first case
-
- if (MPC==8) // Symbolic
- {
- if (m_regnumber != 0)
- {
- if (TRACE_DETAIL) logerror("tms9995: indexed addressing\n");
- MPC = 16; // indexed
- }
- else
- {
- if (TRACE_DETAIL) logerror("tms9995: symbolic addressing\n");
- m_address = PC;
- PC = (PC + 2) & 0xfffe;
- }
- }
-
- m_get_destination = true;
- m_mem_phase = 1;
- m_address_add = 0;
- MPC--; // will be increased in the mail loop
- if (TRACE_DETAIL) logerror("tms9995: *** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1);
-}
-
-/*
- Used for register auto-increment. We have to save the address read from the
- register content so that we can return it at the end.
-*/
-void tms9995_device::increment_register()
-{
- m_address_saved = m_current_value; // need a special return so we do not lose the value
- m_current_value += m_instruction->byteop? 1 : 2;
- m_address = (WP + (m_regnumber<<1)) & 0xffff;
- m_mem_phase = 1;
- pulse_clock(1);
-}
-
-/*
- Used for indexed addressing. We store the contents of the index register
- in m_address_add which is set to 0 by default. Then we set the address
- pointer to the PC location and advance it.
-*/
-void tms9995_device::indexed_addressing()
-{
- m_address_add = m_current_value;
- m_address = PC;
- PC = (PC + 2) & 0xfffe;
- m_mem_phase = 1;
- pulse_clock(1);
-}
-
-void tms9995_device::set_immediate()
-{
- // Need to determine the register address
- m_address_saved = WP + ((m_instruction->IR & 0x000f)<<1);
- m_address = PC;
- m_source_value = m_current_value; // needed for AI, ANDI, ORI
- PC = (PC + 2) & 0xfffe;
- m_mem_phase = 1;
-}
-
-/**************************************************************************
- Status bit operations
-**************************************************************************/
-
-inline void tms9995_device::set_status_bit(int bit, bool state)
-{
- if (state) ST |= bit;
- else ST &= ~bit;
- m_int_overflow = (m_check_overflow && bit == ST_OV && ((ST & ST_OE)!=0) && state == true);
-}
-
-void tms9995_device::set_status_parity(UINT8 value)
-{
- int count = 0;
- for (int i=0; i < 8; i++)
- {
- if ((value & 0x80)!=0) count++;
- value <<= 1;
- }
- set_status_bit(ST_OP, (count & 1)!=0);
-}
-
-inline void tms9995_device::compare_and_set_lae(UINT16 value1, UINT16 value2)
-{
- set_status_bit(ST_EQ, value1 == value2);
- set_status_bit(ST_LH, value1 > value2);
- set_status_bit(ST_AGT, (INT16)value1 > (INT16)value2);
-}
-
-/**************************************************************************
- ALU operations. The activities as implemented here are performed
- during the internal operations of the CPU, according to the current
- instruction.
-
- Some ALU operations are followed by the prefetch operation. In fact,
- this prefetch happens in parallel to the ALU operation. In these
- situations we do not pulse the clock here but leave this to the prefetch
- operation.
-**************************************************************************/
-
-void tms9995_device::alu_nop()
-{
- // Do nothing (or nothing that is externally visible)
- pulse_clock(1);
- return;
-}
-
-void tms9995_device::alu_add_s_sxc()
-{
- // We have the source operand value in m_source_value and the destination
- // value in m_current_value
- // The destination address is still in m_address
- // Prefetch will not change m_current_value and m_address
-
- UINT32 dest_new = 0;
-
- switch (m_instruction->command)
- {
- case A:
- case AB:
- // When adding, a carry occurs when we exceed the 0xffff value.
- dest_new = m_current_value + m_source_value;
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
-
- // If the result has a sign bit that is different from both arguments, we have an overflow
- // (i.e. getting a negative value from two positive values and vice versa)
- set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0);
- break;
- case S:
- case SB:
- dest_new = m_current_value + ((~m_source_value) & 0xffff) + 1;
- // Subtraction means adding the 2s complement, so the carry bit
- // is set whenever adding the 2s complement exceeds ffff
- // In fact the CPU adds the one's complement, then adds a one. This
- // explains why subtracting 0 sets the carry bit.
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
-
- // If the arguments have different sign bits and the result has a
- // sign bit different from the destination value, we have an overflow
- // e.g. value1 = 0x7fff, value2 = 0xffff; value1-value2 = 0x8000
- // or value1 = 0x8000, value2 = 0x0001; value1-value2 = 0x7fff
- // value1 is the destination value
- set_status_bit(ST_OV, (m_current_value ^ m_source_value) & (m_current_value ^ dest_new) & 0x8000);
- break;
- case SOC:
- case SOCB:
- dest_new = m_current_value | m_source_value;
- break;
-
- case SZC:
- case SZCB:
- dest_new = m_current_value & ~m_source_value;
- break;
- }
-
- m_current_value = (UINT16)(dest_new & 0xffff);
-
- compare_and_set_lae((UINT16)(dest_new & 0xffff),0);
- if (m_instruction->byteop)
- {
- set_status_parity((UINT8)(dest_new>>8));
- }
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- // No clock pulse (will be done by prefetch)
-}
-
-/*
- Branch / Branch and link. We put the source address into the PC after
- copying the PC into m_current_value. The address is R11. The B instruction
- will just ignore these settings, but BL will use them.
-*/
-void tms9995_device::alu_b()
-{
- m_current_value = PC;
- PC = m_address & 0xfffe;
- m_address = WP + 22;
-}
-
-/*
- Branch and load workspace pointer. This is a branch to a subprogram with
- context switch.
-*/
-void tms9995_device::alu_blwp()
-{
- int n = 1;
- switch (m_instruction->state)
- {
- case 0:
- // new WP in m_current_value
- m_value_copy = WP;
- WP = m_current_value & 0xfffe;
- m_address_saved = m_address + 2;
- m_address = WP + 30;
- m_current_value = ST;
- break;
- case 1:
- m_current_value = PC;
- m_address = m_address - 2;
- break;
- case 2:
- m_current_value = m_value_copy; // old WP
- m_address = m_address - 2;
- break;
- case 3:
- m_address = m_address_saved;
- break;
- case 4:
- PC = m_current_value & 0xfffe;
- n = 0;
- if (TRACE_OP) logerror("tms9995: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
- break;
- }
- m_instruction->state++;
- pulse_clock(n);
-}
-
-/*
- Compare is similar to add, s, soc, szc, but we do not write a result.
-*/
-void tms9995_device::alu_c()
-{
- // We have the source operand value in m_source_value and the destination
- // value in m_current_value
- // The destination address is still in m_address
- // Prefetch will not change m_current_value and m_address
- if (m_instruction->byteop)
- {
- set_status_parity((UINT8)(m_source_value>>8));
- }
- compare_and_set_lae(m_source_value, m_current_value);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value);
-}
-
-/*
- Compare with immediate value.
-*/
-void tms9995_device::alu_ci()
-{
- // We have the register value in m_source_value, the register address in m_address_saved
- // and the immediate value in m_current_value
- compare_and_set_lae(m_source_value, m_current_value);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value);
-}
-
-void tms9995_device::alu_clr_seto()
-{
- if (TRACE_OP) logerror("tms9995: clr/seto: Setting values for address %04x\n", m_address);
- switch (m_instruction->command)
- {
- case CLR:
- m_current_value = 0;
- break;
- case SETO:
- m_current_value = 0xffff;
- break;
- }
- // No clock pulse, as next instruction is prefetch
-}
-
-/*
- Unsigned division.
-*/
-void tms9995_device::alu_divide()
-{
- int n=1;
- UINT32 uval32;
-
- bool overflow = true;
- UINT16 value1;
-
- switch (m_instruction->state)
- {
- case 0:
- m_source_value = m_current_value;
- // Set address of register
- m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
- m_address_copy = m_address;
- break;
- case 1:
- // Value of register is in m_current_value
- // We have an overflow when the quotient cannot be stored in 16 bits
- // This is the case when the dividend / divisor >= 0x10000,
- // or equivalently, dividend / 0x10000 >= divisor
-
- // Check overflow for unsigned DIV
- if (m_current_value < m_source_value) // also if source=0
- {
- MPC++; // skip the abort
- overflow = false;
- }
- set_status_bit(ST_OV, overflow);
- m_value_copy = m_current_value; // Save the high word
- m_address = m_address + 2;
- break;
- case 2:
- // W2 is in m_current_value
- uval32 = (m_value_copy << 16) | m_current_value;
- // Calculate
- // The number of ALU cycles depends on the number of steps in
- // the division algorithm. The number of cycles is between 1 and 16
- // As in TMS9900, this is a guess; it depends on the actual algorithm
- // used in the chip.
-
- m_current_value = uval32 / m_source_value;
- m_value_copy = uval32 % m_source_value;
- m_address = m_address_copy;
-
- value1 = m_value_copy & 0xffff;
- while (value1 != 0)
- {
- value1 = (value1 >> 1) & 0xffff;
- n++;
- }
-
- break;
- case 3:
- // now write the remainder
- m_current_value = m_value_copy;
- m_address = m_address + 2;
- break;
- }
- m_instruction->state++;
- pulse_clock(n);
-}
-
-/*
- Signed Division
- We cannot handle this by the same ALU operation because we can NOT decide
- whether there is an overflow before we have retrieved the whole 32 bit
- word. Also, the overflow detection is pretty complicated for signed
- division when done before the actual calculation.
-*/
-void tms9995_device::alu_divide_signed()
-{
- int n=1;
- bool overflow = true;
- UINT16 w1, w2, dwait;
- INT16 divisor;
- INT32 dividend;
-
- switch (m_instruction->state)
- {
- case 0:
- // Got the source value (divisor)
- m_source_value = m_current_value;
- m_address = WP; // DIVS always uses R0,R1
- break;
- case 1:
- // Value of register is in m_current_value
- m_value_copy = m_current_value;
- m_address += 2;
- break;
- case 2:
- // Now we have the dividend low word in m_current_value,
- // the dividend high word in m_value_copy, and
- // the divisor in m_source_value.
-
- w1 = m_value_copy;
- w2 = m_current_value;
- divisor = m_source_value;
- dividend = w1 << 16 | w2;
-
- // Now check for overflow
- // We need to go for four cases
- // if the divisor is not 0 anyway
- if (divisor != 0)
- {
- if (dividend >= 0)
- {
- if (divisor > 0)
- {
- overflow = (dividend > ((divisor<<15) - 1));
- }
- else
- {
- overflow = (dividend > (((-divisor)<<15) + (-divisor) - 1));
- }
- }
- else
- {
- if (divisor > 0)
- {
- overflow = ((-dividend) > ((divisor<<15) + divisor - 1));
- }
- else
- {
- overflow = ((-dividend) > (((-divisor)<<15) - 1));
- }
- }
- }
- else
- {
- overflow = true; // divisor is 0
- }
- set_status_bit(ST_OV, overflow);
- if (!overflow) MPC++; // Skip the next microinstruction when there is no overflow
- break;
- case 3:
- // We are here because there was no overflow
- dividend = m_value_copy << 16 | m_current_value;
- // Do the calculation
- m_current_value = (UINT16)(dividend / (INT16)m_source_value);
- m_value_copy = (UINT16)(dividend % (INT16)m_source_value);
- m_address = WP;
-
- // As we have not implemented the real division algorithm we must
- // simulate the number of steps required for calculating the result.
- // This is just a guess.
- dwait = m_value_copy;
- while (dwait != 0)
- {
- dwait = (dwait >> 1) & 0xffff;
- n++;
- }
- // go write the quotient into R0
- break;
- case 4:
- // Now write the remainder
- m_current_value = m_value_copy;
- m_address += 2;
- n = 0;
- break;
- }
- m_instruction->state++;
- pulse_clock(n);
-}
-
-/*
- External operations.
-*/
-void tms9995_device::alu_external()
-{
- // Call some possibly attached external device
- // A specific bit pattern is put on the data bus, and the CRUOUT line is
- // pulsed. In our case we use a special callback function since we cannot
- // emulate this behavior in this implementation.
-
- // Opcodes D012 value
- // -----------------vvv------
- // IDLE = 0000 0011 0100 0000
- // RSET = 0000 0011 0110 0000
- // CKON = 0000 0011 1010 0000
- // CKOF = 0000 0011 1100 0000
- // LREX = 0000 0011 1110 0000
-
- // Only IDLE has a visible effect on the CPU without external support: the
- // CPU will stop execution until an interrupt occurs. CKON, CKOF, LREX have
- // no effect without external support. Neither has RSET, it does *not*
- // cause a reset of the CPU or of the remaining computer system.
- // It only clears the interrupt mask and outputs the
- // external code on the data bus. A special line decoder could then trigger
- // a reset from outside.
-
- if (m_instruction->command == IDLE)
- {
- if (TRACE_OP) logerror("tms9995: Entering IDLE state\n");
- m_idle_state = true;
- }
-
- if (m_instruction->command == RSET)
- {
- ST &= 0xfff0;
- if (TRACE_OP) logerror("tms9995: RSET, new ST = %04x\n", ST);
- }
-
- if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff);
-}
-
-/*
- Logical compare and XOR
-*/
-void tms9995_device::alu_f3()
-{
- switch (m_instruction->state)
- {
- case 0:
- // We have the contents of the source in m_current_value and its address
- // in m_address
- m_source_value = m_current_value;
- // Get register address
- m_address = WP + ((m_instruction->IR >> 5) & 0x001e);
- break;
- case 1:
- // Register contents -> m_current_value
- // Source contents -> m_source_value
- if (m_instruction->command == COC)
- {
- set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value);
- }
- else
- {
- if (m_instruction->command == CZC)
- {
- set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value);
- }
- else
- {
- // XOR
- // The workspace register address is still in m_address
- m_current_value = (m_current_value ^ m_source_value);
- compare_and_set_lae(m_current_value, 0);
- }
- }
- if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST);
- break;
- }
- m_instruction->state++;
-}
-
-/*
- Handles AI, ANDI, ORI.
-*/
-void tms9995_device::alu_imm_arithm()
-{
- UINT32 dest_new = 0;
-
- // We have the register value in m_source_value, the register address in m_address_saved
- // and the immediate value in m_current_value
- switch (m_instruction->command)
- {
- case AI:
- dest_new = m_current_value + m_source_value;
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
-
- // If the result has a sign bit that is different from both arguments, we have an overflow
- // (i.e. getting a negative value from two positive values and vice versa)
- set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0);
- break;
- case ANDI:
- dest_new = m_current_value & m_source_value;
- break;
- case ORI:
- dest_new = m_current_value | m_source_value;
- break;
- }
-
- m_current_value = (UINT16)(dest_new & 0xffff);
- compare_and_set_lae(m_current_value, 0);
- m_address = m_address_saved;
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
-}
-
-/*
- Handles all jump instructions.
-*/
-void tms9995_device::alu_jump()
-{
- bool cond = false;
- INT8 displacement = (m_instruction->IR & 0xff);
-
- switch (m_instruction->command)
- {
- case JMP:
- cond = true;
- break;
- case JLT: // LAECOP == x00xxx
- cond = ((ST & (ST_AGT | ST_EQ))==0);
- break;
- case JLE: // LAECOP == 0xxxxx
- cond = ((ST & ST_LH)==0);
- break;
- case JEQ: // LAECOP == xx1xxx
- cond = ((ST & ST_EQ)!=0);
- break;
- case JHE: // LAECOP == 1x0xxx, 0x1xxx
- cond = ((ST & (ST_LH | ST_EQ)) != 0);
- break;
- case JGT: // LAECOP == x1xxxx
- cond = ((ST & ST_AGT)!=0);
- break;
- case JNE: // LAECOP == xx0xxx
- cond = ((ST & ST_EQ)==0);
- break;
- case JNC: // LAECOP == xxx0xx
- cond = ((ST & ST_C)==0);
- break;
- case JOC: // LAECOP == xxx1xx
- cond = ((ST & ST_C)!=0);
- break;
- case JNO: // LAECOP == xxxx0x
- cond = ((ST & ST_OV)==0);
- break;
- case JL: // LAECOP == 0x0xxx
- cond = ((ST & (ST_LH | ST_EQ)) == 0);
- break;
- case JH: // LAECOP == 1xxxxx
- cond = ((ST & ST_LH)!=0);
- break;
- case JOP: // LAECOP == xxxxx1
- cond = ((ST & ST_OP)!=0);
- break;
- }
-
- if (!cond)
- {
- if (TRACE_OP) logerror("tms9995: Jump condition false\n");
- }
- else
- {
- if (TRACE_OP) logerror("tms9995: Jump condition true\n");
- PC = (PC + (displacement<<1)) & 0xfffe;
- }
-}
-
-/*
- Implements LDCR.
-*/
-void tms9995_device::alu_ldcr()
-{
- switch (m_instruction->state)
- {
- case 0:
- m_count = (m_instruction->IR >> 6) & 0x000f;
- if (m_count==0) m_count = 16;
- m_instruction->byteop = (m_count<9);
- break;
- case 1:
- // We have read the byte or word into m_current_value.
- compare_and_set_lae(m_current_value, 0);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- if (m_instruction->byteop)
- {
- m_current_value = (m_current_value>>8) & 0xff;
- set_status_parity((UINT8)m_current_value);
- }
- m_cru_value = m_current_value;
- m_address = WP + 24;
- break;
- case 2:
- // Prepare CRU operation
- m_cru_address = m_current_value;
- break;
- }
- m_instruction->state++;
- pulse_clock(1);
-}
-
-/*
- Implements LI. Almost everything has been done in the microprogram;
- this part is reached with m_address_saved = register address,
- and m_current_value = *m_address;
-*/
-void tms9995_device::alu_li()
-{
- // Retrieve the address of the register
- // The immediate value is still in m_current_value
- m_address = m_address_saved;
- compare_and_set_lae(m_current_value, 0);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
-}
-
-void tms9995_device::alu_limi_lwpi()
-{
- // The immediate value is in m_current_value
- if (m_instruction->command == LIMI)
- {
- ST = (ST & 0xfff0) | (m_current_value & 0x000f);
- if (TRACE_OP) logerror("tms9995: LIMI sets ST = %04x\n", ST);
- pulse_clock(1); // needs one more than LWPI
- }
- else
- {
- WP = m_current_value & 0xfffe;
- if (TRACE_OP) logerror("tms9995: LWPI sets new WP = %04x\n", WP);
- }
-}
-
-/*
- Load status and load workspace pointer. This is a TMS9995-specific
- operation.
-*/
-void tms9995_device::alu_lst_lwp()
-{
- if (m_instruction->command==LST)
- {
- ST = m_current_value;
- if (TRACE_OP) logerror("tms9995: new ST = %04x\n", ST);
- pulse_clock(1);
- }
- else
- {
- WP = m_current_value & 0xfffe;
- if (TRACE_OP) logerror("tms9995: new WP = %04x\n", WP);
- }
-}
-
-/*
- The MOV operation on the TMS9995 is definitely more efficient than in the
- TMS9900. As we have only 8 data bus lines we can read or write bytes
- with only one cycle. The TMS9900 always has to read the memory word first
- in order to write back a complete word, also when doing byte operations.
-*/
-void tms9995_device::alu_mov()
-{
- m_current_value = m_source_value;
- if (m_instruction->byteop)
- {
- set_status_parity((UINT8)(m_current_value>>8));
- }
- compare_and_set_lae(m_current_value, 0);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- // No clock pulse, as next instruction is prefetch
-}
-
-/*
- Unsigned and signed multiplication
-*/
-void tms9995_device::alu_multiply()
-{
- int n = 0;
- UINT32 result = 0;
- INT32 results = 0;
-
- if (m_instruction->command==MPY)
- {
- switch (m_instruction->state)
- {
- case 0:
- // m_current_value <- multiplier (source)
- m_source_value = m_current_value;
- // m_address is the second multiplier (in a register)
- m_address = ((m_instruction->IR >> 5) & 0x001e) + WP;
- n = 1;
- break;
- case 1:
- // m_current_value <- register content
- result = (m_source_value & 0x0000ffff) * (m_current_value & 0x0000ffff);
- m_current_value = (result >> 16) & 0xffff;
- m_value_copy = result & 0xffff;
- // m_address is still the register
- n = 17;
- break;
- case 2:
- m_address += 2;
- m_current_value = m_value_copy;
- // now write the lower 16 bit.
- // If the register was R15, do not use R0 but continue writing after
- // R15's address
- break;
- }
- }
- else
- {
- switch (m_instruction->state)
- {
- case 0:
- // m_current_value <- multiplier (source)
- m_source_value = m_current_value;
- // m_address is the second multiplier (in R0)
- m_address = WP;
- n = 1;
- break;
- case 1:
- // m_current_value <- register content
- results = ((INT16)m_source_value) * ((INT16)m_current_value);
- m_current_value = (results >> 16) & 0xffff;
- m_value_copy = results & 0xffff;
- // m_address is still the register
- n = 16;
- break;
- case 2:
- m_address += 2;
- m_current_value = m_value_copy;
- // now write the lower 16 bit.
- break;
- }
- }
- m_instruction->state++;
- pulse_clock(n);
-}
-
-void tms9995_device::alu_rtwp()
-{
- switch (m_instruction->state)
- {
- case 0:
- m_address = WP + 30; // R15
- pulse_clock(1);
- break;
- case 1:
- ST = m_current_value;
- m_address -= 2; // R14
- break;
- case 2:
- PC = m_current_value & 0xfffe;
- m_address -= 2; // R13
- break;
- case 3:
- WP = m_current_value & 0xfffe;
-
- // Just for debugging purposes
- m_servicing_interrupt = false;
-
- if (TRACE_OP) logerror("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST);
- break;
- }
- m_instruction->state++;
-}
-
-void tms9995_device::alu_sbo_sbz()
-{
- INT8 displacement;
-
- if (m_instruction->state==0)
- {
- m_address = WP + 24;
- }
- else
- {
- m_cru_value = (m_instruction->command==SBO)? 1 : 0;
- displacement = (INT8)(m_instruction->IR & 0xff);
- m_cru_address = m_current_value + (displacement<<1);
- m_count = 1;
- }
- m_instruction->state++;
- pulse_clock(1);
-}
-
-/*
- Perform the shift operation
-*/
-void tms9995_device::alu_shift()
-{
- bool carry = false;
- bool overflow = false;
- UINT16 sign = 0;
- UINT32 value;
- int count;
-
- switch (m_instruction->state)
- {
- case 0:
- // we have the value of the register in m_current_value
- // Save it (we may have to read R0)
- m_value_copy = m_current_value;
- m_address_saved = m_address;
- m_address = WP;
- // store this in m_current_value where the R0 value will be put
- m_current_value = (m_instruction->IR >> 4)& 0x000f;
- if (m_current_value != 0)
- {
- // skip the next read operation
- MPC++;
- }
- else
- {
- if (TRACE_DETAIL) logerror("tms9995: Shift operation gets count from R0\n");
- }
- pulse_clock(1);
- pulse_clock(1);
- break;
-
- case 1:
- count = m_current_value & 0x000f; // from the instruction or from R0
- if (count==0) count = 16;
-
- value = m_value_copy;
-
- // we are re-implementing the shift operations because we have to pulse
- // the clock at each single shift anyway.
- // Also, it is easier to implement the status bit setting.
- // Note that count is never 0
- if (m_instruction->command == SRA) sign = value & 0x8000;
-
- for (int i=0; i < count; i++)
- {
- switch (m_instruction->command)
- {
- case SRL:
- case SRA:
- carry = ((value & 1)!=0);
- value = (value >> 1) | sign;
- break;
- case SLA:
- carry = ((value & 0x8000)!=0);
- value <<= 1;
- if (carry != ((value&0x8000)!=0)) overflow = true;
- break;
- case SRC:
- carry = ((value & 1)!=0);
- value = (value>>1) | (carry? 0x8000 : 0x0000);
- break;
- }
- pulse_clock(1);
- }
-
- m_current_value = value & 0xffff;
- set_status_bit(ST_C, carry);
- set_status_bit(ST_OV, overflow);
- compare_and_set_lae(m_current_value, 0);
- m_address = m_address_saved; // Register address
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- break;
- }
- m_instruction->state++;
-}
-
-/*
- Handles ABS, DEC, DECT, INC, INCT, NEG, INV
-*/
-void tms9995_device::alu_single_arithm()
-{
- UINT32 dest_new = 0;
- UINT32 src_val = m_current_value & 0x0000ffff;
- UINT16 sign = 0;
- bool check_ov = true;
-
- switch (m_instruction->command)
- {
- case ABS:
- // LAECO (from original word!)
- // O if >8000
- // C is always reset
- set_status_bit(ST_OV, m_current_value == 0x8000);
- set_status_bit(ST_C, false);
- compare_and_set_lae(m_current_value, 0);
-
- if ((m_current_value & 0x8000)!=0)
- {
- dest_new = ((~src_val) & 0x0000ffff) + 1;
- }
- else
- {
- dest_new = src_val;
- }
- m_current_value = dest_new & 0xffff;
- return;
- case DEC:
- // LAECO
- // Carry for result value != 0xffff
- // Overflow for result value == 0x7fff
- dest_new = src_val + 0xffff;
- sign = 0x8000;
- break;
- case DECT:
- // Carry for result value != 0xffff / 0xfffe
- // Overflow for result value = 0x7fff / 0x7ffe
- dest_new = src_val + 0xfffe;
- sign = 0x8000;
- break;
- case INC:
- // LAECO
- // Overflow for result value = 0x8000
- // Carry for result value = 0x0000
- dest_new = src_val + 1;
- break;
- case INCT:
- // LAECO
- // Overflow for result value = 0x8000 / 0x8001
- // Carry for result value = 0x0000 / 0x0001
- dest_new = src_val + 2;
- break;
- case INV:
- // LAE
- dest_new = ~src_val & 0xffff;
- check_ov = false;
- break;
- case NEG:
- // LAECO
- // Overflow occurs for value=0x8000
- // Carry occurs for value=0
- dest_new = ((~src_val) & 0x0000ffff) + 1;
- check_ov = false;
- set_status_bit(ST_OV, src_val == 0x8000);
- break;
- case SWPB:
- m_current_value = ((m_current_value << 8) | (m_current_value >> 8)) & 0xffff;
- // I don't know what they are doing right now, but we lose a lot of cycles
- // according to the spec (which can indeed be proved on a real system)
-
- // Maybe this command is used as a forced wait between accesses to the
- // video system. Usually we have two byte writes to set an address in
- // the VDP, with a SWPB in between. Most software for the TI-99/4A using
- // the TMS9900 will run into trouble when executed on the TI-99/8 with
- // the much faster TMS9995. So the SWPB may be used to as an intentional
- // slowdown.
-
- // No status bits affected
- pulse_clock(10);
- return;
- }
-
- if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign));
- set_status_bit(ST_C, (dest_new & 0x10000) != 0);
- m_current_value = dest_new & 0xffff;
- compare_and_set_lae(m_current_value, 0);
-
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- // No clock pulse, as next instruction is prefetch
-}
-
-/*
- Store CRU.
-*/
-void tms9995_device::alu_stcr()
-{
- int n = 1;
- switch (m_instruction->state)
- {
- case 0:
- m_count = (m_instruction->IR >> 6) & 0x000f;
- if (m_count == 0) m_count = 16;
- m_instruction->byteop = (m_count < 9);
- break;
- case 1:
- m_address_saved = m_address;
- m_address = WP + 24;
- break;
- case 2:
- m_cru_address = m_current_value;
- m_cru_first_read = true;
- break;
- case 3:
- // I don't know what is happening here, but it takes quite some time.
- // May be shift operations.
- m_current_value = m_cru_value;
- m_address = m_address_saved;
- compare_and_set_lae(m_current_value, 0);
- n = 13;
- if (m_instruction->byteop)
- {
- set_status_parity((UINT8)m_current_value);
- m_current_value <<= 8;
- }
- else n += 8;
- if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value);
- break;
- }
- m_instruction->state++;
- pulse_clock(n);
-}
-
-
-/*
- Store status and store workspace pointer. We need to determine the
- address of the register here.
-*/
-void tms9995_device::alu_stst_stwp()
-{
- m_address = WP + ((m_instruction->IR & 0x000f)<<1);
- m_current_value = (m_instruction->command==STST)? ST : WP;
-}
-
-/*
- Test CRU bit.
-*/
-void tms9995_device::alu_tb()
-{
- INT8 displacement;
-
- switch (m_instruction->state)
- {
- case 0:
- m_address = WP + 24;
- pulse_clock(1);
- break;
- case 1:
- displacement = (INT8)(m_instruction->IR & 0xff);
- m_cru_address = m_current_value + (displacement<<1);
- m_cru_first_read = true;
- m_count = 1;
- pulse_clock(1);
- break;
- case 2:
- set_status_bit(ST_EQ, m_cru_value!=0);
- if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST);
- break;
- }
- m_instruction->state++;
-}
-
-/*
- Execute. This operation is substituted after reading the word at the
- given address.
-*/
-void tms9995_device::alu_x()
-{
- // We have the word in m_current_value. This word must now be decoded
- // as if it has been acquired by the normal procedure.
- decode(m_current_value);
- pulse_clock(1);
-
- // Switch to the prefetched and decoded instruction
- next_command();
-}
-
-/*
- XOP operation.
-*/
-void tms9995_device::alu_xop()
-{
- switch (m_instruction->state)
- {
- case 0:
- // we have the source address in m_address
- m_address_saved = m_address;
- // Format is xxxx xxnn nnxx xxxx
- m_address = 0x0040 + ((m_instruction->IR & 0x03c0)>>4);
- pulse_clock(1);
- break;
- case 1:
- // m_current_value is new WP
- m_value_copy = WP; // store this for later
- WP = m_current_value & 0xfffe;
- m_address = WP + 0x0016; // Address of new R11
- m_current_value = m_address_saved;
- pulse_clock(1);
- break;
- case 2:
- m_address = WP + 0x001e;
- m_current_value = ST;
- pulse_clock(1);
- break;
- case 3:
- m_address = WP + 0x001c;
- m_current_value = PC;
- pulse_clock(1);
- break;
- case 4:
- m_address = WP + 0x001a;
- m_current_value = m_value_copy;
- pulse_clock(1);
- break;
- case 5:
- m_address = 0x0042 + ((m_instruction->IR & 0x03c0)>>4);
- pulse_clock(1);
- break;
- case 6:
- PC = m_current_value & 0xfffe;
- set_status_bit(ST_X, true);
- break;
- }
- m_instruction->state++;
-}
-
-/*
- Handle an interrupt. The behavior as implemented here follows
- exactly the flowchart in [1]
-*/
-void tms9995_device::alu_int()
-{
- int pulse = 1;
-
- switch (m_instruction->state)
- {
- case 0:
- PC = (PC - 2) & 0xfffe;
- m_address_saved = m_address;
- if (TRACE_INTD) logerror("tms9995: interrupt service (0): Prepare to read vector\n");
- break;
- case 1:
- pulse = 2; // two cycles (with the one at the end)
- m_source_value = WP; // old WP
- WP = m_current_value & 0xfffe; // new WP
- m_current_value = ST;
- m_address = (WP + 30)&0xfffe;
- if (TRACE_INTD) logerror("tms9995: interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address);
- break;
- case 2:
- m_address = (WP + 28)&0xfffe;
- m_current_value = PC;
- if (TRACE_INTD) logerror("tms9995: interrupt service (2): Save PC to %04x\n", m_address);
- break;
- case 3:
- m_address = (WP + 26)&0xfffe;
- m_current_value = m_source_value; // old WP
- if (TRACE_INTD) logerror("tms9995: interrupt service (3): Save WP to %04x\n", m_address);
- break;
- case 4:
- m_address = (m_address_saved + 2) & 0xfffe;
- if (TRACE_INTD) logerror("tms9995: interrupt service (4): Read PC from %04x\n", m_address);
- break;
- case 5:
- PC = m_current_value & 0xfffe;
- ST = (ST & 0xfe00) | m_intmask;
- if (TRACE_INTD) logerror("tms9995: interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST);
-
- if (((m_int_pending & PENDING_MID)!=0) && m_nmi_active)
- {
- if (TRACE_INTD) logerror("tms9995: interrupt service (6): NMI active after context switch\n");
- m_int_pending &= ~PENDING_MID;
- m_address = 0xfffc;
- m_intmask = 0;
- MPC = 0; // redo the interrupt service for the NMI
- }
- else
- {
- if (m_from_reset)
- {
- if (TRACE_INTD) logerror("tms9995: interrupt service (6): RESET completed\n");
- // We came from the RESET interrupt
- m_from_reset = false;
- ST &= 0x01ff;
- m_mid_flag = false;
- m_mid_active = false;
- // FLAG0 and FLAG1 are also set to zero after RESET ([1], sect. 2.3.1.2.2)
- for (int i=0; i < 5; i++) m_flag[i] = false;
- m_check_hold = true;
- }
- }
- pulse = 0;
- break;
-
- // If next instruction is MID opcode we will detect this in command_completed
- }
- m_instruction->state++;
- pulse_clock(pulse);
-}
-
-/**************************************************************************/
-UINT32 tms9995_device::execute_min_cycles() const
-{
- return 2;
-}
-
-UINT32 tms9995_device::execute_max_cycles() const
-{
- return 44;
-}
-
-UINT32 tms9995_device::execute_input_lines() const
-{
- return 2;
-}
-
-UINT32 tms9995_device::disasm_min_opcode_bytes() const
-{
- return 2;
-}
-
-UINT32 tms9995_device::disasm_max_opcode_bytes() const
-{
- return 6;
-}
-
-offs_t tms9995_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
-{
- extern CPU_DISASSEMBLE( tms9995 );
- return CPU_DISASSEMBLE_NAME(tms9995)(this, buffer, pc, oprom, opram, options);
-}
-
-
-const device_type TMS9995 = &device_creator<tms9995_device>;
-const device_type TMS9995_MP9537 = &device_creator<tms9995_mp9537_device>;
diff --git a/src/emu/cpu/tms9900/tms9995.h b/src/emu/cpu/tms9900/tms9995.h
deleted file mode 100644
index 81e2e560505..00000000000
--- a/src/emu/cpu/tms9900/tms9995.h
+++ /dev/null
@@ -1,446 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- tms9995.h
-
- See tms9995.c for documentation
- Also see tms9900.h for types of TMS99xx processors.
-*/
-
-#ifndef __TMS9995_H__
-#define __TMS9995_H__
-
-#include "emu.h"
-#include "debugger.h"
-#include "tms99com.h"
-
-// device type definition
-extern const device_type TMS9995;
-extern const device_type TMS9995_MP9537;
-
-enum
-{
- INT_9995_RESET = 0,
- INT_9995_INTREQ = 1,
- INT_9995_INT1 = 2,
- INT_9995_INT4 = 3
-};
-
-#define MCFG_TMS9995_EXTOP_HANDLER( _extop) \
- devcb = &tms9995_device::static_set_extop_callback( *device, DEVCB_##_extop );
-
-#define MCFG_TMS9995_IAQ_HANDLER( _iaq ) \
- devcb = &tms9995_device::static_set_iaq_callback( *device, DEVCB_##_iaq );
-
-#define MCFG_TMS9995_CLKOUT_HANDLER( _clkout ) \
- devcb = &tms9995_device::static_set_clkout_callback( *device, DEVCB_##_clkout );
-
-#define MCFG_TMS9995_HOLDA_HANDLER( _holda ) \
- devcb = &tms9995_device::static_set_holda_callback( *device, DEVCB_##_holda );
-
-#define MCFG_TMS9995_DBIN_HANDLER( _dbin ) \
- devcb = &tms9995_device::static_set_dbin_callback( *device, DEVCB_##_dbin );
-
-#define MCFG_TMS9995_ENABLE_OVINT( _ovint ) \
- downcast<tms9995_device*>(device)->set_overflow_interrupt( _ovint );
-
-
-class tms9995_device : public cpu_device
-{
-public:
- tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
- tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
-
- // READY input line. When asserted (high), the memory is ready for data exchange.
- // We chose to use a direct method instead of a delegate to keep performance
- // footprint low; this method may be called very frequently.
- void set_ready(int state);
-
- // HOLD input line. When asserted (low), the CPU is requested to release the
- // data and address bus and enter the HOLD state. The entrance of this state
- // is acknowledged by the HOLDA output line.
- void set_hold(int state);
-
- // Callbacks
- template<class _Object> static devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_external_operation.set_callback(object); }
- template<class _Object> static devcb_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_iaq_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_clock_out_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_holda_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_holda_line.set_callback(object); }
- template<class _Object> static devcb_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast<tms9995_device &>(device).m_dbin_line.set_callback(object); }
-
- // For debugger access
- UINT8 debug_read_onchip_memory(offs_t addr) { return m_onchip_memory[addr & 0xff]; };
- bool is_onchip(offs_t addrb) { return (((addrb & 0xff00)==0xf000 && (addrb < 0xf0fc)) || ((addrb & 0xfffc)==0xfffc)) && !m_mp9537; }
-
- void set_overflow_interrupt( int enable ) { m_check_overflow = (enable!=0); }
-
-protected:
- // device-level overrides
- virtual void device_start();
- virtual void device_stop();
- virtual void device_reset();
-
- // device_execute_interface overrides
- virtual UINT32 execute_min_cycles() const;
- virtual UINT32 execute_max_cycles() const;
- virtual UINT32 execute_input_lines() const;
- virtual void execute_set_input(int irqline, int state);
- virtual void execute_run();
-
- // device_disasm_interface overrides
- virtual UINT32 disasm_min_opcode_bytes() const;
- virtual UINT32 disasm_max_opcode_bytes() const;
- virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
-
- const address_space_config* memory_space_config(address_spacenum spacenum) const;
-
- UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks / 4.0; }
- UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles * 4.0; }
-
- // Variant of the TMS9995 without internal RAM and decrementer
- bool m_mp9537;
-
-private:
- // State / debug management
- UINT16 m_state_any;
- static const char* s_statename[];
- void state_import(const device_state_entry &entry);
- void state_export(const device_state_entry &entry);
- void state_string_export(const device_state_entry &entry, std::string &str);
- UINT16 read_workspace_register_debug(int reg);
- void write_workspace_register_debug(int reg, UINT16 data);
-
- // TMS9995 hardware registers
- UINT16 WP; // Workspace pointer
- UINT16 PC; // Program counter
- UINT16 ST; // Status register
-
- // The TMS9995 has a prefetch feature which causes a wrong display of the PC.
- // We use this additional member for the debugger only.
- UINT16 PC_debug;
-
- // 256 bytes of onchip memory
- UINT8 m_onchip_memory[256];
-
- const address_space_config m_program_config;
- const address_space_config m_io_config;
- address_space* m_prgspace;
- address_space* m_cru;
-
-
- // Processor states
- bool m_idle_state;
- bool m_nmi_state;
- bool m_irq_state;
- bool m_hold_state;
-
- // READY handling. The READY line is operated before the clock
- // pulse falls. As the ready line is only set once in this emulation we
- // keep the level in a buffer (like a latch)
- bool m_ready_bufd; // buffered state
- bool m_ready; // sampled value
-
- // Auto-wait state generation
- bool m_request_auto_wait_state;
- bool m_auto_wait;
-
- // Cycle counter
- int m_icount;
-
- // Phase of the memory access
- int m_mem_phase;
-
- // Check the READY line?
- bool m_check_ready;
-
- // Check the HOLD line
- bool m_check_hold;
-
- // For multi-pass operations. For instance, memory word accesses are
- // executed as two consecutive byte accesses. CRU accesses are repeated
- // single-bit accesses.
- int m_pass;
-
- // For parity operations
- int m_parity;
-
- // For Format 1 instruction; determines whether the next operand address
- // derivation is for the source or address operand
- bool m_get_destination;
-
- // Used for situations when a command is byte-oriented, but the memory access
- // must be word-oriented. Example: MOVB *R1,R0; we must read the full word
- // from R1 to get the address.
- bool m_word_access;
-
- // Interrupt handling
- bool m_nmi_active;
- bool m_int1_active;
- bool m_int4_active;
- bool m_int_decrementer;
- bool m_int_overflow;
-
- bool m_reset;
- bool m_from_reset;
- bool m_mid_flag;
- bool m_mid_active;
-
- int m_decrementer_clkdiv;
- bool m_servicing_interrupt;
-
- // Flag field
- int m_int_pending;
-
- // The TMS9995 is capable of raising an internal interrupt on
- // arithmetic overflow, depending on the status register Overflow Enable bit.
- // However, the specs also say that this feature is non-functional in the
- // currently available chip. Thus we have an option to turn it off so that
- // software will not change its behavior on overflows.
- bool m_check_overflow;
-
- // Service pending interrupts
- void service_interrupt();
-
- // Issue clock pulses. The TMS9995 uses one (output) clock cycle per machine cycle.
- inline void pulse_clock(int count);
-
- // Signal the hold state via the external line
- inline void set_hold_state(bool state);
-
- // Only used for the DIV(S) operations. It seems sufficient to let the
- // command terminate at this point, so this method just calls command_terminated.
- void abort_operation(void);
-
- // Decode the given 16-bit value which has been retrieved by a prefetch or
- // during an X operation.
- void decode(UINT16 inst);
-
- // Store the interrupt mask part of the ST. This is used when processing
- // an interrupt, passing the new mask from the service_interrupt part to
- // the program part.
- int m_intmask;
-
- // Stored address
- UINT16 m_address;
-
- // Stores the recently read word or the word to be written
- UINT16 m_current_value;
-
- // Stores the value of the source operand in multi-operand instructions
- UINT16 m_source_value;
-
- // During indexed addressing, this value is added to get the final address value.
- UINT16 m_address_add;
-
- // During indirect/auto-increment addressing, this copy of the address must
- // be preserved while writing the new value to the register.
- UINT16 m_address_saved;
-
- // Another copy of the address
- UINT16 m_address_copy;
-
- // Copy of the value
- UINT16 m_value_copy;
-
- // Stores the recent register number. Only used to pass the register
- // number during the operand address derivation.
- int m_regnumber;
-
- // Stores the number of bits or shift operations
- int m_count;
-
- // ============== Decrementer =======================
- void trigger_decrementer();
-
- // Start value
- UINT16 m_starting_count_storage_register;
-
- // Current decrementer value.
- UINT16 m_decrementer_value;
-
- // ============== CRU support ======================
-
- UINT16 m_cru_address;
- UINT16 m_cru_value;
- bool m_cru_first_read;
- int m_cru_bits_left;
- UINT32 m_cru_read;
-
- // CPU-internal CRU flags
- bool m_flag[16];
-
- // ============== Prefetch support =====================
-
- struct decoded_instruction
- {
- UINT16 IR;
- UINT16 command;
- const UINT8* program;
- bool byteop;
- int state;
- };
-
- int m_instindex;
-
- // We implement the prefetch mechanism by two separate datasets for
- // the decoded commands. When the previous command has completed, the
- // pointer is just switched to the other one.
- tms9995_device::decoded_instruction m_decoded[2];
- tms9995_device::decoded_instruction* m_instruction;
-
- // ================ Microprogram support ========================
-
- // Set up lookup table
- void build_command_lookup_table();
-
- // Sequence of micro-operations
- typedef const UINT8* microprogram;
-
- // Method pointer
- typedef void (tms9995_device::*ophandler)(void);
-
- // Opcode list entry
- struct tms_instruction
- {
- UINT16 opcode;
- int id;
- int format;
- microprogram prog; // Microprogram
- };
-
- // Lookup table entry
- struct lookup_entry
- {
- lookup_entry *next_digit;
- const tms_instruction *entry;
- };
-
- // Pointer to the lookup table; the entry point for searching the command
- lookup_entry* m_command_lookup_table;
-
- // List of allocated tables (used for easy clean-up on exit)
- lookup_entry* m_lotables[32];
-
- // List of pointers for micro-operations
- static const tms9995_device::ophandler s_microoperation[];
-
- static const tms9995_device::tms_instruction s_command[];
-
- // Micro-operation program counter (as opposed to the program counter PC)
- int MPC;
-
- // Calling microprogram (used when data derivation is called)
- const UINT8* m_caller;
- int m_caller_MPC;
-
- // Table of microprograms
- static const microprogram mp_table[];
-
- // Used to display the number of consumed cycles in the log.
- int m_first_cycle;
-
- // Status register update
- inline void set_status_bit(int bit, bool state);
- inline void compare_and_set_lae(UINT16 value1, UINT16 value2);
- void set_status_parity(UINT8 value);
-
- // Micro-operation declarations
- void int_prefetch_and_decode();
- void prefetch_and_decode();
- void mem_read();
- void mem_write();
- inline void word_read();
- inline void word_write();
- void operand_address_subprogram();
- void increment_register();
- void indexed_addressing();
- void set_immediate();
- void return_with_address();
- void return_with_address_copy();
- void cru_input_operation();
- void cru_output_operation();
- void command_completed();
- void next_command();
-
- // ALU operations for specific commands
- void alu_nop();
- void alu_add_s_sxc();
- void alu_b();
- void alu_blwp();
- void alu_c();
- void alu_ci();
- void alu_clr_seto();
- void alu_divide();
- void alu_divide_signed();
- void alu_external();
- void alu_f3();
- void alu_imm_arithm();
- void alu_jump();
- void alu_ldcr();
- void alu_li();
- void alu_limi_lwpi();
- void alu_lst_lwp();
- void alu_mov();
- void alu_multiply();
- void alu_multiply_signed();
- void alu_rtwp();
- void alu_sbo_sbz();
- void alu_shift();
- void alu_single_arithm();
- void alu_stcr();
- void alu_stst_stwp();
- void alu_tb();
- void alu_x();
- void alu_xop();
- void alu_int();
-
- // ================ Connections ====================
-
- // Trigger external operation. This is achieved by putting a special value in
- // the most significant three bits of the data bus and pulsing the CRUCLK line.
- // Accordingly, we have
- //
- // D0 D1 D2
- // 0 0 0 normal CRU access
- // 0 1 0 IDLE
- // 0 1 1 RSET
- // 1 0 1 CKON
- // 1 1 0 CKOF
- // 1 1 1 LREX
- //
- // We could realize this via the CRU access as well, but the data bus access
- // is not that simple to emulate. For the sake of homogenity between the
- // chip emulations we use a dedicated callback.
- devcb_write8 m_external_operation;
-
- // Signal to the outside world that we are now getting an instruction (IAQ).
- // In the real hardware this line is shared with the HOLDA line, and the
- // /MEMEN line is used to decide which signal we have on the line. We do not
- // emulate the /MEMEN line, so we have to use two separate lines.
- devcb_write_line m_iaq_line;
-
- // Clock output.
- devcb_write_line m_clock_out_line;
-
- // Asserted when the CPU is in a HOLD state
- devcb_write_line m_holda_line;
-
- // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers.
- devcb_write_line m_dbin_line;
-};
-
-
-/*
- Variant of the TMS9995 without on-chip RAM; used in the TI-99/8 console
-*/
-class tms9995_mp9537_device : public tms9995_device
-{
-public:
- tms9995_mp9537_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms9995_device(mconfig, TMS9995_MP9537, "TMS9995-MP9537", tag, owner, clock, "tms9995_mp9537", __FILE__)
- {
- m_mp9537 = true;
- }
-};
-
-#endif /* __TMS9995_H__ */
diff --git a/src/emu/cpu/tms9900/tms99com.h b/src/emu/cpu/tms9900/tms99com.h
deleted file mode 100644
index 3a1aeeb57ee..00000000000
--- a/src/emu/cpu/tms9900/tms99com.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Michael Zapf
-/*
- Common definitions for all TMS processors
-
- Types of TMS99xx processors:
- TI990/9 Early implementation, used in a few real-world applications, 1974
- very similar to mapper-less 990/10 and tms9900, but the Load
- process is different
-
- TI990/10 Original multi-chip implementation for minicomputer systems, 1975
-
- TI990/12 Multi-chip implementation, faster than 990/10. Huge instruction set
-
- TMS9900 Mono-chip implementation, 1976. Used in the TI-99/4(A) computer.
-
- TMS9940 Microcontroller with 2kb ROM, 128b RAM, decrementer, CRU bus, 1979
-
- TMS9980 8-bit variant of tms9900. Two distinct chips actually : tms9980a
- and tms9981 with an extra clock and simplified power supply
-
- TMS9985 9940 with 8kb ROM, 256b RAM, and a 8-bit external bus, c. 1978 (never released)
-
- TMS9989 Improved 9980, used in military hardware.
-
- SBP68689 Improved 9989, built as an ASIC as 9989 was running scarce
-
- TMS9995 TMS9985-like, with many improvements (but no ROM). Used in the
- TI-99/8 prototype and the Geneve computer.
-
- TMS99000 Improved mono-chip implementation, meant to replace 990/10, 1981
- TMS99105 This chip is available in several variants which are similar
- TMS99110 but emulate additional instructions, thanks to the so-called
- macrostore feature.
-
- In this implementation we only consider TMS9900, 9980, and 9995. The
- remaining types are implemented on an own code base as they introduce
- significant changes (e.g. privileged mode, address mapper).
-*/
-
-#ifndef __TMS99COMMON_H__
-#define __TMS99COMMON_H__
-
-#define MCFG_TMS99xx_ADD(_tag, _device, _clock, _prgmap, _iomap ) \
- MCFG_DEVICE_ADD(_tag, _device, _clock) \
- MCFG_DEVICE_PROGRAM_MAP(_prgmap) \
- MCFG_DEVICE_IO_MAP(_iomap)
-
-#define MCFG_TMS99xx_EXTOP_HANDLER( _extop) \
- devcb = &tms99xx_device::static_set_extop_callback( *device, DEVCB_##_extop );
-
-#define MCFG_TMS99xx_INTLEVEL_HANDLER( _intlevel ) \
- devcb = &tms99xx_device::static_set_intlevel_callback( *device, DEVCB_##_intlevel );
-
-#define MCFG_TMS99xx_IAQ_HANDLER( _iaq ) \
- devcb = &tms99xx_device::static_set_iaq_callback( *device, DEVCB_##_iaq );
-
-#define MCFG_TMS99xx_CLKOUT_HANDLER( _clkout ) \
- devcb = &tms99xx_device::static_set_clkout_callback( *device, DEVCB_##_clkout );
-
-#define MCFG_TMS99xx_WAIT_HANDLER( _wait ) \
- devcb = &tms99xx_device::static_set_wait_callback( *device, DEVCB_##_wait );
-
-#define MCFG_TMS99xx_HOLDA_HANDLER( _holda ) \
- devcb = &tms99xx_device::static_set_holda_callback( *device, DEVCB_##_holda );
-
-#define MCFG_TMS99xx_DBIN_HANDLER( _dbin ) \
- devcb = &tms99xx_device::static_set_dbin_callback( *device, DEVCB_##_dbin );
-
-enum
-{
- TI990_10_ID = 1,
- TMS9900_ID = 3,
- TMS9940_ID = 4,
- TMS9980_ID = 5,
- TMS9985_ID = 6,
- TMS9989_ID = 7,
- TMS9995_ID = 9,
- TMS99000_ID = 10,
- TMS99105A_ID = 11,
- TMS99110A_ID = 12
-};
-
-enum
-{
- IDLE_OP = 2,
- RSET_OP = 3,
- CKOF_OP = 5,
- CKON_OP = 6,
- LREX_OP = 7
-};
-
-#endif /* __TMS99COMMON_H__ */