diff options
author | 2015-09-13 08:41:44 +0200 | |
---|---|---|
committer | 2015-09-13 08:41:44 +0200 | |
commit | f88cefad27a1737c76e09d99c9fb43e173506081 (patch) | |
tree | 2d8167d03579c46e226471747eb4407bd00ed6fa /src/devices/cpu/tlcs90 | |
parent | e92ac9e0fa8e99869894bea00589bbb526be30aa (diff) |
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/devices/cpu/tlcs90')
-rw-r--r-- | src/devices/cpu/tlcs90/tlcs90.c | 2786 | ||||
-rw-r--r-- | src/devices/cpu/tlcs90/tlcs90.h | 181 |
2 files changed, 2967 insertions, 0 deletions
diff --git a/src/devices/cpu/tlcs90/tlcs90.c b/src/devices/cpu/tlcs90/tlcs90.c new file mode 100644 index 00000000000..1e3d5dde80a --- /dev/null +++ b/src/devices/cpu/tlcs90/tlcs90.c @@ -0,0 +1,2786 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +/************************************************************************************************************* + + Toshiba TLCS-90 Series MCU's + + emulation by Luca Elia, based on the Z80 core by Juergen Buchmueller + + ChangeLog: + + 20150517 Fixed TRUN bit masking (timers start/stop handling) [Rainer Keuchel] + +*************************************************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tlcs90.h" + +enum _e_op { UNKNOWN, NOP, EX, EXX, LD, LDW, LDA, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, PUSH, POP, JP, JR, CALL, CALLR, RET, RETI, HALT, DI, EI, SWI, DAA, CPL, NEG, LDAR, RCF, SCF, CCF, TSET, BIT, SET, RES, INC, DEC, INCX, DECX, INCW, DECW, ADD, ADC, SUB, SBC, AND, XOR, OR, CP, RLC, RRC, RL, RR, SLA, SRA, SLL, SRL, RLD, RRD, DJNZ, MUL, DIV }; +static const char *const op_names[] = { "??", "nop", "ex", "exx", "ld", "ldw", "lda", "ldi", "ldir", "ldd", "lddr", "cpi", "cpir", "cpd", "cpdr", "push", "pop", "jp", "jr", "call", "callr", "ret", "reti", "halt", "di", "ei", "swi", "daa", "cpl", "neg", "ldar", "rcf", "scf", "ccf", "tset", "bit", "set", "res", "inc", "dec", "incx", "decx", "incw", "decw", "add", "adc", "sub", "sbc", "and", "xor", "or", "cp", "rlc", "rrc", "rl", "rr", "sla", "sra", "sll", "srl", "rld", "rrd", "djnz", "mul", "div" }; + +ALLOW_SAVE_TYPE(tlcs90_device::e_mode); // allow save_item on a non-fundamental type + + +const device_type TMP90840 = &device_creator<tmp90840_device>; +const device_type TMP90841 = &device_creator<tmp90841_device>; +const device_type TMP91640 = &device_creator<tmp91640_device>; +const device_type TMP91641 = &device_creator<tmp91641_device>; + + +static ADDRESS_MAP_START(tmp90840_mem, AS_PROGRAM, 8, tlcs90_device) + AM_RANGE( 0x0000, 0x1fff ) AM_ROM // 8KB ROM (internal) + AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp90841_mem, AS_PROGRAM, 8, tlcs90_device) +// AM_RANGE( 0x0000, 0x1fff ) AM_ROM // rom-less + AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp91640_mem, AS_PROGRAM, 8, tlcs90_device ) + AM_RANGE( 0x0000, 0x3fff ) AM_ROM // 16KB ROM (internal) + AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp91641_mem, AS_PROGRAM, 8, tlcs90_device ) +// AM_RANGE( 0x0000, 0x3fff ) AM_ROM // rom-less + AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + + +tlcs90_device::tlcs90_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, address_map_constructor program_map) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0, program_map) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) +{ +} + + +tmp90840_device::tmp90840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP90840, "TMP90840", tag, owner, clock, "tmp90840", __FILE__, ADDRESS_MAP_NAME(tmp90840_mem)) +{ +} + +tmp90841_device::tmp90841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP90841, "TMP90841", tag, owner, clock, "tmp90841", __FILE__, ADDRESS_MAP_NAME(tmp90841_mem)) +{ +} + + +tmp91640_device::tmp91640_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP91640, "TMP91640", tag, owner, clock, "tmp91640", __FILE__, ADDRESS_MAP_NAME(tmp91640_mem)) +{ +} + + +tmp91641_device::tmp91641_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP91641, "TMP91641", tag, owner, clock, "tmp91641", __FILE__, ADDRESS_MAP_NAME(tmp91641_mem)) +{ +} + + +enum { + T90_B, T90_C, T90_D, T90_E, T90_H, T90_L, T90_A, + T90_BC, T90_DE, T90_HL, T90_XX, T90_IX, T90_IY, T90_SP, + T90_AF, T90_PC +}; + +// Regs + +#define B 0 +#define C 1 +#define D 2 +#define E 3 +#define H 4 +#define L 5 +#define A 6 + +#define BC 0 +#define DE 1 +#define HL 2 +// 3 +#define IX 4 +#define IY 5 +#define SP 6 + +#define AF 7 +#define AF2 8 +#define PC 9 + +#define F m_af.b.l + +static const char *const r8_names[] = { "b", "c", "d", "e", "h", "l", "a" }; +static const char *const r16_names[] = { "bc", "de", "hl", "??", "ix", "iy", "sp", "af", "af'", "pc" }; + +// Condition Codes + +#define FLS 0x0 +#define LT 0x1 +#define LE 0x2 +#define ULE 0x3 +#define OV 0x4 +#define PE 0x4 +#define MI 0x5 +#define Z 0x6 +#define EQ 0x6 +#define CR 0x7 +#define ULT 0x7 +#define T 0x8 +#define GE 0x9 +#define GT 0xa +#define UGT 0xb +#define NOV 0xc +#define PO 0xc +#define PL 0xd +#define NZ 0xe +#define NE 0xe +#define NC 0xf +#define UGE 0xf + +#define CF 0x01 +#define NF 0x02 +#define PF 0x04 +#define VF PF +#define XCF 0x08 +#define HF 0x10 +#define IF 0x20 +#define ZF 0x40 +#define SF 0x80 + +static UINT8 SZ[256]; /* zero and sign flags */ +static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */ +static UINT8 SZP[256]; /* zero, sign and parity flags */ +static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */ +static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */ + +static const char *const cc_names[] = { "f", "lt", "le", "ule", "ov", "mi", "z", "c", "", "ge", "gt", "ugt", "nov", "pl", "nz", "nc" }; + +// Opcodes + +#define OP_16 0x80 + + + + + +#define OP( X,CT ) m_op = X; m_cyc_t = (CT*2); +#define OP16( X,CT ) OP( (X)|OP_16,CT ) + +#define OPCC( X,CF,CT ) OP( X, CT ) m_cyc_f = (CF*2); +#define OPCC16( X,CF,CT ) OPCC( (X)|OP_16,CF,CT ) + +#define BIT8( N,I ) m_mode##N = MODE_BIT8; m_r##N = I; +#define I8( N,I ) m_mode##N = MODE_I8; m_r##N = I; +#define D8( N,I ) m_mode##N = MODE_D8; m_r##N = I; +#define I16( N,I ) m_mode##N = MODE_I16; m_r##N = I; +#define D16( N,I ) m_mode##N = MODE_D16; m_r##N = I; +#define R8( N,R ) m_mode##N = MODE_R8; m_r##N = R; +#define R16( N,R ) m_mode##N = MODE_R16; m_r##N = R; +#define Q16( N,R ) m_mode##N = MODE_R16; m_r##N = R; if (m_r##N == SP) m_r##N = AF; +#define MI16( N,I ) m_mode##N = MODE_MI16; m_r##N = I; +#define MR16( N,R ) m_mode##N = MODE_MR16; m_r##N = R; +#define MR16D8( N,R,I ) m_mode##N = MODE_MR16D8; m_r##N = R; m_r##N##b = I; +#define MR16R8( N,R,g ) m_mode##N = MODE_MR16R8; m_r##N = R; m_r##N##b = g; +#define NONE( N ) m_mode##N = MODE_NONE; +#define CC( N,cc ) m_mode##N = MODE_CC; m_r##N = cc; +#define R16D8( N,R,I ) m_mode##N = MODE_R16D8; m_r##N = R; m_r##N##b = I; +#define R16R8( N,R,g ) m_mode##N = MODE_R16R8; m_r##N = R; m_r##N##b = g; + +UINT8 tlcs90_device::RM8 (UINT32 a) { return m_program->read_byte( a ); } +UINT16 tlcs90_device::RM16(UINT32 a) { return RM8(a) | (RM8( (a+1) & 0xffff ) << 8); } + +void tlcs90_device::WM8 (UINT32 a, UINT8 v) { m_program->write_byte( a, v ); } +void tlcs90_device::WM16(UINT32 a, UINT16 v) { WM8(a,v); WM8( (a+1) & 0xffff, v >> 8); } + +UINT8 tlcs90_device::RX8 (UINT32 a, UINT32 base) { return m_program->read_byte( base | a ); } +UINT16 tlcs90_device::RX16(UINT32 a, UINT32 base) { return RX8(a,base) | (RX8( (a+1) & 0xffff, base ) << 8); } + +void tlcs90_device::WX8 (UINT32 a, UINT8 v, UINT32 base) { m_program->write_byte( base | a, v ); } +void tlcs90_device::WX16(UINT32 a, UINT16 v, UINT32 base) { WX8(a,v,base); WX8( (a+1) & 0xffff, v >> 8, base); } + +UINT8 tlcs90_device::READ8() { UINT8 b0 = RM8( m_addr++ ); m_addr &= 0xffff; return b0; } +UINT16 tlcs90_device::READ16() { UINT8 b0 = READ8(); return b0 | (READ8() << 8); } + +void tlcs90_device::decode() +{ + UINT8 b0, b1, b2, b3; + UINT16 imm16; + + b0 = READ8(); + + switch ( b0 ) + { + case 0x00: + OP( NOP,2 ) NONE( 1 ) NONE( 2 ) return; // NOP + + case 0x01: + OP( HALT,4 ) NONE( 1 ) NONE( 2 ) return; // HALT + case 0x02: + OP( DI,2 ) NONE( 1 ) NONE( 2 ) return; // DI + case 0x03: + OP( EI,2 ) NONE( 1 ) NONE( 2 ) return; // EI + + case 0x07: + OPCC( INCX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCX ($FF00+n) + + case 0x08: + OP( EX,2 ) R16( 1, DE ) R16( 2, HL ) return; // EX DE,HL + case 0x09: + OP( EX,2 ) R16( 1, AF ) R16( 2, AF2 ) return; // EX AF,AF' + case 0x0a: + OP( EXX,2 ) NONE( 1 ) NONE( 2 ) return; // EXX + + case 0x0b: + OP( DAA,4 ) R8( 1, A ) NONE( 2 ) return; // DAA A + + case 0x0c: + OP( RCF,2 ) NONE( 1 ) NONE( 2 ) return; // RCF + case 0x0d: + OP( SCF,2 ) NONE( 1 ) NONE( 2 ) return; // SCF + case 0x0e: + OP( CCF,2 ) NONE( 1 ) NONE( 2 ) return; // CCF + + case 0x0f: + OPCC( DECX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECX ($FF00+n) + + case 0x10: + OP( CPL,2 ) R8( 1, A ) NONE( 2 ) return; // CPL A + case 0x11: + OP( NEG,2 ) R8( 1, A ) NONE( 2 ) return; // NEG A + + case 0x12: // MUL HL,n + case 0x13: // DIV HL,n + OP( MUL+b0-0x12,16) R16( 1, HL ) I8( 2, READ8() ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,6 ) R16( 1, IX+b0-0x14 ) I16( 2, READ16() ) return; // ADD ix,mn + + case 0x17: + OP( LDAR,8 ) R16( 1, HL ) D16( 2, READ16() ) return; // LDAR HL,+cd + + case 0x18: + OP( DJNZ,10 ) D8( 1, READ8() ) NONE( 2 ) return; // DJNZ +d + case 0x19: + OP16( DJNZ,10 ) R16( 1, BC ) D8( 2, READ8() ) return; // DJNZ BC,+d + + case 0x1a: + OPCC( JP,8,8 ) CC( 1, T ) I16( 2, READ16() ) return; // JP T,mn + case 0x1b: + OPCC16( JR,10,10 ) CC( 1, T ) D16( 2, READ16() ) return; // JR T,+cd + + case 0x1c: + OPCC( CALL,14,14 ) CC( 1, T ) I16( 2, READ16() ) return; // CALL T,mn + case 0x1d: + OP( CALLR,16 ) D16( 1, READ16() ) NONE( 2 ) return; // CALLR +cd + + case 0x1e: + OPCC( RET,10,10 ) CC( 1, T ) NONE( 2 ) return; // RET T + case 0x1f: + OP( RETI,14 ) NONE( 1 ) NONE( 2 ) return; // RETI + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,2 ) R8( 1, A ) R8( 2, b0 - 0x20 ) return; // LD A,r + + case 0x27: + OP( LD,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return; // LD A,($FF00+n) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,2 ) R8( 1, b0 - 0x28 ) R8( 2, A ) return; // LD r,A + + case 0x2f: + OP( LD,8 ) MI16( 1, 0xFF00|READ8() ) R8( 2, A ) return; // LD ($FF00+n), A + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: + OP( LD,4 ) R8( 1, b0 - 0x30 ) I8( 2, READ8() ) return; // LD r,n + + case 0x37: + OP( LD,10 ) MI16( 1, 0xFF00|READ8() ) I8( 2, READ8() ) return; // LD ($FF00+w),n + + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP16( LD,6 ) R16( 1, b0 - 0x38 ) I16( 2, READ16() ) return; // LD rr,nn + + case 0x3f: + OP( LDW,14 ) MI16( 1, 0xFF00|READ8() ) I16( 2, READ16() ) return; // LDW ($FF00+w),mn + + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,4 ) R16( 1, HL ) R16( 2, b0 - 0x40 ) return; // LD HL,rr + + case 0x47: + OP16( LD,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return; // LD HL,($FF00+n) + + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,4 ) R16( 1, b0 - 0x48 ) R16( 2, HL ) return; // LD rr,HL + + case 0x4f: + OP16( LD,10 ) MI16( 1, 0xFF00|READ8() ) R16( 2, HL ) return; // LD ($FF00+n), HL + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( PUSH,8 ) Q16( 1, b0 - 0x50 ) NONE( 2 ) return; // PUSH qq + case 0x58: case 0x59: case 0x5a: /*case 0x5b:*/ case 0x5c: case 0x5d: case 0x5e: + OP( POP,10 ) Q16( 1, b0 - 0x58 ) NONE( 2 ) return; // POP qq + + case 0x60: // ADD A,($FF00+n) + case 0x61: // ADC A,($FF00+n) + case 0x62: // SUB A,($FF00+n) + case 0x63: // SBC A,($FF00+n) + case 0x64: // AND A,($FF00+n) + case 0x65: // XOR A,($FF00+n) + case 0x66: // OR A,($FF00+n) + case 0x67: // CP A,($FF00+n) + OP( ADD+b0-0x60,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return; + + case 0x68: // ADD A,n + case 0x69: // ADC A,n + case 0x6a: // SUB A,n + case 0x6b: // SBC A,n + case 0x6c: // AND A,n + case 0x6d: // XOR A,n + case 0x6e: // OR A,n + case 0x6f: // CP A,n + OP( ADD+b0-0x68,4 ) R8( 1, A ) I8( 2, READ8() ) return; + + case 0x70: // ADD HL,($FF00+n) + case 0x71: // ADC HL,($FF00+n) + case 0x72: // SUB HL,($FF00+n) + case 0x73: // SBC HL,($FF00+n) + case 0x74: // AND HL,($FF00+n) + case 0x75: // XOR HL,($FF00+n) + case 0x76: // OR HL,($FF00+n) + case 0x77: // CP HL,($FF00+n) + OP16( ADD+b0-0x70,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return; + + case 0x78: // ADD HL,mn + case 0x79: // ADC HL,mn + case 0x7a: // SUB HL,mn + case 0x7b: // SBC HL,mn + case 0x7c: // AND HL,mn + case 0x7d: // XOR HL,mn + case 0x7e: // OR HL,mn + case 0x7f: // CP HL,mn + OP16( ADD+b0-0x78,6 ) R16( 1, HL ) I16( 2, READ16() ) return; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: + OP( INC,2 ) R8( 1, b0 - 0x80 ) NONE( 2 ) return; // INC r + case 0x87: + OP( INC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INC ($FF00+n) + + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: + OP( DEC,2 ) R8( 1, b0 - 0x88 ) NONE( 2 ) return; // DEC r + case 0x8f: + OP( DEC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DEC ($FF00+n) + + case 0x90: case 0x91: case 0x92: /*case 0x93:*/ case 0x94: case 0x95: case 0x96: + OP16( INC,4 ) R16( 1, b0 - 0x90 ) NONE( 2 ) return; // INC rr + case 0x97: + OP( INCW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCW ($FF00+n) + case 0x98: case 0x99: case 0x9a: /*case 0x9b:*/ case 0x9c: case 0x9d: case 0x9e: + OP16( DEC,4 ) R16( 1, b0 - 0x98 ) NONE( 2 ) return; // DEC rr + case 0x9f: + OP( DECW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECW ($FF00+n) + + case 0xa0: // RLC A + case 0xa1: // RRC A + case 0xa2: // RL A + case 0xa3: // RR A + case 0xa4: // SLA A + case 0xa5: // SRA A + case 0xa6: // SLL A + case 0xa7: // SRL A + OP( RLC+b0-0xa0,2 ) R8( 1, A ) NONE( 2 ) return; + + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,8 ) BIT8( 1, b0 - 0xa8 ) MI16( 2, 0xFF00|READ8() ) return; // BIT b,($FF00+n) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,12 ) BIT8( 1, b0 - 0xb0 ) MI16( 2, 0xFF00|READ8() ) return; // RES b,($FF00+n) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,12 ) BIT8( 1, b0 - 0xb8 ) MI16( 2, 0xFF00|READ8() ) return; // SET b,($FF00+n) + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JR,4,8 ) CC( 1, b0 - 0xc0 ) D8( 2, READ8() ) return; // JR cc,+d + + case 0xe0: case 0xe1: case 0xe2: /*case 0xe3:*/ case 0xe4: case 0xe5: case 0xe6: + b1 = READ8(); + switch ( b1 ) { + case 0x10: // RLD (gg) + case 0x11: // RRD (gg) + OP( RLD+b1-0x10,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(gg) + case 0x13: // DIV HL,(gg) + OP( MUL+b1-0x12,18 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) MR16( 2, b0 - 0xe0 ) return; // ADD ix,(gg) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,6 ) R8( 1, b1 - 0x28 ) MR16( 2, b0 - 0xe0 ) return; // LD r,(gg) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,8 ) R16( 1, b1 - 0x48 ) MR16( 2, b0 - 0xe0 ) return; // LD rr,(gg) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,14 ) MR16( 1, b0 - 0xe0 ) R16( 2, b1 - 0x50 ) return; // EX (gg),rr + + case 0x60: // ADD A,(gg) + case 0x61: // ADC A,(gg) + case 0x62: // SUB A,(gg) + case 0x63: // SBC A,(gg) + case 0x64: // AND A,(gg) + case 0x65: // XOR A,(gg) + case 0x66: // OR A,(gg) + case 0x67: // CP A,(gg) + OP( ADD+b1-0x60,6 ) R8( 1, A ) MR16( 2, b0 - 0xe0 ) return; + + case 0x70: // ADD HL,(gg) + case 0x71: // ADC HL,(gg) + case 0x72: // SUB HL,(gg) + case 0x73: // SBC HL,(gg) + case 0x74: // AND HL,(gg) + case 0x75: // XOR HL,(gg) + case 0x76: // OR HL,(gg) + case 0x77: // CP HL,(gg) + OP16( ADD+b1-0x70,8 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return; + + case 0x87: + OP( INC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INC (gg) + case 0x8f: + OP( DEC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DEC (gg) + + case 0x97: + OP( INCW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INCW (gg) + case 0x9f: + OP( DECW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DECW (gg) + + case 0xa0: // RLC (gg) + case 0xa1: // RRC (gg) + case 0xa2: // RL (gg) + case 0xa3: // RR (gg) + case 0xa4: // SLA (gg) + case 0xa5: // SRA (gg) + case 0xa6: // SLL (gg) + case 0xa7: // SRL (gg) + OP( RLC+b1-0xa0,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,12 ) BIT8( 1, b1 - 0x18 ) MR16( 2, b0 - 0xe0 ) return; // TSET b,(gg) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,6 ) BIT8( 1, b1 - 0xa8 ) MR16( 2, b0 - 0xe0 ) return; // BIT b,(gg) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,10 ) BIT8( 1, b1 - 0xb0 ) MR16( 2, b0 - 0xe0 ) return; // RES b,(gg) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,10 ) BIT8( 1, b1 - 0xb8 ) MR16( 2, b0 - 0xe0 ) return; // SET b,(gg) + } break; + case 0xe3: + imm16 = READ16(); + b3 = READ8(); + switch ( b3 ) { + case 0x10: // RLD (mn) + case 0x11: // RRD (mn) + OP( RLD+b3-0x10,16 ) MI16( 1, imm16 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(mn) + case 0x13: // DIV HL,(mn) + OP( MUL+b3-0x12,22 ) R16( 1, HL ) MI16( 2, imm16 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,12 ) R16( 1, IX+b3-0x14 ) MI16( 2, imm16 ) return; // ADD ix,(mn) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,10 ) R8( 1, b3 - 0x28 ) MI16( 2, imm16 ) return; // LD r,(mn) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,12 ) R16( 1, b3 - 0x48 ) MI16( 2, imm16 ) return; // LD rr,(mn) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,18 ) MI16( 1, imm16 ) R16( 2, b3 - 0x50 ) return; // EX (mn),rr + + case 0x60: // ADD A,(mn) + case 0x61: // ADC A,(mn) + case 0x62: // SUB A,(mn) + case 0x63: // SBC A,(mn) + case 0x64: // AND A,(mn) + case 0x65: // XOR A,(mn) + case 0x66: // OR A,(mn) + case 0x67: // CP A,(mn) + OP( ADD+b3-0x60,10 ) R8( 1, A ) MI16( 2, imm16 ) return; + + case 0x70: // ADD HL,(mn) + case 0x71: // ADC HL,(mn) + case 0x72: // SUB HL,(mn) + case 0x73: // SBC HL,(mn) + case 0x74: // AND HL,(mn) + case 0x75: // XOR HL,(mn) + case 0x76: // OR HL,(mn) + case 0x77: // CP HL,(mn) + OP16( ADD+b3-0x70,12 ) R16( 1, HL ) MI16( 2, imm16 ) return; + + case 0x87: + OP( INC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // INC (mn) + case 0x8f: + OP( DEC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // DEC (mn) + + case 0x97: + OP( INCW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // INCW (mn) + case 0x9f: + OP( DECW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // DECW (mn) + + case 0xa0: // RLC (mn) + case 0xa1: // RRC (mn) + case 0xa2: // RL (mn) + case 0xa3: // RR (mn) + case 0xa4: // SLA (mn) + case 0xa5: // SRA (mn) + case 0xa6: // SLL (mn) + case 0xa7: // SRL (mn) + OP( RLC+b3-0xa0,12 ) MI16( 1, imm16 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,16 ) BIT8( 1, b3 - 0x18 ) MI16( 2, imm16 ) return; // TSET b,(mn) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,10 ) BIT8( 1, b3 - 0xa8 ) MI16( 2, imm16 ) return; // BIT b,(mn) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,14 ) BIT8( 1, b3 - 0xb0 ) MI16( 2, imm16 ) return; // RES b,(mn) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,14 ) BIT8( 1, b3 - 0xb8 ) MI16( 2, imm16 ) return; // SET b,(mn) + } break; + + case 0xe7: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x10: // RLD ($FF00+n) + case 0x11: // RRD ($FF00+n) + OP( RLD+b2-0x10,14 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return; + + case 0x12: // MUL HL,($FF00+n) + case 0x13: // DIV HL,($FF00+n) + OP( MUL+b2-0x12,20 ) R16( 1, HL ) MI16( 2, 0xFF00|b1 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,10 ) R16( 1, IX+b2-0x14 ) MI16( 2, 0xFF00|b1 ) return; // ADD ix,($FF00+n) + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,14 ) BIT8( 1, b2 - 0x18 ) MI16( 2, 0xFF00|b1 ) return; // TSET b,($FF00+n) + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,8 ) R8( 1, b2 - 0x28 ) MI16( 2, 0xFF00|b1 ) return; // LD r,($FF00+n) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,10 ) R16( 1, b2 - 0x48 ) MI16( 2, 0xFF00|b1 ) return; // LD rr,($FF00+n) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,16 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x50 ) return; // EX ($FF00+n),rr + + case 0xa0: // RLC ($FF00+n) + case 0xa1: // RRC ($FF00+n) + case 0xa2: // RL ($FF00+n) + case 0xa3: // RR ($FF00+n) + case 0xa4: // SLA ($FF00+n) + case 0xa5: // SRA ($FF00+n) + case 0xa6: // SLL ($FF00+n) + case 0xa7: // SRL ($FF00+n) + OP( RLC+b2-0xa0,10 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return; + } break; + + case 0xe8: case 0xe9: case 0xea: /*case 0xeb:*/ case 0xec: case 0xed: case 0xee: + b1 = READ8(); + switch ( b1 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,6 ) MR16( 1, b0 - 0xe8 ) R8( 2, b1 - 0x20 ) return; // LD (gg),r + case 0x37: + OP( LD,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; // LD (gg),n + case 0x3f: + OP( LDW,12 ) MR16( 1, b0 - 0xe8 ) I16( 2, READ16() ) return; // LDW (gg),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,8 ) MR16( 1, b0 - 0xe8 ) R16( 2, b1 - 0x40 ) return; // LD (gg),rr + + case 0x68: // ADD (gg),n + case 0x69: // ADC (gg),n + case 0x6a: // SUB (gg),n + case 0x6b: // SBC (gg),n + case 0x6c: // AND (gg),n + case 0x6d: // XOR (gg),n + case 0x6e: // OR (gg),n + OP( ADD+b1-0x68,10 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; + case 0x6f: // CP (gg),n + OP( CP,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,6,8 ) CC( 1, b1 - 0xc0 ) R16( 2, b0 - 0xe8 ) return; // JP [cc,]gg + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,6,14 ) CC( 1, b1 - 0xd0 ) R16( 2, b0 - 0xe8 ) return; // CALL [cc,]gg + } break; + case 0xeb: + imm16 = READ16(); + b3 = READ8(); + switch ( b3 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,10 ) MI16( 1, imm16 ) R8( 2, b3 - 0x20 ) return; // LD (mn),r + case 0x37: + OP( LD,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; // LD (vw),n + case 0x3f: + OP( LDW,16 ) MI16( 1, imm16 ) I16( 2, READ16() ) return; // LDW (vw),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,12 ) MI16( 1, imm16 ) R16( 2, b3 - 0x40 ) return; // LD (mn),rr + + case 0x68: // ADD (vw),n + case 0x69: // ADC (vw),n + case 0x6a: // SUB (vw),n + case 0x6b: // SBC (vw),n + case 0x6c: // AND (vw),n + case 0x6d: // XOR (vw),n + case 0x6e: // OR (vw),n + OP( ADD+b3-0x68,14 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; + case 0x6f: // CP (vw),n + OP( ADD+b3-0x68,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,10,12 ) CC( 1, b3 - 0xc0 ) I16( 2, imm16 ) return; // JP cc,mn + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,10,18 ) CC( 1, b3 - 0xd0 ) I16( 2, imm16 ) return; // CALL cc,mn + } break; + + case 0xef: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,8 ) MI16( 1, 0xFF00|b1 ) R8( 2, b2 - 0x20 ) return; // LD ($FF00+n),r + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,10 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x40 ) return; // LD ($FF00+n),rr + + case 0x68: // ADD ($FF00+w),n + case 0x69: // ADC ($FF00+w),n + case 0x6a: // SUB ($FF00+w),n + case 0x6b: // SBC ($FF00+w),n + case 0x6c: // AND ($FF00+w),n + case 0x6d: // XOR ($FF00+w),n + case 0x6e: // OR ($FF00+w),n + OP( ADD+b2-0x68,12 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return; + case 0x6f: // CP ($FF00+w),n + OP( ADD+b2-0x68,10 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return; + } break; + + case 0xf0: case 0xf1: case 0xf2: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x10: // RLD (ix+d) + case 0x11: // RRD (ix+d) + OP( RLD+b2-0x10,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(ix+d) + case 0x13: // DIV HL,(ix+d) + OP( MUL+b2-0x12,22 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,12 ) R16( 1, IX+b2-0x14 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // ADD ix,(jx+d) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,10 ) R8( 1, b2 - 0x28 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD r,(ix+d) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,12 ) R16( 1, b2 - 0x48 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD rr,(ix+d) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,18 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) R16( 2, b2 - 0x50 ) return; // EX (ix+d),rr + + case 0x60: // ADD A,(ix+d) + case 0x61: // ADC A,(ix+d) + case 0x62: // SUB A,(ix+d) + case 0x63: // SBC A,(ix+d) + case 0x64: // AND A,(ix+d) + case 0x65: // XOR A,(ix+d) + case 0x66: // OR A,(ix+d) + case 0x67: // CP A,(ix+d) + OP( ADD+b2-0x60,10 ) R8( 1, A ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x70: // ADD HL,(ix+d) + case 0x71: // ADC HL,(ix+d) + case 0x72: // SUB HL,(ix+d) + case 0x73: // SBC HL,(ix+d) + case 0x74: // AND HL,(ix+d) + case 0x75: // XOR HL,(ix+d) + case 0x76: // OR HL,(ix+d) + case 0x77: // CP HL,(ix+d) + OP16( ADD+b2-0x70,12 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x87: + OP( INC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INC (ix+d) + case 0x8f: + OP( DEC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DEC (ix+d) + + case 0x97: + OP( INCW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INCW (ix+d) + case 0x9f: + OP( DECW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DECW (ix+d) + + case 0xa0: // RLC (ix+d) + case 0xa1: // RRC (ix+d) + case 0xa2: // RL (ix+d) + case 0xa3: // RR (ix+d) + case 0xa4: // SLA (ix+d) + case 0xa5: // SRA (ix+d) + case 0xa6: // SLL (ix+d) + case 0xa7: // SRL (ix+d) + OP( RLC+b2-0xa0,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,16 ) BIT8( 1, b2 - 0x18 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // TSET b,(ix+d) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,10 ) BIT8( 1, b2 - 0xa8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // BIT b,(ix+d) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,14 ) BIT8( 1, b2 - 0xb0 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // RES b,(ix+d) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,14 ) BIT8( 1, b2 - 0xb8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // SET b,(ix+d) + } break; + + case 0xf3: + b1 = READ8(); + switch ( b1 ) { + case 0x10: // RLD (HL+A) + case 0x11: // RRD (HL+A) + OP( RLD+b1-0x10,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; + + case 0x12: // MUL HL,(HL+A) + case 0x13: // DIV HL,(HL+A) + OP( MUL+b1-0x12,26 ) R16( 1, HL ) MR16R8( 2, HL, A ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,16 ) R16( 1, IX+b1-0x14 ) MR16R8( 2, HL, A ) return; // ADD ix,(HL+A) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,14 ) R8( 1, b1 - 0x28 ) MR16R8( 2, HL, A ) return; // LD r,(HL+A) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,16 ) R16( 1, b1 - 0x48 ) MR16R8( 2, HL, A ) return; // LD rr,(HL+A) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,22 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x50 ) return; // EX (HL+A),rr + + case 0x60: // ADD A,(HL+A) + case 0x61: // ADC A,(HL+A) + case 0x62: // SUB A,(HL+A) + case 0x63: // SBC A,(HL+A) + case 0x64: // AND A,(HL+A) + case 0x65: // XOR A,(HL+A) + case 0x66: // OR A,(HL+A) + case 0x67: // CP A,(HL+A) + OP( ADD+b1-0x60,14 ) R8( 1, A ) MR16R8( 2, HL, A ) return; + + case 0x70: // ADD HL,(HL+A) + case 0x71: // ADC HL,(HL+A) + case 0x72: // SUB HL,(HL+A) + case 0x73: // SBC HL,(HL+A) + case 0x74: // AND HL,(HL+A) + case 0x75: // XOR HL,(HL+A) + case 0x76: // OR HL,(HL+A) + case 0x77: // CP HL,(HL+A) + OP16( ADD+b1-0x70,16 ) R16( 1, HL ) MR16R8( 2, HL, A ) return; + + case 0x87: + OP( INC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INC (HL+A) + case 0x8f: + OP( DEC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DEC (HL+A) + + case 0x97: + OP( INCW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INCW (HL+A) + case 0x9f: + OP( DECW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DECW (HL+A) + + case 0xa0: // RLC (HL+A) + case 0xa1: // RRC (HL+A) + case 0xa2: // RL (HL+A) + case 0xa3: // RR (HL+A) + case 0xa4: // SLA (HL+A) + case 0xa5: // SRA (HL+A) + case 0xa6: // SLL (HL+A) + case 0xa7: // SRL (HL+A) + OP( RLC+b1-0xa0,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,20 ) BIT8( 1, b1 - 0x18 ) MR16R8( 2, HL, A ) return; // TSET b,(HL+A) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,14 ) BIT8( 1, b1 - 0xa8 ) MR16R8( 2, HL, A ) return; // BIT b,(HL+A) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,18 ) BIT8( 1, b1 - 0xb0 ) MR16R8( 2, HL, A ) return; // RES b,(HL+A) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,18 ) BIT8( 1, b1 - 0xb8 ) MR16R8( 2, HL, A ) return; // SET b,(HL+A) + } break; + + case 0xf4: case 0xf5: case 0xf6: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,10 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R8( 2, b2 - 0x20 ) return; // LD (ix+d),r + case 0x37: + OP( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; // LD (ix+d),n + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP( LDA,10 ) R16( 1, b2 - 0x38 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // LDA rr,ix+d + case 0x3f: + OP( LDW,16 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I16( 2, READ16() ) return; // LDW (ix+d),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R16( 2, b2 - 0x40 ) return; // LD (ix+d),rr + + case 0x68: // ADD (ix+d),n + case 0x69: // ADC (ix+d),n + case 0x6a: // SUB (ix+d),n + case 0x6b: // SBC (ix+d),n + case 0x6c: // AND (ix+d),n + case 0x6d: // XOR (ix+d),n + case 0x6e: // OR (ix+d),n + OP( ADD+b2-0x68,14) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; + case 0x6f: // CP (ix+d),n + OP( ADD+b2-0x68,12) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,10,12 ) CC( 1, b2 - 0xc0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // JP [cc,]ix+d + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,10,18 ) CC( 1, b2 - 0xd0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // CALL [cc,]ix+d + } break; + + case 0xf7: + b1 = READ8(); + switch ( b1 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,14 ) MR16R8( 1, HL, A ) R8( 2, b1 - 0x20 ) return; // LD (HL+A),r + case 0x37: + OP( LD,16 ) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; // LD (HL+A),n + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP( LDA,14 ) R16( 1, b1 - 0x38 ) R16R8( 2, HL, A ) return; // LDA rr,HL+A + case 0x3f: + OP( LDW,20 ) MR16R8( 1, HL, A ) I16( 2, READ16() ) return; // LDW (HL+A),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,16 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x40 ) return; // LD (HL+A),rr + + case 0x68: // ADD (HL+A),n + case 0x69: // ADC (HL+A),n + case 0x6a: // SUB (HL+A),n + case 0x6b: // SBC (HL+A),n + case 0x6c: // AND (HL+A),n + case 0x6d: // XOR (HL+A),n + case 0x6e: // OR (HL+A),n + OP( ADD+b1-0x68,18) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; + case 0x6f: // CP (HL+A),n + OP( ADD+b1-0x68,16) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,14,16 ) CC( 1, b1 - 0xc0 ) R16R8( 2, HL, A ) return; // JP [cc,]HL+A + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,14,22 ) CC( 1, b1 - 0xd0 ) R16R8( 2, HL, A ) return; // CALL [cc,]HL+A + } break; + + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: + b1 = READ8(); + switch ( b1 ) { + case 0x12: // MUL HL,g + case 0x13: // DIV HL,g + OP( MUL+b1-0x12,18) R16( 1, HL ) R8( 2, b0 - 0xf8 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) R16( 2, b0 - 0xf8 ) return; // ADD ix,gg + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: + OP( LD,4 ) R8( 1, b1 - 0x30 ) R8( 2, b0 - 0xf8 ) return; // LD r,g + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP16( LD,6 ) R16( 1, b1 - 0x38 ) R16( 2, b0 - 0xf8 ) return; // LD rr,gg + + case 0x58: // LDI + case 0x59: // LDIR + case 0x5a: // LDD + case 0x5b: // LDDR + case 0x5c: // CPI + case 0x5d: // CPIR + case 0x5e: // CPD + case 0x5f: // CPDR + if (b0 == 0xfe) { + OPCC( LDI+b1-0x58,14,18 ) NONE( 1 ) NONE( 2 ) return; + } + + case 0x60: // ADD A,g + case 0x61: // ADC A,g + case 0x62: // SUB A,g + case 0x63: // SBC A,g + case 0x64: // AND A,g + case 0x65: // XOR A,g + case 0x66: // OR A,g + case 0x67: // CP A,g + OP( ADD+b1-0x60,4 ) R8( 1, A ) R8( 2, b0 - 0xf8 ) return; + + case 0x68: // ADD g,n + case 0x69: // ADC g,n + case 0x6a: // SUB g,n + case 0x6b: // SBC g,n + case 0x6c: // AND g,n + case 0x6d: // XOR g,n + case 0x6e: // OR g,n + case 0x6f: // CP g,n + OP( ADD+b1-0x68,6 ) R8( 1, b0 - 0xf8 ) I8( 2, READ8() ) return; + + case 0x70: // ADD HL,gg + case 0x71: // ADC HL,gg + case 0x72: // SUB HL,gg + case 0x73: // SBC HL,gg + case 0x74: // AND HL,gg + case 0x75: // XOR HL,gg + case 0x76: // OR HL,gg + case 0x77: // CP HL,gg + OP16( ADD+b1-0x70,8 ) R16( 1, HL ) R16( 2, b0 - 0xf8 ) return; + + case 0xa0: // RLC g + case 0xa1: // RRC g + case 0xa2: // RL g + case 0xa3: // RR g + case 0xa4: // SLA g + case 0xa5: // SRA g + case 0xa6: // SLL g + case 0xa7: // SRL g + OP( RLC+b1-0xa0,4 ) R8( 1, b0 - 0xf8 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,8 ) BIT8( 1, b1 - 0x18 ) R8( 2, b0 - 0xf8 ) return; // TSET b,g + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,4 ) BIT8( 1, b1 - 0xa8 ) R8( 2, b0 - 0xf8 ) return; // BIT b,g + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,4 ) BIT8( 1, b1 - 0xb0 ) R8( 2, b0 - 0xf8 ) return; // RES b,g + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,4 ) BIT8( 1, b1 - 0xb8 ) R8( 2, b0 - 0xf8 ) return; // SET b,g + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + if (b0 == 0xfe) { + OPCC( RET,6,14 ) CC( 1, b1 - 0xd0 ) NONE( 2 ) return; // RET cc + } + } break; + + case 0xff: + OP( SWI,20 ) NONE( 1 ) NONE( 2 ) return; // SWI + } + + OP( UNKNOWN,2 ) NONE( 1 ) NONE( 2 ) +} + +static const char *const ir_names[] = { + "P0", "P1", "P01CR/IRFL", "IRFH", "P2", "P2CR", "P3", "P3CR", + "P4", "P4CR", "P5", "SMMOD", "P6", "P7", "P67CR", "SMCR", + "P8", "P8CR", "WDMOD", "WDCR", "TREG0", "TREG1", "TREG2", "TREG3", + "TCLK", "TFFCR", "TMOD", "TRUN", "CAP1L", "CAP1H", "CAP2L", "CAL2H", + "TREG4L", "TREG4H", "TREG5L", "TREG5H", "T4MOD", "T4FFCR", "INTEL", "INTEH", + "DMAEH", "SCMOD", "SCCR", "SCBUF", "BX", "BY", "ADREG", "ADMOD" +}; + +const char *tlcs90_device::internal_registers_names(UINT16 x) +{ + int ir = x - T90_IOBASE; + if ( ir >= 0 && ir < ARRAY_LENGTH(ir_names) ) + return ir_names[ir]; + return NULL; +} +int tlcs90_device::sprint_arg(char *buffer, UINT32 pc, const char *pre, const e_mode mode, const UINT16 r, const UINT16 rb) +{ + const char *reg_name; + switch ( mode ) + { + case MODE_NONE: return 0; + + case MODE_BIT8: return sprintf( buffer, "%s%d", pre, r ); + case MODE_I8: return sprintf( buffer, "%s$%02X", pre, r ); + case MODE_D8: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7f)-(r&0x80))&0xffff ); + case MODE_I16: return sprintf( buffer, "%s$%04X", pre, r ); + case MODE_D16: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7fff)-(r&0x8000))&0xffff ); + case MODE_MI16: + reg_name = internal_registers_names(r); + return (reg_name) ? sprintf( buffer, "%s(%s)", pre, reg_name ): + sprintf( buffer, "%s($%04X)", pre, r ); + case MODE_R8: return sprintf( buffer, "%s%s", pre, r8_names[r] ); + case MODE_R16: return sprintf( buffer, "%s%s", pre, r16_names[r] ); + case MODE_MR16: return sprintf( buffer, "%s(%s)", pre, r16_names[r] ); + + case MODE_MR16R8: return sprintf( buffer, "%s(%s+%s)", pre, r16_names[r], r8_names[rb] ); + case MODE_MR16D8: return sprintf( buffer, "%s(%s%c$%02X)", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb ); + + case MODE_CC: return sprintf( buffer, "%s%s", pre, cc_names[r] ); + + case MODE_R16R8: return sprintf( buffer, "%s%s+%s", pre, r16_names[r], r8_names[rb] ); + case MODE_R16D8: return sprintf( buffer, "%s%s%c$%02X", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb ); + + default: + fatalerror("%04x: unimplemented addr mode = %d\n",pc,mode); + } + + // never executed + //return 0; +} + +offs_t tlcs90_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + int len; + + m_addr = pc; + + decode(); + m_op &= ~OP_16; + + buffer += sprintf ( buffer, "%-5s", op_names[ m_op ] ); // strlen("callr") == 5 + len = sprint_arg ( buffer, pc, " ", m_mode1, m_r1, m_r1b ); + buffer += len; + buffer += sprint_arg ( buffer, pc, (len>1)?",":"", m_mode2, m_r2, m_r2b ); + + return (m_addr - pc) | DASMFLAG_SUPPORTED; +} + + +UINT16 tlcs90_device::r8( const UINT16 r ) +{ + switch( r ) + { + case A: return m_af.b.h; + case B: return m_bc.b.h; + case C: return m_bc.b.l; + case D: return m_de.b.h; + case E: return m_de.b.l; + case H: return m_hl.b.h; + case L: return m_hl.b.l; + + default: + fatalerror("%04x: unimplemented r8 register index = %d\n",m_pc.w.l,r); + } +} + +void tlcs90_device::w8( const UINT16 r, UINT16 value ) +{ + switch( r ) + { + case A: m_af.b.h = value; return; + case B: m_bc.b.h = value; return; + case C: m_bc.b.l = value; return; + case D: m_de.b.h = value; return; + case E: m_de.b.l = value; return; + case H: m_hl.b.h = value; return; + case L: m_hl.b.l = value; return; + + default: + fatalerror("%04x: unimplemented w8 register index = %d\n",m_pc.w.l,r); + } +} + +UINT16 tlcs90_device::r16( const UINT16 r ) +{ + switch( r ) + { + case BC: return m_bc.w.l; + case DE: return m_de.w.l; + case HL: return m_hl.w.l; + case IX: return m_ix.w.l; + case IY: return m_iy.w.l; + case SP: return m_sp.w.l; + case AF: return m_af.w.l; +// case AF2: return m_af2.w.l; +// one interrupt flip-flop? Needed by e.g. mjifb + case AF2: return (m_af2.w.l & (~IF)) | (m_af.w.l & IF); + case PC: return m_pc.w.l; + + default: + fatalerror("%04x: unimplemented r16 register index = %d\n",m_pc.w.l,r); + } +} + +void tlcs90_device::w16( const UINT16 r, UINT16 value ) +{ + switch( r ) + { + case BC: m_bc.w.l = value; return; + case DE: m_de.w.l = value; return; + case HL: m_hl.w.l = value; return; + case IX: m_ix.w.l = value; return; + case IY: m_iy.w.l = value; return; + case SP: m_sp.w.l = value; return; + case AF: m_af.w.l = value; return; + case AF2: m_af2.w.l = value; return; + case PC: m_pc.d = value; return; + + default: + fatalerror("%04x: unimplemented w16 register index = %d\n",m_pc.w.l,r); + } +} + + +#define READ_FN( N ) \ +UINT8 tlcs90_device::Read##N##_8() { \ + switch ( m_mode##N ) { \ + case MODE_CC: \ + case MODE_BIT8: \ + case MODE_I8: return (UINT8)m_r##N; \ + case MODE_D8: return (UINT8)m_r##N; \ + case MODE_R8: return (UINT8)r8(m_r##N); \ + case MODE_MI16: return RM8(m_r##N); \ + case MODE_MR16R8: return RM8((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b))); \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: return RX8(m_ix.w.l,m_ixbase); \ + case IY: return RX8(m_iy.w.l,m_iybase); \ + } \ + return RM8(r16(m_r##N)); \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: return RX8((UINT16)(m_ix.w.l + (INT8)m_r##N##b),m_ixbase); \ + case IY: return RX8((UINT16)(m_iy.w.l + (INT8)m_r##N##b),m_iybase); \ + } \ + return RM8((UINT16)(r16(m_r##N) + (INT8)m_r##N##b)); \ + default: \ + fatalerror("%04x: unimplemented Read%d_8 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ + return 0; \ +} \ +UINT16 tlcs90_device::Read##N##_16() { \ + switch ( m_mode##N ) { \ + case MODE_I16: return m_r##N; \ + case MODE_D16: return m_r##N - 1; \ + case MODE_R16: return r16(m_r##N); \ + case MODE_R16D8: return r16(m_r##N) + (INT8)m_r##N##b; \ + case MODE_R16R8: return r16(m_r##N) + (INT8)r8(m_r##N##b); \ + case MODE_MI16: return RM16(m_r##N); \ + case MODE_MR16R8: return RM16((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b))); \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: return RX16(m_ix.w.l,m_ixbase); \ + case IY: return RX16(m_iy.w.l,m_iybase); \ + } \ + return RM16(r16(m_r##N)); \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: return RX16((UINT16)(m_ix.w.l + (INT8)m_r##N##b),m_ixbase); \ + case IY: return RX16((UINT16)(m_iy.w.l + (INT8)m_r##N##b),m_iybase); \ + } \ + return RM16((UINT16)(r16(m_r##N) + (INT8)m_r##N##b)); \ + default: \ + fatalerror("%04x: unimplemented Read%d_16 modes = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ + return 0; \ +} + + + +#define WRITE_FN( N ) \ +void tlcs90_device::Write##N##_8( UINT8 value ) { \ + switch ( m_mode##N ) { \ + case MODE_R8: w8(m_r##N,value); return; \ + case MODE_MI16: WM8(m_r##N, value); return; \ + case MODE_MR16R8: WM8((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b)), value); return; \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: WX8(m_ix.w.l,value,m_ixbase); return; \ + case IY: WX8(m_iy.w.l,value,m_iybase); return; \ + } \ + WM8(r16(m_r##N), value); return; \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: WX8((UINT16)(m_ix.w.l + (INT8)m_r##N##b),value,m_ixbase); return; \ + case IY: WX8((UINT16)(m_iy.w.l + (INT8)m_r##N##b),value,m_iybase); return; \ + } \ + WM8((UINT16)(r16(m_r##N) + (INT8)m_r##N##b), value); return; \ + default: \ + fatalerror("%04x: unimplemented Write%d_8 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ +} \ +void tlcs90_device::Write##N##_16( UINT16 value ) \ +{ \ + switch ( m_mode##N ) { \ + case MODE_R16: w16(m_r##N,value); return; \ + case MODE_MI16: WM16(m_r##N, value); return; \ + case MODE_MR16R8: WM16((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b)), value); return; \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: WX16(m_ix.w.l,value,m_ixbase); return; \ + case IY: WX16(m_iy.w.l,value,m_iybase); return; \ + } \ + WM16(r16(m_r##N), value); return; \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: WX16((UINT16)(m_ix.w.l + (INT8)m_r##N##b),value,m_ixbase); return; \ + case IY: WX16((UINT16)(m_iy.w.l + (INT8)m_r##N##b),value,m_iybase); return; \ + } \ + WM16((UINT16)(r16(m_r##N) + (INT8)m_r##N##b), value); return; \ + default: \ + fatalerror("%04x: unimplemented Write%d_16 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ +} + +READ_FN(1) +READ_FN(2) +WRITE_FN(1) +WRITE_FN(2) + +int tlcs90_device::Test( UINT8 cond ) +{ + int s,v; + switch ( cond ) + { + case FLS: return 0; + case LT: s = F & SF; v = F & VF; return (s && !v) || (!s && v); + case LE: s = F & SF; v = F & VF; return (F & ZF) || (s && !v) || (!s && v); + case ULE: return (F & CF) || (F & ZF); + case OV: return F & VF; + case MI: return F & SF; + case Z: return F & ZF; + case CR: return F & CF; + case T: return 1; + case GE: s = F & SF; v = F & VF; return (s && v) || (!s && !v); + case GT: s = F & SF; v = F & VF; return !((F & ZF) || (s && !v) || (!s && v)); + case UGT: return !(F & CF) && !(F & ZF); + case NOV: return !(F & VF); + case PL: return !(F & SF); + case NZ: return !(F & ZF); + case NC: return !(F & CF); + default: + fatalerror("%04x: unimplemented condition = %d\n",m_pc.w.l,cond); + } + + // never executed + //return 0; +} + +void tlcs90_device::Push( UINT16 rr ) +{ + m_sp.w.l -= 2; + WM16( m_sp.w.l, r16(rr) ); +} +void tlcs90_device::Pop( UINT16 rr ) +{ + w16( rr, RM16( m_sp.w.l ) ); + m_sp.w.l += 2; +} + +/************************************************************************************************************* + +Interrupts + +---------------------------------------------------------------------------------------------------------------- +Priority Type Interrupt Source Vector/8 Vector Address uDMA Address +---------------------------------------------------------------------------------------------------------------- +1 Non Maskable SWI - 10 0010 - +2 "" NMI - 18 0018 - +3 "" INTWD Watch Dog - 20 0020 - +4 Maskable INT0 External 0 05 28 0028 FF28 +5 "" INTT0 Timer 0 06 30 0030 FF30 +6 "" INTT1 Timer 1 07 38 0038 FF38 +7 "" INTAD A/D 08 40 0040 FF48 +"" "" INTT2 Timer 2 "" "" "" "" +8 "" INTT3 Timer 3 09 48 0048 FF48 +9 "" INTT4 Timer 4 0A 50 0050 FF50 +10 "" INT1 External 1 0B 58 0058 FF58 +11 "" INTT5 Timer 5 0C 60 0060 FF60 +12 "" INT2 External 2 0D 68 0068 FF68 +13 "" INTRX End Serial Receive 0E 70 0070 FF70 +14 "" INTTX End Serial Transmit 0F 78 0078 FF78 + +---------------------------------------------------------------------------------------------------------------- +Interrupt Terminal Mode How To Set +---------------------------------------------------------------------------------------------------------------- +NMI - Falling Edge - +INT0 P80 Level P8CR<EDGE> = 0 + Rising Edge P8CR<EDGE> = 1 +INT1 P81 Rising Edge T4MOD<CAPM1,0> = 0,0 or 0,1 or 1,1 + Falling Edge T4MOD<CAPM1,0> = 1,0 +INT2 P82 Rising Edge - + +*************************************************************************************************************/ + +void tlcs90_device::leave_halt() +{ + if( m_halt ) + { + m_halt = 0; + m_pc.w.l++; + } +} + +void tlcs90_device::take_interrupt(tlcs90_e_irq irq) +{ + m_irq_state &= ~(1 << irq); + + leave_halt(); + + Push( PC ); + Push( AF ); + + F &= ~IF; + + m_pc.w.l = 0x10 + irq * 8; + + m_extra_cycles += 20*2; +} + +void tlcs90_device::check_interrupts() +{ + tlcs90_e_irq irq; + int mask; + + if (!(F & IF)) + return; + + for (irq = INTSWI; irq < INTMAX; irq++) + { + mask = (1 << irq); + if(irq >= INT0) mask &= m_irq_mask; + if ( m_irq_state & mask ) + { + take_interrupt( irq ); + return; + } + } +} + +void tlcs90_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) { + case INPUT_LINE_NMI: + set_irq_line(INTNMI, state); + break; + case INPUT_LINE_IRQ0: + set_irq_line(INT0, state); + break; + case INPUT_LINE_IRQ1: + set_irq_line(INT1, state); + break; + case INPUT_LINE_IRQ2: + set_irq_line(INT2, state); + break; + } +} + +void tlcs90_device::set_irq_line(int irq, int state) +{ + if ( ((m_irq_state >> irq)&1) == state ) return; + + if (state) + { + m_irq_state |= 1 << irq; + check_interrupts(); + } + else + { + m_irq_state &= ~(1 << irq); + } +} + +void tlcs90_device::Cyc() { m_icount -= m_cyc_t; } +void tlcs90_device::Cyc_f() { m_icount -= m_cyc_f; } + +void tlcs90_device::execute_run() +{ + UINT8 a8,b8; + UINT16 a16,b16; + unsigned a32; + PAIR tmp; + + m_icount -= m_extra_cycles; + m_extra_cycles = 0; + + do + { + m_prvpc.d = m_pc.d; + debugger_instruction_hook(this, m_pc.d); + + check_interrupts(); + + m_addr = m_pc.d; + decode(); + m_pc.d = m_addr; + + switch ( m_op ) + { + case NOP: + Cyc(); + break; + + case EX: + a16 = Read1_16(); + Write1_16( Read2_16() ); + Write2_16( a16 ); + Cyc(); + break; + case EXX: + tmp = m_bc; m_bc = m_bc2; m_bc2 = tmp; + tmp = m_de; m_de = m_de2; m_de2 = tmp; + tmp = m_hl; m_hl = m_hl2; m_hl2 = tmp; + Cyc(); + break; + + case LD: + Write1_8( Read2_8() ); + Cyc(); + break; + case LDW: + case LD | OP_16: + Write1_16( Read2_16() ); + Cyc(); + break; + +// case LDA: +// Cyc(); +// break; + + case LDI: +#define _LDI \ + WM8( m_de.w.l, RM8(m_hl.w.l) ); \ + m_de.w.l++; \ + m_hl.w.l++; \ + m_bc.w.l--; \ + F &= SF | ZF | IF | XCF | CF; \ + if ( m_bc.w.l ) F |= VF; + + _LDI + Cyc(); + break; + case LDIR: + _LDI + if ( m_bc.w.l ) + { + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + case LDD: +#define _LDD \ + WM8( m_de.w.l, RM8(m_hl.w.l) ); \ + m_de.w.l--; \ + m_hl.w.l--; \ + m_bc.w.l--; \ + F &= SF | ZF | IF | XCF | CF; \ + if ( m_bc.w.l ) F |= VF; + + _LDD + Cyc(); + break; + case LDDR: + _LDD + if ( m_bc.w.l ) + { + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + +// case CPD: +// Cyc(); +// break; +// case CPDR: +// Cyc(); +// break; + case CPI: + a8 = RM8(m_hl.w.l); + b8 = m_af.b.h - a8; + m_hl.w.l++; + m_bc.w.l--; + F = (F & (IF | CF)) | SZ[b8] | ((m_af.b.h^a8^b8)&HF) | NF; + if ( m_bc.w.l ) F |= VF; + Cyc(); + break; + case CPIR: + a8 = RM8(m_hl.w.l); + b8 = m_af.b.h - a8; + m_hl.w.l++; + m_bc.w.l--; + F = (F & (IF | CF)) | SZ[b8] | ((m_af.b.h^a8^b8)&HF) | NF; + if ( m_bc.w.l ) + { + F |= VF; + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + case PUSH: + Push( m_r1 ); + Cyc(); + break; + case POP: + Pop( m_r1 ); + Cyc(); + break; + + case JP: + if ( Test( Read1_8() ) ) + { + m_pc.w.l = Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + case JR: + if ( Test( Read1_8() ) ) + { + m_pc.w.l += /*2 +*/ (INT8)Read2_8(); + Cyc(); + } + else Cyc_f(); + break; + case JR | OP_16: + if ( Test( Read1_8() ) ) + { + m_pc.w.l += /*2 +*/ Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + + + case CALL: + if ( Test( Read1_8() ) ) + { + Push( PC ); + m_pc.w.l = Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + case CALLR: + Push( PC ); + m_pc.w.l += /*2 +*/ Read1_16(); + Cyc(); + break; + + case RET: + if ( Test( Read1_8() ) ) + { + Pop( PC ); + Cyc(); + } + else Cyc_f(); + break; + case RETI: + Pop( AF ); + Pop( PC ); + Cyc(); + break; + +// case HALT: +// Cyc(); +// break; + case DI: + m_after_EI = 0; + F &= ~IF; + Cyc(); + break; + case EI: + m_after_EI = !(F & IF); + Cyc(); + break; + + case SWI: + Cyc(); + take_interrupt( INTSWI ); + break; + + case DAA: + { + UINT8 cf, nf, hf, lo, hi, diff; + cf = F & CF; + nf = F & NF; + hf = F & HF; + lo = m_af.b.h & 15; + hi = m_af.b.h / 16; + + if (cf) + { + diff = (lo <= 9 && !hf) ? 0x60 : 0x66; + } + else + { + if (lo >= 10) + { + diff = hi <= 8 ? 0x06 : 0x66; + } + else + { + if (hi >= 10) + { + diff = hf ? 0x66 : 0x60; + } + else + { + diff = hf ? 0x06 : 0x00; + } + } + } + if (nf) m_af.b.h -= diff; + else m_af.b.h += diff; + + F = SZP[A] | (F & (IF | NF)); + if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) F |= XCF | CF; + if (nf ? hf && lo <= 5 : lo >= 10) F |= HF; + } + Cyc(); + break; + + + case CPL: + m_af.b.h ^= 0xff; + F |= HF | NF; + Cyc(); + break; + case NEG: + a8 = 0; + b8 = m_af.b.h; + a32 = a8 - b8; + F = (F & IF) | SZ[(UINT8)a32] | NF; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF; + m_af.b.h = a32; + Cyc(); + break; + + case LDAR: + m_hl.w.l = m_pc.w.l + /*2 +*/ Read2_16(); + Cyc(); + break; + + case RCF: + F &= SF | ZF | IF | VF; + Cyc(); + break; + case SCF: + F = (F & (SF | ZF | IF | VF)) | XCF | CF; + Cyc(); + break; + case CCF: + F = (F & (SF | ZF | IF | VF)) | ((F & CF)?HF:(XCF | CF)); + Cyc(); + break; + +// case TSET: +// Cyc(); +// break; + case BIT: + F = (F & (IF | CF)) | HF | SZ_BIT[ Read2_8() & (1 << Read1_8()) ]; + Cyc(); + break; + case SET: + Write2_8( Read2_8() | (1 << Read1_8()) ); + Cyc(); + break; + case RES: + Write2_8( Read2_8() & (~(1 << Read1_8())) ); + Cyc(); + break; + + case INC: + a8 = Read1_8() + 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_inc[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + break; + case INCX: + if ( F & XCF ) + { + a8 = Read1_8() + 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_inc[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + } + else Cyc_f(); + break; + case INC | OP_16: + a16 = Read1_16() + 1; + Write1_16( a16 ); + if (a16 == 0) F |= XCF; + else F &= ~XCF; + Cyc(); + break; + case INCW: + a16 = Read1_16(); + a32 = a16 + 1; + Write1_16( a32 ); + F &= IF | CF; + if ((UINT16)a32 == 0) F |= ZF | XCF; + if (a32 & 0x8000) F |= SF; + if ((a16 ^ 0x8000) & a32 & 0x8000) F |= VF; + if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //?? + Cyc(); + break; + + + case DEC: + a8 = Read1_8() - 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_dec[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + break; + case DECX: + if ( F & XCF ) + { + a8 = Read1_8() - 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_dec[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + } + else Cyc_f(); + break; + case DEC | OP_16: + a16 = Read1_16() - 1; + Write1_16( a16 ); + if (a16 == 0) F |= XCF; + else F &= ~XCF; + Cyc(); + break; + case DECW: + a16 = Read1_16(); + a32 = a16 - 1; + Write1_16( a32 ); + F = (F & (IF | CF)) | NF; + if ((UINT16)a32 == 0) F |= ZF | XCF; + if (a32 & 0x8000) F |= SF; + if (a16 == 0x8000) F |= VF; + if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //?? + Cyc(); + break; + + case ADD: + case ADC: + a8 = Read1_8(); + b8 = Read2_8(); + a32 = a8 + b8; + if ( (m_op == ADC) && (F & CF) ) a32 += 1; + Write1_8( a32 ); + F = (F & IF) | SZ[(UINT8)a32]; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8 ^ 0x80) & (b8 ^ a32) & 0x80) F |= VF; + Cyc(); + break; + case ADD | OP_16: + case ADC | OP_16: + a16 = Read1_16(); + b16 = Read2_16(); + a32 = a16 + b16; + if ( (m_op == (ADC | OP_16)) && (F & CF) ) a32 += 1; + Write1_16( a32 ); + if ( (m_op == (ADD | OP_16)) && m_mode2 == MODE_R16 ) + { + F &= SF | ZF | IF | VF; + } + else + { + F &= IF; + if ((UINT16)a32 == 0) F |= ZF; + if (a32 & 0x8000) F |= SF; + if ((b16 ^ a16 ^ 0x8000) & (b16 ^ a32) & 0x8000) F |= VF; + } + if (a32 & 0x10000) F |= CF | XCF; //X? + if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //?? + Cyc(); + break; + + case CP: + case SUB: + case SBC: + a8 = Read1_8(); + b8 = Read2_8(); + a32 = a8 - b8; + if ( (m_op == SBC) && (F & CF) ) a32 -= 1; + F = (F & IF) | SZ[(UINT8)a32] | NF; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF; + if (m_op != CP) + Write1_8( a32 ); + Cyc(); + break; + case CP | OP_16: + case SUB | OP_16: + case SBC | OP_16: + a16 = Read1_16(); + b16 = Read2_16(); + a32 = a16 - b16; + if ( (m_op == (SBC | OP_16)) && (F & CF) ) a32 -= 1; + F = (F & IF) | NF; + if ((UINT16)a32 == 0) F |= ZF; + if (a32 & 0x8000) F |= SF; + if (a32 & 0x10000) F |= CF | XCF; //X? + if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //?? + if ((b16 ^ a16) & (a16 ^ a32) & 0x8000) F |= VF; + if (m_op != (CP | OP_16)) + Write1_16( a32 ); + Cyc(); + break; + + case AND: + a8 = Read1_8() & Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8] | HF; + Cyc(); + break; + case AND | OP_16: + a16 = Read1_16() & Read2_16(); + Write1_16( a16 ); + F = (F & IF) | HF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + case XOR: + a8 = Read1_8() ^ Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8]; + Cyc(); + break; + case XOR | OP_16: + a16 = Read1_16() ^ Read2_16(); + Write1_16( a16 ); + F &= IF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + case OR: + a8 = Read1_8() | Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8]; + Cyc(); + break; + case OR | OP_16: + a16 = Read1_16() | Read2_16(); + Write1_16( a16 ); + F &= IF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + + case RLC: + a8 = Read1_8(); + a8 = (a8 << 1) | (a8 >> 7); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (a8 & 0x01) F |= CF | XCF; // X? + Cyc(); + break; + case RRC: + a8 = Read1_8(); + a8 = (a8 >> 1) | (a8 << 7); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (a8 & 0x80) F |= CF | XCF; // X? + Cyc(); + break; + case RL: + a8 = Read1_8(); + b8 = a8 & 0x80; + a8 <<= 1; + if (F & CF) a8 |= 0x01; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case RR: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 >>= 1; + if (F & CF) a8 |= 0x80; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + + case SLA: + case SLL: + a8 = Read1_8(); + b8 = a8 & 0x80; + a8 <<= 1; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case SRA: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 = (a8 & 0x80) | (a8 >> 1); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case SRL: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 >>= 1; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case RLD: + a8 = m_af.b.h; + b8 = Read1_8(); + Write1_8( (b8 << 4) | (a8 & 0x0f) ); + a8 = (a8 & 0xf0) | (b8 >> 4); + F = (F & (IF | CF)) | SZP[a8]; + m_af.b.h = a8; + Cyc(); + break; + case RRD: + a8 = m_af.b.h; + b8 = Read1_8(); + Write1_8( (b8 >> 4) | (a8 << 4) ); + a8 = (a8 & 0xf0) | (b8 & 0x0f); + F = (F & (IF | CF)) | SZP[a8]; + m_af.b.h = a8; + Cyc(); + break; + + case DJNZ: + if ( --m_bc.b.h ) + { + m_pc.w.l += /*2 +*/ (INT8)Read1_8(); + Cyc(); + } + else Cyc_f(); + break; + case DJNZ | OP_16: + if ( --m_bc.w.l ) + { + m_pc.w.l += /*2 +*/ (INT8)Read2_8(); + Cyc(); + } + else Cyc_f(); + break; + + case MUL: + m_hl.w.l = (UINT16)m_hl.b.l * (UINT16)Read2_8(); + Cyc(); + break; + case DIV: + a16 = m_hl.w.l; + b16 = (UINT16)Read2_8(); + if (b16 == 0) + { + F |= VF; + m_hl.w.l = (a16 << 8) | ((a16 >> 8) ^ 0xff); + } + else + { + m_hl.b.h = a16 % b16; + a16 /= b16; + if (a16 > 0xff) F |= VF; + else F &= ~VF; + m_hl.b.l = a16; + } + Cyc(); + break; + + default: + fatalerror("%04x: unimplemented opcode, op=%02x\n",pc(),m_op); + } + + if ( m_op != EI ) + if (m_after_EI) + { + F |= IF; + m_after_EI = 0; + } + + } while( m_icount > 0 ); + + m_icount -= m_extra_cycles; + m_extra_cycles = 0; +} + +void tlcs90_device::device_reset() +{ + m_irq_state = 0; + m_irq_mask = 0; + m_pc.d = 0x0000; + F &= ~IF; +/* + P0/D0-D7 P1/A0-A7 P2/A8-A15 P6 P7 = INPUT + P35/~RD P36/~WR CLK = 1 (ALWAYS OUTPUTS) + P4/A16-A19 P83 = 0 + dedicated input ports and CPU registers remain unchanged, + but PC IFF BX BY = 0, A undefined +*/ + memset(m_internal_registers, 0, sizeof(m_internal_registers)); +} + +void tlcs90_device::execute_burn(INT32 cycles) +{ + m_icount -= 4 * ((cycles + 3) / 4); +} + + +/************************************************************************************************************* + + +---------------------------------------------------------------------------------------------------------------- +FFC0 P0 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P07-P00 R W IN I/O Port 0 + +---------------------------------------------------------------------------------------------------------------- +FFC1 P1 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P17-P10 R W IN I/O Port 1 + +---------------------------------------------------------------------------------------------------------------- +FFC2 P01CR/ R/W Reset Description * Prohibit Read-Modify-Write * + IRFL +---------------------------------------------------------------------------------------------------------------- + 7 - - 0 - + 6 IRF0 R 0 INT0 interrupt request (1 = asserted) + 5 IRFT0 R 0 INTT0 "" + 4 IRFT1 R 0 INTT1 "" + 3 - - 0 - + 2 EXT W 0 P1/P2 control: 0 = Port 1 = Address Bus + 1 P1CR W 0 P1 control: 0 = IN 1 = OUT | + 0 P0CR W 0 P0 control: 0 = IN 1 = OUT | + | | + Port 0 also functions as data bus (D0-D7),so P1: regardless of <P1CR> + P0CR is reset when external memory is accessed P2: only if P2CR is set to 1 (output) + TMP90C841A: always address bus + +---------------------------------------------------------------------------------------------------------------- +FFC3 IRFH R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- + 7 IRFT2 R W 0 INTT2 interrupt request (1 = asserted) + 6 IRFT3 R W 0 INTT3 "" + 5 IRFT4 R W 0 INTT4 "" + 4 IRF1 R W 0 INT1 "" + 3 IRFT5 R W 0 INTT5 "" + 2 IRF2 R W 0 INT2 "" + 1 IRFRX R W 0 INTRX "" + 0 IRFTX R W 0 INTTX "" + |__ Writing Vector/8 clears the request flip-flop for that interrupt + +---------------------------------------------------------------------------------------------------------------- +FFC4 P2 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P27-P20 R W IN I/O Port 2 + +---------------------------------------------------------------------------------------------------------------- +FFC5 P2CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P27C- W 0 Port 2 control: 0 = IN 1 = OUT + P20C + +---------------------------------------------------------------------------------------------------------------- +FFC6 P3 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 P37 R IN P37 input + 6 P36 R W 1 ~WD + 5 P35 R W 1 ~RD + 4 P34 R IN P34 input + 3 P33 R W 1 TxD / P33 output + 2 P32 R W 1 TxD / P32 output + 1 P31 R IN RxD / P31 input + 0 P30 R IN RxD / P30 input + +---------------------------------------------------------------------------------------------------------------- +FFC7 P3CR R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- +7-6 WAITC1-0R W 00 Wait control: 00 = 2state 01 = normal 10 = no wait 11 = reserved + 5 RDE R W 0 RD control: 0 = only external access 1 = always + 4 ODE R W 0 P33 control: 0 = CMOS 1 = Open Drain +3-2 TXDC1-0 R W 00 P33-P32: 00 = OUT-OUT 01 = OUT-TxD 10 = TxD-OUT 11 = TxD-~RTS/SCLK +1-0 RXDC1-0 R W 00 P31-P30: 00 = IN-IN 01 = IN-RxD 10 = RxD-IN 11 = not used + +---------------------------------------------------------------------------------------------------------------- +FFC8 P4 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - +3-0 P43-P40 R W 0 I/O Port 4 bits 3-0 or address bus A16-A19 + +---------------------------------------------------------------------------------------------------------------- +FFC9 P4CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - +3-0 P43C- W 0 Port 4 control: 0 = OUT 1 = Address Output + P40C + +---------------------------------------------------------------------------------------------------------------- +FFCA P5 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7 - R 0 Test bit, must be set to 0 +6 - R 0 +5-0 P55-P50 R 0 I/O Port 5 bits 5-0 / AN5-AN0 analog inputs + +---------------------------------------------------------------------------------------------------------------- +FFCB SMMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R W - + 6 SM7M0 R W 0 Motor Step: 0 = Full 1 = Half + 5 P70C1 R W 0 Port 7 control: 0 = IN-OUT 0 = IN-OUT,TO3 1 = IN / M1 1 = Timer 4 + 4 P70C0 R W 0 0 1 0 Timer 2,3 1 + 3 - R W - + 2 SM6M0 R W 0 Motor Step: 0 = Full 1 = Half + 1 P60C1 R W 0 Port 6 control: 0 = IN-OUT 0 = IN-OUT,TO1 1 = IN / M0 + 0 P60C0 R W 0 0 1 X Timer 0,1 + +---------------------------------------------------------------------------------------------------------------- +FFCC P6 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control * +---------------------------------------------------------------------------------------------------------------- +7-4 SA60-63 W Undef Stepping motor Port 0 (M0) Shifter alternate reg. +3-0 P63-P60 R W IN Bits 3-0 of I/O Port 6 or Stepping motor Port 0 (M0) + +---------------------------------------------------------------------------------------------------------------- +FFCD P7 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control * +---------------------------------------------------------------------------------------------------------------- +7-4 SA70-73 W Undef Stepping motor Port 1 (M1) Shifter alternate reg. +3-0 P73-P70 R W IN Bits 3-0 of I/O Port 7 or Stepping motor Port 1 (M1) + +---------------------------------------------------------------------------------------------------------------- +FFCE P67CR R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- +7-4 P73-70C W 0 Port 7: 0 = IN 1 = OUT +3-0 P63-60C W 0 Port 6: 0 = IN 1 = OUT + +---------------------------------------------------------------------------------------------------------------- +FFD0 P8 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - + 3 P83 R W 0 P83 / TIO3 / TIO4 output + 2 P82 R IN P82 + INT2 input + 1 P81 R IN P81 + INT1 input + 0 P80 R IN P80 + INT0 input + +---------------------------------------------------------------------------------------------------------------- +FFD1 P8CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - + 3 P83OC W 0 P83 out control: 0 = P83 1 = TO3 / TO4 + 2 ZCE2 W 0 INT2/TI5 control: 0 = ZCD disable 1 = ZCD enable + 1 ZCE1 W 0 INT1/TI4 control: 0 = ZCD disable 1 = ZCD enable + 0 EDGE W 0 INT0 control: 0 = Level 1 = Rising edge + +---------------------------------------------------------------------------------------------------------------- +FFD2 WDMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 WDTE R W 1 1 = WDT Enable + 6 WDTP1 R W 0 WDT detection time: 0 = 2^14/fc 0 = 2^16/fc 1 = 2^18/fc 1 = 2^20/fc + 5 WDTP0 R W 0 0 1 0 1 + 4 WARM R W 0 Warming up time: 0 = 2^14/fc 1 = 2^16/fc + 3 HALTM1 R W 0 Standby mode: 0 = RUN 0 = STOP 1 = IDLE1 1 = IDLE2 + 2 HALTM0 R W 0 0 1 0 1 + 1 EXF R Undef Invert each time EXX instruction is executed + 0 DRIVE R W 0 1 to drive pins in stop mode + +---------------------------------------------------------------------------------------------------------------- +FFD4 TREG0 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD5 TREG1 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD6 TREG2 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD7 TREG3 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD8 TCLK R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 T3CLK1-0R W 00 Timer 3 clock: 00 = Timer 2 01 = clock 10 = clock/16 11 = clock/256 <- Timer 2 overflow output in 16 bit mode +5-4 T2CLK1-0R W 00 Timer 2 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256 +3-2 T1CLK1-0R W 00 Timer 1 clock: 00 = Timer 0 01 = clock 10 = clock/16 11 = clock/256 <- Timer 0 overflow output in 16 bit mode +1-0 T0CLK1-0R W 00 Timer 0 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256 + +---------------------------------------------------------------------------------------------------------------- +FFD9 TFFCR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 TFF3C1-0 W - Timer 3 flip-flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11 +5 TFF3IE R W 0 Timer 3 Invert: 0 = Disable 1 = Enable +4 TFF3IS R W 0 Timer 3 Invert: 0 = Timer 2 1 = Timer 3 +3-2 TFF1C1-0 W - Timer 1 Flip-Flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11 +1 TFF1IE R W 0 Timer 1 Invert: 0 = Disable 1 = Enable +0 TFF1IS R W 0 Timer 1 Invert: 0 = Timer 0 1 = Timer 1 + +---------------------------------------------------------------------------------------------------------------- +FFDA TMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 T32M1-0 R W 00 Timers 2 & 3: 00 = 8b x 2 01 = 16b(T3+T2) 10 = 8b PPG(T3) 11 = 8b PWM (T3) + 8b (T2) +5-4 PWM21-0 R W 00 Timer 3 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc +3-2 T10M1-0 R W 00 Timers 1 & 0: 00 = 8b x 2 01 = 16b(T1+T0) 10 = 8b PPG(T1) 11 = 8b PWM (T1) + 8b (T0) +1-0 PWM01-0 R W 00 Timer 1 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc + +---------------------------------------------------------------------------------------------------------------- +FFDB TRUN R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 BRATE1-0R W 00 Serial baud rate: 00 = 300/150 01 = 1200/600 10 = 4800/2400 11 = 19200/9600 + 5 PRRUN R W 0 Prescaler control: 0 = Stop & Clear 1 = Run + 4 T4RUN R W 0 Timer 4 control: 0 = Stop & Clear 1 = Run +3-0 T4RUN-0 R W 00 Timers 3-0 control: 0 = Stop & Clear 1 = Run + +---------------------------------------------------------------------------------------------------------------- +FFE6 INTEL R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 DET2 R W 0 INTT2/INTAD interrupt enable flag (1 = enable) + 6 DET3 R W 0 INTT3 "" + 5 DET4 R W 0 INTT4 "" + 4 DE1 R W 0 INT1 "" + 3 DET5 R W 0 INTT5 "" + 2 DE2 R W 0 INT2 "" + 1 DERX R W 0 INTRX "" + 0 DETX R W 0 INTTX "" + +---------------------------------------------------------------------------------------------------------------- +FFE7 INTEH R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R W 0 Write "0" + 6 DE0 R W 0 INT0 DMA enable flag (1 = enable) + 5 DET0 R W 0 INTT0 "" + 4 DET1 R W 0 INTT1 "" + 3 ADIS R W 0 INTT2/INTAD selection (1 = INTAD) + 2 IE0 R W 0 INT0 interrupt enable flag (1 = enable) + 1 IET0 R W 0 INTT0 "" + 0 IET1 R W 0 INTT1 "" + +---------------------------------------------------------------------------------------------------------------- +FFE8 DMAEH R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 DET2 R W 0 INTT2/INTAD DMA enable flag (1 = enable) + 6 DET3 R W 0 INTT3 "" + 5 DET4 R W 0 INTT4 "" + 4 DE1 R W 0 INT1 "" + 3 DET5 R W 0 INTT5 "" + 2 DE2 R W 0 INT2 "" + 1 DERX R W 0 INTRX "" + 0 DETX R W 0 INTTX "" + +---------------------------------------------------------------------------------------------------------------- +FFEC BX R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R 1 + 6 - R 1 + 5 - R 1 + 4 - R 1 + 3 BX3 R W 0 IX bank register bit 3 + 2 BX2 R W 0 IX bank register bit 2 + 1 BX1 R w 0 IX bank register bit 1 + 0 BX0 R W 0 IX bank register bit 0 + +---------------------------------------------------------------------------------------------------------------- +FFED BX R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R 1 + 6 - R 1 + 5 - R 1 + 4 - R 1 + 3 BY3 R W 0 IY bank register bit 3 + 2 BY2 R W 0 IY bank register bit 2 + 1 BY1 R w 0 IY bank register bit 1 + 0 BY0 R W 0 IY bank register bit 0 + +*************************************************************************************************************/ + +READ8_MEMBER( tlcs90_device::t90_internal_registers_r ) +{ + #define RIO m_io->read_byte( T90_IOBASE+offset ) + + UINT8 data = m_internal_registers[offset]; + switch ( T90_IOBASE + offset ) + { + case T90_P3: // 7,4,1,0 + return (data & 0x6c) | (RIO & 0x93); + + case T90_P4: // only output + return data & 0x0f; + + case T90_P5: + return (RIO & 0x3f); + + case T90_P6: + case T90_P7: + return (data & 0xf0) | (RIO & 0x0f); + + case T90_P8: // 2,1,0 + return (data & 0x08) | (RIO & 0x07); + + case T90_BX: + case T90_BY: + return 0xf0 | data; + } + return data; +} + +void tlcs90_device::t90_start_timer(int i) +{ + int prescaler; + attotime period; + + m_timer_value[i] = 0; + + switch((m_internal_registers[ T90_TMOD - T90_IOBASE ] >> (i * 2)) & 0x03) + { + case 0: + // 8-bit mode + break; + case 1: + // 16-bit mode + break; + case 2: + logerror("%04X: CPU Timer %d, unsupported PPG mode\n", m_pc.w.l, i); + return; + case 3: + logerror("%04X: CPU Timer %d, unsupported PWM mode\n", m_pc.w.l, i); + return; + } + + switch((m_internal_registers[ T90_TCLK - T90_IOBASE ] >> (i * 2)) & 0x03) + { + case 0: if (i & 1) logerror("%04X: CPU Timer %d clocked by Timer %d match signal\n", m_pc.w.l, i,i-1); + else logerror("%04X: CPU Timer %d, unsupported TCLK = 0\n", m_pc.w.l, i); + return; + case 2: prescaler = 16; break; + case 3: prescaler = 256; break; + default: + case 1: prescaler = 1; break; + } + + + period = m_timer_period * prescaler; + + m_timer[i]->adjust(period, i, period); + + logerror("%04X: CPU Timer %d started at %f Hz\n", m_pc.w.l, i, 1.0 / period.as_double()); +} + +void tlcs90_device::t90_start_timer4() +{ + int prescaler; + attotime period; + + m_timer4_value = 0; + + switch(m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03) + { + case 1: prescaler = 1; break; + case 2: prescaler = 16; break; + default: logerror("%04X: CPU Timer 4, unsupported T4MOD = %d\n", m_pc.w.l,m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03); + return; + } + + period = m_timer_period * prescaler; + + m_timer[4]->adjust(period, 4, period); + + logerror("%04X: CPU Timer 4 started at %f Hz\n", m_pc.w.l, 1.0 / period.as_double()); +} + + +void tlcs90_device::t90_stop_timer(int i) +{ + m_timer[i]->adjust(attotime::never, i); + logerror("%04X: CPU Timer %d stopped\n", m_pc.w.l, i); +} + +void tlcs90_device::t90_stop_timer4() +{ + t90_stop_timer(4); +} + +TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer_callback ) +{ + int mode, timer_fired; + int i = param; + + int mask = 0x20 | (1 << i); + if ( (m_internal_registers[ T90_TRUN - T90_IOBASE ] & mask) != mask ) + return; + + timer_fired = 0; + + mode = (m_internal_registers[ T90_TMOD - T90_IOBASE ] >> ((i & ~1) + 2)) & 0x03; + // Match + switch (mode) + { + case 0x02: // 8bit PPG + case 0x03: // 8bit PWM + logerror("CPU Timer %d expired with unhandled mode %d\n", i, mode); + // TODO: hmm... + case 0x00: // 8bit + m_timer_value[i]++; + if ( m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ] ) + timer_fired = 1; + break; + + case 0x01: // 16bit + if(i & 1) + break; + m_timer_value[i]++; + if(m_timer_value[i] == 0) m_timer_value[i+1]++; + if(m_timer_value[i+1] == m_internal_registers[ T90_TREG0+i+1 - T90_IOBASE ]) + if(m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ]) + timer_fired = 1; + break; + } + + if(timer_fired) { + // special stuff handling + switch(mode) { + case 0x02: // 8bit PPG + case 0x03: // 8bit PWM + // TODO: hmm... + case 0x00: // 8bit + if(i & 1) + break; + if ( (m_internal_registers[ T90_TCLK - T90_IOBASE ] & (0x0C << (i * 2))) == 0 ) // T0/T1 match signal clocks T1/T3 + t90_timer_callback(ptr, i+1); + break; + case 0x01: // 16bit, only can happen for i=0,2 + m_timer_value[i+1] = 0; + set_irq_line(INTT0 + i+1, 1); + break; + } + // regular handling + m_timer_value[i] = 0; + set_irq_line(INTT0 + i, 1); + } +} + +TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer4_callback ) +{ +// logerror("CPU Timer 4 fired! value = %d\n", (unsigned)m_timer_value[4]); + + m_timer4_value++; + + // Match + + if ( m_timer4_value == (m_internal_registers[ T90_TREG4L - T90_IOBASE ] + (m_internal_registers[ T90_TREG4H - T90_IOBASE ] << 8)) ) + { +// logerror("CPU Timer 4 matches TREG4\n"); + set_irq_line(INTT4, 1); + } + if ( m_timer4_value == (m_internal_registers[ T90_TREG5L - T90_IOBASE ] + (m_internal_registers[ T90_TREG5H - T90_IOBASE ] << 8)) ) + { +// logerror("CPU Timer 4 matches TREG5\n"); + set_irq_line(INTT5, 1); + if (m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x04) + m_timer4_value = 0; + } + + // Overflow + + if ( m_timer_value == 0 ) + { +// logerror("CPU Timer 4 overflow\n"); + } +} + +WRITE8_MEMBER( tlcs90_device::t90_internal_registers_w ) +{ + #define WIO m_io->write_byte( T90_IOBASE+offset, data ) + + UINT8 out_mask; + UINT8 old = m_internal_registers[offset]; + switch ( T90_IOBASE + offset ) + { + case T90_TRUN: + { + int i; + UINT8 mask; + // Timers 0-3 + for (i = 0; i < 4; i++) + { + mask = 0x20 | (1 << i); + if ( (old ^ data) & mask ) // if timer bit or prescaler bit changed + { + if ( (data & mask) == mask ) t90_start_timer(i); + else t90_stop_timer(i); + } + } + + // Timer 4 + mask = 0x20 | 0x10; + if ( (old ^ data) & mask ) + { + if ( (data & mask) == mask ) t90_start_timer4(); + else t90_stop_timer4(); + } + break; + } + + case T90_INTEL: + m_irq_mask &= ~( (1 << INTT2 ) | + (1 << INTT3 ) | + (1 << INTT4 ) | + (1 << INT1 ) | + (1 << INTT5 ) | + (1 << INT2 ) | + (1 << INTRX ) | + (1 << INTTX ) ); + + m_irq_mask |= ((data & 0x80) ? (1 << INTT2 ) : 0) | + ((data & 0x40) ? (1 << INTT3 ) : 0) | + ((data & 0x20) ? (1 << INTT4 ) : 0) | + ((data & 0x10) ? (1 << INT1 ) : 0) | + ((data & 0x08) ? (1 << INTT5 ) : 0) | + ((data & 0x04) ? (1 << INT2 ) : 0) | + ((data & 0x02) ? (1 << INTRX ) : 0) | + ((data & 0x01) ? (1 << INTTX ) : 0) ; + break; + + case T90_INTEH: + m_irq_mask &= ~( (1 << INT0 ) | + (1 << INTT0) | + (1 << INTT1) ); + + m_irq_mask |= ((data & 0x04) ? (1 << INT0 ) : 0) | + ((data & 0x02) ? (1 << INTT0) : 0) | + ((data & 0x01) ? (1 << INTT1) : 0) ; + break; + + case T90_P3: + data &= 0x6c; + WIO; + break; + + case T90_P4: + data &= 0x0f; + out_mask = (~m_internal_registers[ T90_P4CR - T90_IOBASE ]) & 0x0f; + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P6: + out_mask = m_internal_registers[ T90_P67CR - T90_IOBASE ] & 0x0f; + switch (m_internal_registers[ T90_SMMOD - T90_IOBASE ] & 0x03) + { + case 1: + data &= ~0x01; + // add TO1 here + break; + case 2: + case 3: + data &= ~0x0f; + // add M0 here + break; + } + + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P7: + out_mask = (m_internal_registers[ T90_P67CR - T90_IOBASE ] & 0xf0) >> 4; + switch ((m_internal_registers[ T90_SMMOD - T90_IOBASE ]>>4) & 0x03) + { + case 1: + data &= ~0x01; + // add TO3 here + break; + case 2: + case 3: + data &= ~0x0f; + // add M1 here + break; + } + + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P8: + data &= 0x0f; + out_mask = (~m_internal_registers[ T90_P8CR - T90_IOBASE ]) & 0x08; + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_BX: + m_ixbase = (data & 0xf) << 16; + break; + case T90_BY: + m_iybase = (data & 0xf) << 16; + break; + } + m_internal_registers[offset] = data; +} + + +void tlcs90_device::device_start() +{ + int i, p; + + save_item(NAME(m_prvpc.w.l)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_sp.w.l)); + save_item(NAME(m_af.w.l)); + save_item(NAME(m_bc.w.l)); + save_item(NAME(m_de.w.l)); + save_item(NAME(m_hl.w.l)); + save_item(NAME(m_ix.w.l)); + save_item(NAME(m_iy.w.l)); + save_item(NAME(m_af2.w.l)); + save_item(NAME(m_bc2.w.l)); + save_item(NAME(m_de2.w.l)); + save_item(NAME(m_hl2.w.l)); + save_item(NAME(m_halt)); + save_item(NAME(m_after_EI)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_mask)); + save_item(NAME(m_extra_cycles)); + + save_item(NAME(m_internal_registers)); + save_item(NAME(m_ixbase)); + save_item(NAME(m_iybase)); + + save_item(NAME(m_timer_value)); + save_item(NAME(m_timer4_value)); + + // Work registers + save_item(NAME(m_op)); + save_item(NAME(m_mode1)); + save_item(NAME(m_r1)); + save_item(NAME(m_r1b)); + save_item(NAME(m_mode2)); + save_item(NAME(m_r2)); + save_item(NAME(m_r2b)); + + save_item(NAME(m_cyc_t)); + save_item(NAME(m_cyc_f)); + save_item(NAME(m_addr)); + + for (i = 0; i < 256; i++) + { + p = 0; + if( i&0x01 ) ++p; + if( i&0x02 ) ++p; + if( i&0x04 ) ++p; + if( i&0x08 ) ++p; + if( i&0x10 ) ++p; + if( i&0x20 ) ++p; + if( i&0x40 ) ++p; + if( i&0x80 ) ++p; + SZ[i] = i ? i & SF : ZF; +// SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZ_BIT[i] = i ? i & SF : ZF | PF; +// SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZP[i] = SZ[i] | ((p & 1) ? 0 : PF); + SZHV_inc[i] = SZ[i]; + if( i == 0x80 ) SZHV_inc[i] |= VF; + if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF; + SZHV_dec[i] = SZ[i] | NF; + if( i == 0x7f ) SZHV_dec[i] |= VF; + if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF; + } + + m_prvpc.d = m_pc.d = m_sp.d = m_af.d = m_bc.d = m_de.d = m_hl.d = m_ix.d = m_iy.d = 0; + m_af2.d = m_bc2.d = m_de2.d = m_hl2.d = 0; + m_halt = m_after_EI = 0; + m_irq_state = m_irq_mask = 0; + m_extra_cycles = 0; + memset(m_internal_registers, 0, sizeof(m_internal_registers)); + m_ixbase = m_iybase = 0; + m_timer_value[0] = m_timer_value[1] = m_timer_value[2] = m_timer_value[3] = 0; + m_timer4_value = 0; + m_op = 0; + m_mode1 = MODE_NONE; + m_r1 = m_r1b = 0; + m_mode2 = MODE_NONE; + m_r2 = m_r2b = 0; + m_cyc_t = m_cyc_f = 0; + m_addr = 0; + + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + m_timer_period = attotime::from_hz(unscaled_clock()) * 8; + + // Timers + + for (i = 0; i < 4; i++) + m_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tlcs90_device::t90_timer_callback),this)); + + m_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tlcs90_device::t90_timer4_callback),this)); + + state_add( T90_PC, "PC", m_pc.w.l).formatstr("%04X"); + state_add( T90_SP, "SP", m_sp.w.l).formatstr("%04X"); + state_add( T90_A, "~A", m_af.b.h).formatstr("%02X"); + state_add( T90_B, "~B", m_bc.b.h).formatstr("%02X"); + state_add( T90_C, "~C", m_bc.b.l).formatstr("%02X"); + state_add( T90_D, "~D", m_de.b.h).formatstr("%02X"); + state_add( T90_E, "~E", m_de.b.l).formatstr("%02X"); + state_add( T90_H, "~H", m_hl.b.h).formatstr("%02X"); + state_add( T90_L, "~L", m_hl.b.l).formatstr("%02X"); + state_add( T90_AF, "AF", m_af.w.l).formatstr("%04X"); + state_add( T90_BC, "BC", m_bc.w.l).formatstr("%04X"); + state_add( T90_DE, "DE", m_de.w.l).formatstr("%04X"); + state_add( T90_HL, "HL", m_hl.w.l).formatstr("%04X"); + state_add( T90_IX, "IX", m_ix.w.l).formatstr("%04X"); + state_add( T90_IY, "IY", m_iy.w.l).formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_pc.w.l).formatstr("%04X").noshow(); + state_add(STATE_GENSP, "GENSP", m_sp.w.l).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", F ).formatstr("%8s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_prvpc.w.l).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + + +void tlcs90_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + F & 0x80 ? 'S':'.', + F & 0x40 ? 'Z':'.', + F & 0x20 ? 'I':'.', + F & 0x10 ? 'H':'.', + F & 0x08 ? 'X':'.', + F & 0x04 ? 'P':'.', + F & 0x02 ? 'N':'.', + F & 0x01 ? 'C':'.' + ); + break; + } +} diff --git a/src/devices/cpu/tlcs90/tlcs90.h b/src/devices/cpu/tlcs90/tlcs90.h new file mode 100644 index 00000000000..5e379cb4425 --- /dev/null +++ b/src/devices/cpu/tlcs90/tlcs90.h @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +#pragma once + +#ifndef __TLCS90_H__ +#define __TLCS90_H__ + + +#define T90_IOBASE 0xffc0 + +enum e_ir +{ + T90_P0=T90_IOBASE, T90_P1, T90_P01CR_IRFL, T90_IRFH, T90_P2, T90_P2CR, T90_P3, T90_P3CR, + T90_P4, T90_P4CR, T90_P5, T90_SMMOD, T90_P6, T90_P7, T90_P67CR, T90_SMCR, + T90_P8, T90_P8CR, T90_WDMOD, T90_WDCR, T90_TREG0, T90_TREG1, T90_TREG2, T90_TREG3, + T90_TCLK, T90_TFFCR, T90_TMOD, T90_TRUN, T90_CAP1L, T90_CAP1H, T90_CAP2L, T90_CAL2H, + T90_TREG4L, T90_TREG4H, T90_TREG5L, T90_TREG5H, T90_T4MOD, T90_T4FFCR, T90_INTEL, T90_INTEH, + T90_DMAEH, T90_SCMOD, T90_SCCR, T90_SCBUF, T90_BX, T90_BY, T90_ADREG, T90_ADMOD +}; + +enum tlcs90_e_irq { INTSWI = 0, INTNMI, INTWD, INT0, INTT0, INTT1, INTT2, INTT3, INTT4, INT1, INTT5, INT2, INTRX, INTTX, INTMAX }; +DECLARE_ENUM_OPERATORS(tlcs90_e_irq) + +class tlcs90_device : public cpu_device +{ +public: + // construction/destruction + tlcs90_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, address_map_constructor program_map); + + DECLARE_READ8_MEMBER( t90_internal_registers_r ); + DECLARE_WRITE8_MEMBER( t90_internal_registers_w ); + + TIMER_CALLBACK_MEMBER( t90_timer_callback ); + TIMER_CALLBACK_MEMBER( t90_timer4_callback ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 26; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual void execute_burn(INT32 cycles); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + enum e_mode { + MODE_NONE, MODE_BIT8, MODE_CC, + MODE_I8, MODE_D8, MODE_R8, + MODE_I16, MODE_D16, MODE_R16, + MODE_MI16, MODE_MR16, MODE_MR16D8, MODE_MR16R8, + MODE_R16D8, MODE_R16R8 + }; + + address_space_config m_program_config; + address_space_config m_io_config; + + PAIR m_prvpc,m_pc,m_sp,m_af,m_bc,m_de,m_hl,m_ix,m_iy; + PAIR m_af2,m_bc2,m_de2,m_hl2; + UINT8 m_halt, m_after_EI; + UINT16 m_irq_state, m_irq_mask; + address_space *m_program; + address_space *m_io; + int m_icount; + int m_extra_cycles; // extra cycles for interrupts + UINT8 m_internal_registers[48]; + UINT32 m_ixbase,m_iybase; + + // Timers: 4 x 8-bit + 1 x 16-bit + emu_timer *m_timer[4+1]; + UINT8 m_timer_value[4]; + UINT16 m_timer4_value; + attotime m_timer_period; + + // Work registers + UINT8 m_op; + + e_mode m_mode1; + UINT16 m_r1,m_r1b; + + e_mode m_mode2; + UINT16 m_r2,m_r2b; + + int m_cyc_t,m_cyc_f; + + UINT32 m_addr; + + inline UINT8 RM8 (UINT32 a); + inline UINT16 RM16(UINT32 a); + inline void WM8 (UINT32 a, UINT8 v); + inline void WM16(UINT32 a, UINT16 v); + inline UINT8 RX8 (UINT32 a, UINT32 base); + inline UINT16 RX16(UINT32 a, UINT32 base); + inline void WX8 (UINT32 a, UINT8 v, UINT32 base); + inline void WX16(UINT32 a, UINT16 v, UINT32 base); + inline UINT8 READ8(); + inline UINT16 READ16(); + void decode(); + const char *internal_registers_names(UINT16 x); + int sprint_arg(char *buffer, UINT32 pc, const char *pre, const e_mode mode, const UINT16 r, const UINT16 rb); + inline UINT16 r8( const UINT16 r ); + inline void w8( const UINT16 r, UINT16 value ); + inline UINT16 r16( const UINT16 r ); + inline void w16( const UINT16 r, UINT16 value ); + inline UINT8 Read1_8(); + inline UINT16 Read1_16(); + inline UINT8 Read2_8(); + inline UINT16 Read2_16(); + inline void Write1_8( UINT8 value ); + inline void Write1_16( UINT16 value ); + inline void Write2_8( UINT8 value ); + inline void Write2_16( UINT16 value ); + inline int Test( UINT8 cond ); + inline void Push( UINT16 rr ); + inline void Pop( UINT16 rr ); + inline void leave_halt(); + void take_interrupt(tlcs90_e_irq irq); + void check_interrupts(); + inline void Cyc(); + inline void Cyc_f(); + void t90_start_timer(int i); + void t90_start_timer4(); + void t90_stop_timer(int i); + void t90_stop_timer4(); + void set_irq_line(int irq, int state); +}; + + +class tmp90840_device : public tlcs90_device +{ +public: + // construction/destruction + tmp90840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp90841_device : public tlcs90_device +{ +public: + // construction/destruction + tmp90841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp91640_device : public tlcs90_device +{ +public: + // construction/destruction + tmp91640_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp91641_device : public tlcs90_device +{ +public: + // construction/destruction + tmp91641_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type TMP90840; +extern const device_type TMP90841; +extern const device_type TMP91640; +extern const device_type TMP91641; + +#endif /* __TLCS90_H__ */ |