diff options
author | 2016-11-10 18:54:47 +0100 | |
---|---|---|
committer | 2016-11-10 18:54:47 +0100 | |
commit | 6199bac4ffca55103ccd81831f357b7acaa9c9a3 (patch) | |
tree | 630e54ba68b1270c19089e9641532ba644d05342 /src/devices/cpu/tms9900 | |
parent | 677ec78eb50decdc40fad3d30daa3560feaff3cc (diff) |
removed not used file (nw)
Diffstat (limited to 'src/devices/cpu/tms9900')
-rw-r--r-- | src/devices/cpu/tms9900/99xxcore.h | 5319 |
1 files changed, 0 insertions, 5319 deletions
diff --git a/src/devices/cpu/tms9900/99xxcore.h b/src/devices/cpu/tms9900/99xxcore.h deleted file mode 100644 index 6eaef876d95..00000000000 --- a/src/devices/cpu/tms9900/99xxcore.h +++ /dev/null @@ -1,5319 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Raphael Nabet - -/*************************************************************************** - Legacy TMS99xx core implementation - - PLEASE DO NOT REMOVE THIS FILE from the source tree, even if none of the - drivers make use of it anymore. It still contains documentation and - incomplete implementations of cores that are not (yet) used in drivers. - - It need not be included in the build process, however. - - Michael Zapf, February 2014 - -***************************************************************************/ - -/* - 99xxcore.h : generic tms99xx emulation - - The TMS99XX_MODEL switch tells which emulator we want to build. Set the - switch, then include 99xxcore.h, and you will have an emulator for this - processor. - - Only ti990/10, tms9900, tms9980a/9981, and tms9995 work OK for now. Note - that tms9995 has not been tested extensively. - - tms9940 is WIP: it is probably still buggy (particularily the BCD support), - as it has not been tested. tms9985 has been implemented as a 9940 with - a data bus, which should be mostly correct. - - I think all software aspects of tms9985 and tms9989 are implemented. - You just need to implement bus interfaces, provided you know them. - (I don't...) - - tms99000 cannot be implemented fully yet, due to lack of documentation. - - ti990/12 is not supported at all, and it should probably be implemented as - a separate processor core, anyway. - - Original tms9900 emulator by Edward Swartz - Smoothed out by Raphael Nabet - Originally converted for Mame by M.Coates - Processor timing, support for tms9980 and tms9995, and many bug fixes by R Nabet -*/ - -/* - The first member of the family was actually the ti990/10 minicomputer, - released in 1975. tms9900 was released in 1976, and has the same - instruction set as ti990/10: however, tms9900 is slower, it does not - support privileges and memory mapping, and illegal instructions do not - cause an error interrupt. - - The ti990 family later evoluted into the huge ti990/12 system, with support - for 144 different instructions, and microcode programming in case some user - found it was not enough. ti990/10 was eventually replaced by a cheaper - ti990/10a board, built around a tms99000 microprocessor. - - The tms9980 processor is merely a tms9900 with a 8-bit data bus (instead of - 16-bit on tms9900). - - tms9940 is a microcontroller, and is mostly similar to 9900/9980. The - variant I know has 2kb of ROM, 128 bytes of RAM, a timer, 32 I/O line, some - of which can be reconfigured as a CRU bus, but no external memory bus. It - includes three additional opcodes, which are not supported by any other - member of the family (with the probable exception of TMS9985). - - tms9985 is similar to tms9940, but it supports an external 8-bit-wide - memory bus. At least one variant included 8kb of ROM, 256 bytes of RAM. - It was ill-fated, as it was never released due to technical problems. - - tms9989 is mostly alien to me. I guess it is a close relative of tms9995, - although I am not sure. I have read that the SBP68689 supports tms9995 - opcodes, but that tms9989 does not. - - tms9995 belongs to another generation. It is quite faster than tms9900, - and supports 4 extra opcodes. Its external bus is 8-bit-wide, and it has - 256 bytes of internal 16-bit RAM. - - tms99000 is the successor to both ti9900 and ti990/10. It supports - privileges, and has a coprocessor interface which enables the use of an - external memory mapper. Additionnally, it can use a Macrostore ROM to - emulate additional instructions. - - This feature allowed TI to expand the 99000 family with the tms99105 (which - was said to support 84 instructions types), the tms99110 (which supported - floating point instructions), and possibly another chip (tms99220???) which - included parts of the UCSD P-system in Macrostore. - -References : -* 9900 family systems design, chapter 6, 7, 8 -* TMS 9980A/ TMS 9981 Product Data Book -* TMS 9995 16-Bit Microcomputer Data Manual -* Model 990/10A computer general description, section 4 (p/n 2302633-9701 A) -* 990/99000 assembly language reference manual (p/n 2270509-9701 A) -* Chapter 18 of unidentified book is the only reference on tms9940 I have found so far (Paperport format) - <ftp://ftp.whtech.com//datasheets/Hardware manuals/tms9900 9901 9904 9940 9980 (by a osborne).max> - -Other references can be found on spies.com: -<http://www.spies.com/arcade/simulation/processors/index.html> -<http://www.spies.com/~aek/pdf/ti/> - -*/ - - -#if (TMS99XX_MODEL == TI990_10_ID) - - #define TMS99XX_PREFIX ti990_10 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( ti990_10l ) - #define TMS99XX_device_get_name "TI990/10L" - #define TMS99XX_device_get_shortname "ti990_10l" - -#elif (TMS99XX_MODEL == TMS9900_ID) - - #define TMS99XX_PREFIX tms9900 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9900l ) - #define TMS99XX_device_get_name "TMS9900L" - #define TMS99XX_device_get_shortname "tms9900l" - -#elif (TMS99XX_MODEL == TMS9940_ID) - - #define TMS99XX_PREFIX tms9940 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9940l ) - #define TMS99XX_device_get_name "TMS9940L" - #define TMS99XX_device_get_shortname "tms9940l" - - #error "tms9940 is not yet supported" - -#elif (TMS99XX_MODEL == TMS9980_ID) - - #define TMS99XX_PREFIX tms9980a - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9980al ) - #define TMS99XX_device_get_name "TMS9980AL/TMS9981L" - #define TMS99XX_device_get_shortname "tms9980al" - -#elif (TMS99XX_MODEL == TMS9985_ID) - - #define TMS99XX_PREFIX tms9985 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9985l ) - #define TMS99XX_device_get_name "TMS9985L" - #define TMS99XX_device_get_shortname "tms9985l" - - #error "tms9985 is not yet supported" - -#elif (TMS99XX_MODEL == TMS9989_ID) - - #define TMS99XX_PREFIX tms9989 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9989l ) - #define TMS99XX_device_get_name "TMS9989L" - #define TMS99XX_device_get_shortname "tms9989l" - - #error "tms9989 is not yet supported" - -#elif (TMS99XX_MODEL == TMS9995_ID) - - #define TMS99XX_PREFIX tms9995 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9995l ) - #define TMS99XX_device_get_name "TMS9995L" - #define TMS99XX_device_get_shortname "tms9995l" - -#elif (TMS99XX_MODEL == TMS99000_ID) - - #define TMS99XX_PREFIX tms99000 - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99000l ) - #define TMS99XX_device_get_name "TMS99000L" - #define TMS99XX_device_get_shortname "tms99000l" - - #error "tms99000 is not yet supported" - -#elif (TMS99XX_MODEL == TMS99105A_ID) - - #define TMS99XX_PREFIX tms99105a - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99105al ) - #define TMS99XX_device_get_name "TMS99105AL" - #define TMS99XX_device_get_shortname "tms99105al" - - #error "tms99105a is not yet supported" - -#elif (TMS99XX_MODEL == TMS99110A_ID) - - #define TMS99XX_PREFIX tms99110a - #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99110al ) - #define TMS99XX_device_get_name "TMS99110AL" - #define TMS99XX_device_get_shortname "tms99110al" - - #error "tms99110a is not yet supported" - -#endif - -/* - Now for some preprocessor wizardry. -*/ -#define concat2(a,b) a##b - -#define GET_INFO(prefix) concat2(prefix,_get_info) -#define RESET_PARAM(prefix) concat2(prefix,reset_param) - -#define TMS99XX_RESET_PARAM RESET_PARAM(TMS99XX_PREFIX) - - - -/* - I include this macro because we may eventually support other 99000 variants such as tms99110, - and this macro will remain true for every 99000 family member, even when we have - (TMS99XX_MODEL != TMS99000_ID). -*/ -#define IS_99000 (TMS99XX_MODEL == TMS99000_ID) - -/* - On microprocessor implementations (other than TMS9940 and, probably, TMS9985), the CKOF, CKON, - IDLE, LREX and RSET cause an external CRU write. CKOF, CKON and LREX do nothing apart of this, - therefore they must be implemented with external hardware (CKON and CKOF are supposed to - enable/disable a line clock interrupt, and LREX to trigger a LOAD interrupt). IDLE and RSET - are functional, but, on the one hand, the design allowed to light a diagnostic LED when - the processor is in IDLE state, and, on the other hand, the RSET instruction is supposed - to reset external devices as well. - - On the TI990/10 and TI990/12 minicomputers, there is no such CRU write. The line clock - interrupt latch is part of the CPU board, LREX is fully functional, the IDLE led is connected - to the board, and the RSET line is part of the TILINE bus connector. - - On the TMS9940, CKOF, CKON, LREX and RSET are not supported. IDLE, on the other hand, is - supported, and the CPU can be configured to output its IDLE state on the P16 I/O pin. -*/ -#define EXTERNAL_INSTRUCTION_DECODING (TMS99XX_MODEL != TI990_10_ID) && (TMS99XX_MODEL != TI9940_ID) && (TMS99XX_MODEL != TI9985_ID) -#define EXTERNAL_INSTRUCTION_CALLBACK (TMS99XX_MODEL == TI990_10_ID) - -/* - ti990/10, ti990/12 and tms99000 support privileges - - privileged instructions: - CKOF, CKON, IDLE, LIMI, LREX, RSET, - LDD, LDS, LMF, (memory mapping instructions) - DINT, EINT, EMD , LCS, LIM, SLSP. (990/12 instructions) - - instructions which are privileged when the effective CRU address is higher than 0xE00: - LDCR, SBO, SBZ, STCR, TB. - - instructions whose behaviour is modified in user mode (only user flags in ST are affected): - RTWP, - LST. (ti990/12 and tms99000 instruction) -*/ -#define HAS_PRIVILEGE ((TMS99XX_MODEL == TI990_10_ID) || IS_99000) - -/* - opcode groups - - * 69 basic opcodes implemented on all family members - * 3 memory mapping opcodes implemented on ti990/10 with mapping option, ti990/12, and - the tim99610 mapper in conjunction with any tms99000 family member: LMF, LDS, LDD - * 3 opcodes implemented on tms9940 (and probably tms9985) only: DCA, DCS, LIIM - * 4 opcodes implemented on ti990/12, tms9989 and above: MPYS, DIVS, LST, LWP - * 1 opcode implemented on ti990/12, and tms99000: BIND - * 72 opcodes implemented on ti990/12 only (some of which are emulated by tms99105 & tms99110) -*/ - -#define HAS_MAPPING ((TMS99XX_MODEL == TI990_10_ID) /*|| IS_99000*/) -#define HAS_9995_OPCODES ((TMS99XX_MODEL == TMS9989_ID) || (TMS99XX_MODEL == TMS9995_ID) || IS_99000) -#define HAS_BIND_OPCODE IS_99000 - -#define HAS_OVERFLOW_INTERRUPT ((TMS99XX_MODEL == TMS9995_ID) || IS_99000) - -/* - Under tms9900, opcodes >0200->03FF are incompletely decoded: bits 11 is ignored, and so are - bits 12-15 for instructions which do not require a register. On the other hand, ti990/10 - generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15. - Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are - non-zero. -*/ -#define BETTER_0200_DECODING (TMS99XX_MODEL == TI990_10_ID) -#define COMPLETE_0200_DECODING (TMS99XX_MODEL >= TMS9995_ID) - -/* - TI990/10 and tms9900 force unused bits in the ST register to 0. - TMS9995 does not. -*/ -#define USE_ST_MASK (TMS99XX_MODEL <= TMS9985_ID) - -/* - TI990/10, TMS9900 and TMS99000 have a 16-bit-wide memory bus, and use 16-bus accessors. - TMS9940 use 16-bit accessors, too, as it has an internal 16-bit bus, and no external bus. -*/ -#define USE_16_BIT_ACCESSORS ((TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (IS_99000)) - -struct tms99xx_state; - -static inline void execute(tms99xx_state *cpustate, uint16_t opcode); - -#if EXTERNAL_INSTRUCTION_DECODING -static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID); -#endif -static uint16_t decipheraddr(tms99xx_state *cpustate, uint16_t opcode); -static uint16_t decipheraddrbyte(tms99xx_state *cpustate, uint16_t opcode); -static void contextswitch(tms99xx_state *cpustate, uint16_t addr); -#if HAS_MAPPING || HAS_PRIVILEGE -static void contextswitchX(tms99xx_state *cpustate, uint16_t addr); -#else -#define contextswitchX(cs, addr) contextswitch(cs, addr) -#endif -static void field_interrupt(tms99xx_state *cpustate); - -/***************************/ -/* Mame Interface Routines */ -/***************************/ - - -/* tms9900 ST register bits. */ - -/* These bits are set by every compare, move and arithmetic or logical operation : */ -/* (Well, COC, CZC and TB only set the E bit, but these are kind of exceptions.) */ -#define ST_LGT 0x8000 /* Logical Greater Than (strictly) */ -#define ST_AGT 0x4000 /* Arithmetical Greater Than (strictly) */ -#define ST_EQ 0x2000 /* Equal */ - -/* These bits are set by arithmetic operations, when it makes sense to update them. */ -#define ST_C 0x1000 /* Carry */ -#define ST_OV 0x0800 /* OVerflow (overflow with operations on signed integers, */ - /* and when the result of a 32bits:16bits division cannot fit in a 16-bit word.) */ - -/* This bit is set by move and arithmetic operations WHEN THEY USE BYTE OPERANDS. */ -#define ST_OP 0x0400 /* Odd Parity */ - -#if (TMS99XX_MODEL != TMS9940_ID) - -/* This bit is set by the XOP instruction. */ -#define ST_X 0x0200 /* Xop */ - -#endif - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - -/* This bit is set by arithmetic operations to support BCD */ -#define ST_DC 0x0100 /* Digit Carry */ - -#endif - -#if HAS_PRIVILEGE - -/* This bit is set in user (i.e. non-supervisor) mode */ -#define ST_PR 0x0100 /* PRivilege */ - -#endif - -#if HAS_MAPPING - -/* This tells which map is currently in use */ -#define ST_MF 0x0080 /* Map File */ - -#endif - -#if (HAS_OVERFLOW_INTERRUPT) - -/* This bit is set in ti990/12, TMS9995 and later chips to generate a level-2 interrupt when -the Overflow status bit is set */ -#define ST_OVIE 0x0020 /* OVerflow Interrupt Enable */ - -#endif - -#if (IS_99000) - -/* This bit enables the macrostore feature on tms99000 */ -/* (It is used on ti990/12 with a different meaning.) */ -#define ST_EMR 0x0010 /* Enable Macrostore Rom */ - -#endif - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - -#define ST_IM 0x0003 /* Interrupt Mask */ - -#else - -#define ST_IM 0x000F /* Interrupt Mask */ - -#endif - -/* On models before TMS9995 (TMS9989 ?), unused ST bits are always forced to 0, so we define -a ST_MASK */ -#if (USE_ST_MASK) - #if (TMS99XX_MODEL == TI990_10_ID) - #define ST_MASK 0xFF8F - #elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) -#define ST_MASK 0xFD03 - #else - #define ST_MASK 0xFE0F - #endif -#endif - - -/* error interrupt register bits */ - -#if (TMS99XX_MODEL == TI990_10_ID) - -/* This bit is set in user (i.e. non-supervisor) mode */ -#define EIR_MAPERR 0x0800 /* memory MAPping ERRor */ -#define EIR_MER 0x1000 /* Memory parity ERRor */ -#define EIR_ILLOP 0x2000 /* ILLegal OPcode */ -#define EIR_PRIVOP 0x4000 /* PRiviledged OPeration */ -#define EIR_TIMEOUT 0x8000 /* TILINE TIMEOUT */ - -#endif - - -/* Offsets for registers. */ -#define R0 0 -#define R1 2 -#define R2 4 -#define R3 6 -#define R4 8 -#define R5 10 -#define R6 12 -#define R7 14 -#define R8 16 -#define R9 18 -#define R10 20 -#define R11 22 -#define R12 24 -#define R13 26 -#define R14 28 -#define R15 30 - -struct map_file_t -{ - uint16_t L[3], B[3]; /* actual registers */ - uint32_t limit[3], bias[3]; /* equivalent in a more convenient form */ -}; - -struct tms99xx_state -{ -/* "actual" tms9900 registers : */ - uint16_t WP; /* Workspace pointer */ - uint16_t PC; /* Program counter */ - uint16_t STATUS; /* STatus register */ - -/* Now, data used for emulation */ - uint8_t lastparity; - char lds_flag, ldd_flag; - uint16_t IR; /* Instruction register, with the currently parsed opcode */ - - uint8_t interrupt_pending; /* true if an interrupt must be honored... */ - -#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) - uint8_t load_state; /* nonzero if the LOAD* line is active (low) */ -#endif - -#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) - /* On tms9900, we cache the state of INTREQ* and IC0-IC3 here */ - /* On tms9980/9981, we translate the state of IC0-IC2 to the equivalent state for a tms9900, - and store the result here */ - uint8_t irq_level; /* when INTREQ* is active, interrupt level on IC0-IC3 ; else always 16 */ - uint8_t irq_state; /* nonzero if the INTREQ* line is active (low) */ - /* with TMS9940, bit 0 means INT1, bit 1 decrementer, bit 2 INT2 */ -#elif (TMS99XX_MODEL == TMS9995_ID) - /* tms9995 is quite different : it latches the interrupt inputs */ - uint8_t irq_level; /* We store the level of the request with the highest level here */ - uint8_t int_state; /* interrupt lines state */ - uint8_t int_latch; /* interrupt latches state */ -#endif - - /* interrupt callback */ - /* note that this callback is used by tms9900_set_irq_line(cpustate) and tms9980a_set_irq_line(cpustate) to - retreive the value on IC0-IC3 (non-standard behaviour) */ - device_irq_acknowledge_delegate irq_callback; - legacy_cpu_device *device; - address_space *program; - address_space *io; - int icount; - - uint8_t IDLE; /* nonzero if processor is IDLE - i.e waiting for interrupt while writing - special data on CRU bus */ - -#if HAS_MAPPING - uint8_t mapping_on; /* set by a CRU write */ - map_file_t map_files[3]; /* internal mapper registers */ - uint8_t cur_map; /* equivalent to ST_MF status bit */ - uint8_t cur_src_map; /* set to 2 by LDS */ - uint8_t cur_dst_map; /* set to 2 by LDD */ - -#if (TMS99XX_MODEL == TI990_10_ID) - uint8_t reset_maperr; /* reset mapper error flag line (reset flags in 945417-9701 p. 3-90) */ - - uint32_t mapper_address_latch; /* used to load the map file and for diagnostic purpose */ - uint16_t mapper_cru_read_register; /* read register select code for mapper cru interface */ - uint8_t diaglat; /* set when diagnostic address latch is done */ - uint8_t latch_control[3]; /* latch control */ - -#endif -#endif - -#if (TMS99XX_MODEL == TI990_10_ID) - uint16_t error_interrupt_register; /* one flag for each interrupt condition */ - ti99xx_error_interrupt_func error_interrupt_callback; -#endif - -#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) - uint8_t RAM[256]; /* on-chip RAM (I know this is weird, but the internal bus is 16-bit-wide, whereas the external bus is 8-bit-wide) */ -#endif - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) - /* on-chip event counter/timer*/ - uint8_t decrementer_enabled; - uint16_t decrementer_interval; - uint16_t decrementer_count; /* used in event counter mode*/ - emu_timer *timer; /* used in timer mode */ -#endif - -#if (TMS99XX_MODEL == TMS9995_ID) - /* additionnal registers */ - uint16_t flag; /* flag register */ - uint8_t MID_flag; /* MID flag register */ - - /* chip config, which can be set on reset */ - uint8_t memory_wait_states_byte; - uint8_t memory_wait_states_word; - - /* mask option (off on normal tms9995) */ - uint8_t is_mp9537; -#endif - - /* Some instructions (i.e. XOP, BLWP, and MID) disable interrupt recognition until another - instruction is executed : so they set this flag */ - uint8_t disable_interrupt_recognition; - - /* notify the driver of changes in IDLE state */ - ti99xx_idle_func idle_callback; - -#if EXTERNAL_INSTRUCTION_CALLBACK - ti99xx_rset_func rset_callback; - ti99xx_lrex_func lrex_callback; - ti99xx_ckon_ckof_func ckon_ckof_callback; -#endif - - int write_inhibit; - int extra_byte; /* buffer holding the unused byte in a word read */ -}; - -static inline tms99xx_state *get_safe_token(device_t *device) -{ - assert(device != nullptr); -// assert(device->type() == TMS99XX_GET_INFO); - return (tms99xx_state *)downcast<legacy_cpu_device *>(device)->token(); -} - -#if (TMS99XX_MODEL == TMS9995_ID) -static void reset_decrementer(tms99xx_state *cpustate); -#endif - - -#if (TMS99XX_MODEL == TI990_10_ID) - -/* - accessor for the internal ROM -*/ -READ16_HANDLER(ti990_10_internal_r) -{ - //return cpustate->ROM[offset]; - return space.read_word(0x1ffc00+offset); -} - -#endif - -#if (TMS99XX_MODEL == TMS9995_ID) - -/* - accessor for the first 252 bytes of internal RAM -*/ -READ8_HANDLER(tms9995_internal1_r) -{ - tms99xx_state *cpustate = get_safe_token(&space.device()); - return cpustate->RAM[offset]; -} - -WRITE8_HANDLER(tms9995_internal1_w) -{ - tms99xx_state *cpustate = get_safe_token(&space.device()); - cpustate->RAM[offset]=data; -} - -/* - accessor for the last 4 bytes of internal RAM -*/ -READ8_HANDLER(tms9995_internal2_r) -{ - tms99xx_state *cpustate = get_safe_token(&space.device()); - return cpustate->RAM[offset+0xfc]; -} - -WRITE8_HANDLER(tms9995_internal2_w) -{ - tms99xx_state *cpustate = get_safe_token(&space.device()); - cpustate->RAM[offset+0xfc]=data; -} - -#endif - -#if (TMS99XX_MODEL == TI990_10_ID) - - /* on-board ROMs are not emulated (we use a hack) */ - - #define readword(cs, addr) readwordX((cs), (addr), (cs)->cur_map) - static int readwordX(tms99xx_state *cpustate, int addr, int map_file) - { - if ((map_file == 0) && (addr >= 0xf800)) - { /* intercept TPCS and CPU ROM */ - if (addr < 0xfc00) - /* TPCS */ - return cpustate->program->read_word(0x1f0000+addr); - else - /* CPU ROM */ - return cpustate->program->read_word(0x1f0000+addr); /* hack... */ - } - else if (! cpustate->mapping_on) - { - return cpustate->program->read_word(addr); - } - else - { - int map_index; - - if (addr <= cpustate->map_files[map_file].limit[0]) - map_index = 0; - else if (addr <= cpustate->map_files[map_file].limit[1]) - map_index = 1; - else if (addr <= cpustate->map_files[map_file].limit[2]) - map_index = 2; - else - { /* mapping error */ - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = addr; - if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) - { - cpustate->error_interrupt_register |= EIR_MAPERR; - cpustate->write_inhibit = 1; - } - return cpustate->program->read_word(addr); - } - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; - if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) - cpustate->diaglat = 1; - return cpustate->program->read_word(cpustate->map_files[map_file].bias[map_index]+addr); - } - } - - #define writeword(cs, addr, data) writewordX((cs), (addr), (data), (cs)->cur_map) - static void writewordX(tms99xx_state *cpustate, int addr, int data, int map_file) - { - if ((map_file == 0) && (addr >= 0xf800)) - { /* intercept TPCS and CPU ROM */ - if (addr < 0xfc00) - /* TPCS */ - cpustate->program->write_word(0x1f0000+addr, data); - else - /* CPU ROM */ - cpustate->program->write_word(0x1f0000+addr, data); /* hack... */ - } - else if (! cpustate->mapping_on) - { - cpustate->program->write_word(addr, data); - } - else - { - int map_index; - - if (addr <= cpustate->map_files[map_file].limit[0]) - map_index = 0; - else if (addr <= cpustate->map_files[map_file].limit[1]) - map_index = 1; - else if (addr <= cpustate->map_files[map_file].limit[2]) - map_index = 2; - else - { /* mapping error */ - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = addr; - if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) - { - cpustate->error_interrupt_register |= EIR_MAPERR; - cpustate->write_inhibit = 1; - } - if (cpustate->write_inhibit) - (void)cpustate->program->read_word(addr); - else - cpustate->program->write_word(addr, data); - return; - } - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; - if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) - cpustate->diaglat = 1; - cpustate->program->write_word(cpustate->map_files[map_file].bias[map_index]+addr, data); - } - } - - #define readbyte(cs, addr) readbyteX((cs), (addr), (cs)->cur_map) - static int readbyteX(tms99xx_state *cpustate, int addr, int map_file) - { - if ((map_file == 0) && (addr >= 0xf800)) - { /* intercept TPCS and CPU ROM */ - if (addr < 0xfc00) - /* TPCS */ - return cpustate->program->read_byte(0x1f0000+addr); - else - /* CPU ROM */ - return cpustate->program->read_byte(0x1f0000+addr); /* hack... */ - } - else if (! cpustate->mapping_on) - { - return cpustate->program->read_byte(addr); - } - else - { - int map_index; - - if (addr <= cpustate->map_files[map_file].limit[0]) - map_index = 0; - else if (addr <= cpustate->map_files[map_file].limit[1]) - map_index = 1; - else if (addr <= cpustate->map_files[map_file].limit[2]) - map_index = 2; - else - { /* mapping error */ - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = addr; - if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) - { - cpustate->error_interrupt_register |= EIR_MAPERR; - cpustate->write_inhibit = 1; - } - return cpustate->program->read_byte(addr); - } - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; - if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) - cpustate->diaglat = 1; - return cpustate->program->read_byte(cpustate->map_files[map_file].bias[map_index]+addr); - } - } - - #define writebyte(cs, addr, data) writebyteX((cs), (addr), (data), (cs)->cur_map) - static void writebyteX(tms99xx_state *cpustate, int addr, int data, int map_file) - { - if ((map_file == 0) && (addr >= 0xf800)) - { /* intercept TPCS and CPU ROM */ - if (addr < 0xfc00) - /* TPCS */ - cpustate->program->write_byte(0x1f0000+addr, data); - else - /* CPU ROM */ - cpustate->program->write_byte(0x1f0000+addr, data); /* hack... */ - } - else if (! cpustate->mapping_on) - { - cpustate->program->write_byte(addr, data); - } - else - { - int map_index; - - if (addr <= cpustate->map_files[map_file].limit[0]) - map_index = 0; - else if (addr <= cpustate->map_files[map_file].limit[1]) - map_index = 1; - else if (addr <= cpustate->map_files[map_file].limit[2]) - map_index = 2; - else - { /* mapping error */ - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = addr; - if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) - { - cpustate->error_interrupt_register |= EIR_MAPERR; - cpustate->write_inhibit = 1; - } - if (cpustate->write_inhibit) - (void)cpustate->program->read_byte(addr); - else - cpustate->program->write_byte(addr, data); - return; - } - if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) - cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; - if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) - cpustate->diaglat = 1; - cpustate->program->write_byte(cpustate->map_files[map_file].bias[map_index]+addr, data); - } - } - -#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) - /*16-bit data bus, 16-bit address bus (internal bus in the case of TMS9940)*/ - /*Note that tms9900 actually never accesses a single byte : when performing byte operations, - it reads a 16-bit word, changes the relevant byte, then write a complete word. You should - remember this when writing memory handlers.*/ - /*This does not apply to tms9995 and tms99xxx, but does apply to tms9980 (see below).*/ - - #define readword(cs, addr) (cs)->program->read_word(addr) - #define writeword(cs, addr,data) (cs)->program->write_word((addr), (data)) - - #define readbyte(cs, addr) (cs)->program->read_byte(addr) - #define writebyte(cs, addr,data) (cs)->program->write_byte((addr),(data)) - -#elif (TMS99XX_MODEL == TMS9980_ID) - /*8-bit data bus, 14-bit address*/ - /*Note that tms9980 never accesses a single byte (however crazy it may seem). Although this - makes memory access slower, I have emulated this feature, because if I did otherwise, - there would be some implementation problems in some driver sooner or later.*/ - - static inline int readword(tms99xx_state *cpustate, int addr) - { - int val; - - cpustate->icount -= 2; - val = cpustate->program->read_byte(addr); - return (val << 8) | cpustate->program->read_byte(addr+1); - } - #define writeword(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr), (data) >> 8); cpustate->program->write_byte((addr) + 1, (data) & 0xff); } - -#if 0 - #define readbyte(cs, addr) ((cs)->icount -= 2, (cs)->program->read_byte(addr)) - #define writebyte(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr),(data)); } -#else - /*This is how it really works*/ - /*Note that every writebyte must match a readbyte (which is indeed the case)*/ - - static int readbyte(tms99xx_state *cpustate, int addr) - { - cpustate->icount -= 2; - if (addr & 1) - { - cpustate->extra_byte = cpustate->program->read_byte(addr-1); - return cpustate->program->read_byte(addr); - } - else - { - int val = cpustate->program->read_byte(addr); - cpustate->extra_byte = cpustate->program->read_byte(addr+1); - return val; - } - } - static void writebyte (tms99xx_state *cpustate, int addr, int data) - { - cpustate->icount -= 2; - if (addr & 1) - { - cpustate->program->write_byte(addr-1, cpustate->extra_byte); - cpustate->program->write_byte(addr, data); - } - else - { - cpustate->program->write_byte(addr, data); - cpustate->program->write_byte(addr+1, cpustate->extra_byte); - } - } -#endif - -#elif (TMS99XX_MODEL == TMS9985_ID) - /*Note that every writebyte must match a readbyte (which is indeed the case)*/ - - static int readword(tms99xx_state *cpustate, int addr) - { - if (addr < 0x2000) - { - } - else if ((addr >= 0x8300) && (addr < 0x8400)) - { - } - else - { - cpustate->icount -= 2; - return (cpustate->program->read_byte(addr) << 8) + cpustate->program->read_byte(addr + 1); - } - } - static void writeword(tms99xx_state *cpustate, int addr, int data) - { - if ((addr >= 0x8300) && (addr < 0x8400)) - { - } - else if (!(addr < 0x2000)) - { - cpustate->icount -= 2; - cpustate->program->write_byte(addr, data >> 8); - cpustate->program->write_byte(addr + 1, data & 0xff); - } - } - - static int readbyte(tms99xx_state *cpustate, int addr) - { - if (addr < 0x2000) - { - } - else if ((addr >= 0x8300) && (addr < 0x8400)) - { - } - else - { - cpustate->icount -= 2; - if (addr & 1) - { - cpustate->extra_byte = cpustate->program->read_byte(addr-1); - return cpustate->program->read_byte(addr); - } - else - { - int val = cpustate->program->read_byte(addr); - cpustate->extra_byte = cpustate->program->read_byte(addr+1); - return val; - } - } - } - static void writebyte(tms99xx_state *cpustate, int addr, int data) - { - if ((addr >= 0x8300) && (addr < 0x8400)) - { - } - else if (!(addr < 0x2000)) - { - cpustate->icount -= 2; - if (addr & 1) - { - cpustate->program->write_byte(addr-1, cpustate->extra_byte); - cpustate->program->write_byte(addr, data); - } - else - { - cpustate->program->write_byte(addr, data); - cpustate->program->write_byte(addr+1, cpustate->extra_byte); - } - } - } - -#elif (TMS99XX_MODEL == TMS9995_ID) - /*8-bit external data bus, with on-chip 16-bit RAM, and 16-bit address bus*/ - /*The code is complex, so we use functions rather than macros*/ - - static TIMER_CALLBACK( decrementer_callback ); - - static int readword(tms99xx_state *cpustate, int addr) - { - if ((addr < 0xf000) || (cpustate->is_mp9537)) - { - int reply; - cpustate->icount -= cpustate->memory_wait_states_word; - reply = cpustate->program->read_byte(addr); - return (reply << 8) | cpustate->program->read_byte(addr + 1); - } - else if (addr < 0xf0fc) - { - return *(uint16_t *)(& cpustate->RAM[addr - 0xf000]); - } - else if (addr < 0xfffa) - { - int reply; - cpustate->icount -= cpustate->memory_wait_states_word; - reply = cpustate->program->read_byte(addr); - return (reply << 8) | cpustate->program->read_byte(addr + 1); - } - else if (addr < 0xfffc) - { - /* read decrementer */ - if (cpustate->decrementer_enabled && !(cpustate->flag & 1)) - /* timer mode, timer enabled */ - return cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16); - else - /* event counter mode or timer mode, timer disabled */ - return cpustate->decrementer_count; - } - else - { - return *(uint16_t *)(& cpustate->RAM[addr - 0xff00]); - } - } - - static void writeword (tms99xx_state *cpustate, int addr, int data) - { - if ((addr < 0xf000) || (cpustate->is_mp9537)) - { - cpustate->icount -= cpustate->memory_wait_states_word; - cpustate->program->write_byte(addr, data >> 8); - cpustate->program->write_byte(addr + 1, data & 0xff); - } - else if (addr < 0xf0fc) - { - *(uint16_t *)(& cpustate->RAM[addr - 0xf000]) = data; - } - else if (addr < 0xfffa) - { - cpustate->icount -= cpustate->memory_wait_states_word; - cpustate->program->write_byte(addr, data >> 8); - cpustate->program->write_byte(addr + 1, data & 0xff); - } - else if (addr < 0xfffc) - { - /* write decrementer */ - cpustate->decrementer_interval = data; - reset_decrementer(cpustate); - } - else - { - *(uint16_t *)(& cpustate->RAM[addr - 0xff00]) = data; - } - } - - static int readbyte(tms99xx_state *cpustate, int addr) - { - if ((addr < 0xf000) || (cpustate->is_mp9537)) - { - cpustate->icount -= cpustate->memory_wait_states_byte; - return cpustate->program->read_byte(addr); - } - else if (addr < 0xf0fc) - { - return cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)]; - } - else if (addr < 0xfffa) - { - cpustate->icount -= cpustate->memory_wait_states_byte; - return cpustate->program->read_byte(addr); - } - else if (addr < 0xfffc) - { - /* read decrementer */ - int value; - - if (cpustate->decrementer_enabled && !(cpustate->flag & 1)) - /* timer mode, timer enabled */ - value = cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16); - else - /* event counter mode or timer mode, timer disabled */ - value = cpustate->decrementer_count; - - if (addr & 1) - return (value & 0xFF); - else - return (value >> 8); - } - else - { - return cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)]; - } - } - - static void writebyte (tms99xx_state *cpustate, int addr, int data) - { - if ((addr < 0xf000) || (cpustate->is_mp9537)) - { - cpustate->icount -= cpustate->memory_wait_states_byte; - cpustate->program->write_byte(addr, data); - } - else if (addr < 0xf0fc) - { - cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)] = data; - } - else if (addr < 0xfffa) - { - cpustate->icount -= cpustate->memory_wait_states_byte; - cpustate->program->write_byte(addr, data); - } - else if (addr < 0xfffc) - { - /* write decrementer */ - /* Note that a byte write to tms9995 timer messes everything up. */ - cpustate->decrementer_interval = (data << 8) | data; - reset_decrementer(cpustate); - } - else - { - cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)] = data; - } - } - -#else - - #error "memory access not implemented" - -#endif - -#if !HAS_MAPPING - #define readwordX(cs, addr, map_file) readword(cs, addr) - #define writewordX(cs, addr, data, map_file) writeword(cs, (addr), (data)) - #define readbyteX(cs, addr, map_file) readbyte(cs, addr) - #define writebyteX(cs, addr, data, map_file) writebyte(cs, (addr), (data)) -#endif - -#define READREG(reg) readword(cpustate, (cpustate->WP+(reg)) & 0xffff) -#define WRITEREG(reg, data) writeword(cpustate, (cpustate->WP+(reg)) & 0xffff, (data)) - -static inline uint16_t READREG_DEBUG(tms99xx_state *cpustate, int reg) -{ - int temp = cpustate->icount; - uint16_t result = READREG(reg); - cpustate->icount = temp; - return result; -} - -static inline void WRITEREG_DEBUG(tms99xx_state *cpustate, int reg, uint16_t data) -{ - int temp = cpustate->icount; - WRITEREG(reg, data); - cpustate->icount = temp; -} - -#if (TMS99XX_MODEL == TI990_10_ID) - READ8_HANDLER(ti990_10_mapper_cru_r) - { - tms99xx_state *cpustate = get_safe_token(&space.device()); - int reply = 0; - - switch(cpustate->mapper_cru_read_register) - { - case 0xb000: - reply = cpustate->map_files[cpustate->cur_map].B[0]; - break; - case 0xb001: - reply = cpustate->map_files[cpustate->cur_map].B[1]; - break; - case 0xb010: - reply = cpustate->map_files[cpustate->cur_map].B[2]; - break; - case 0xb011: - reply = cpustate->map_files[cpustate->cur_map].L[0]; - break; - case 0xb100: - reply = cpustate->map_files[cpustate->cur_map].L[1]; - break; - case 0xb101: - reply = cpustate->map_files[cpustate->cur_map].L[2]; - break; - case 0xb110: - reply = cpustate->mapper_address_latch; - break; - case 0xb111: - reply = cpustate->mapper_address_latch >> 16; - break; - } - - if (offset) - return (reply >> 8) & 0xff; - else - return reply & 0xff; - } - - WRITE8_HANDLER(ti990_10_mapper_cru_w) - { - tms99xx_state *cpustate = get_safe_token(&space.device()); - switch (offset) - { - case 0: - case 1: - case 2: - /* read register select */ - if (data) - cpustate->mapper_cru_read_register |= (1 << offset); - else - cpustate->mapper_cru_read_register &= ~ (1 << offset); - break; - case 3: - /* enable mapping */ - cpustate->mapping_on = data; - break; - case 4: - /* reset flags */ - cpustate->reset_maperr = data; - if (data) - { - cpustate->error_interrupt_register &= ~ EIR_MAPERR; - cpustate->diaglat = 0; - } - break; - case 5: - case 6: - case 7: - /* latch control */ - cpustate->latch_control[7-offset] = data; - break; - } - } - - static inline void handle_error_interrupt(tms99xx_state *cpustate) - { - if (cpustate->error_interrupt_callback) - (*cpustate->error_interrupt_callback)(cpustate->device, cpustate->error_interrupt_register ? 1 : 0); - } - - READ8_HANDLER(ti990_10_eir_cru_r) - { - tms99xx_state *cpustate = get_safe_token(&space.device()); - return (offset == 1) ? (cpustate->error_interrupt_register & 0xff) : 0; - } - - WRITE8_HANDLER(ti990_10_eir_cru_w) - { - tms99xx_state *cpustate = get_safe_token(&space.device()); - if (offset < 4) /* does not work for EIR_MAPERR */ - { - cpustate->error_interrupt_register &= ~ (1 << offset); - - handle_error_interrupt(cpustate); - } - } - - -#endif - -/* Interrupt mask */ -#define IMASK (cpustate->STATUS & ST_IM) - -/* - CYCLES macro : you provide timings for tms9900 and tms9995, and the macro chooses for you. - - BTW, I have no idea what the timings are for tms9989 and tms99xxx... -*/ -#if TMS99XX_MODEL == TI990_10_ID - /* Use TI990/10 timings*/ - #define CYCLES(a,b,c) cpustate->icount -= a -#elif TMS99XX_MODEL <= TMS9985_ID - /* Use TMS9900/TMS9980 timings*/ - #define CYCLES(a,b,c) cpustate->icount -= b -#else - /* Use TMS9995 timings*/ - #define CYCLES(a,b,c) cpustate->icount -= c*4 -#endif - -#if (TMS99XX_MODEL == TMS9995_ID) - -static void set_flag0(tms99xx_state *cpustate, int val); -static void set_flag1(tms99xx_state *cpustate, int val); - -#endif - -/************************************************************************ - * Status register functions - ************************************************************************/ - -/* - remember that the OP ST bit is maintained in cpustate->lastparity -*/ - -/* - setstat sets the ST_OP bit according to cpustate->lastparity - - It must be called before reading the ST register. -*/ - -static void setstat(tms99xx_state *cpustate) -{ - int i; - uint8_t a; - - cpustate->STATUS &= ~ ST_OP; - - /* We set the parity bit. */ - a = cpustate->lastparity; - - for (i=0; i<8; i++) /* 8 bits to test */ - { - if (a & 1) /* If current bit is set */ - cpustate->STATUS ^= ST_OP; /* we toggle the ST_OP bit */ - - a >>= 1; /* Next bit. */ - } -} - -/* - getstat sets emulator's cpustate->lastparity variable according to 9900's STATUS bits. - It must be called on interrupt return, or when, for some reason, - the emulated program sets the STATUS register directly. -*/ -static void getstat(tms99xx_state *cpustate) -{ -#if (USE_ST_MASK) - cpustate->STATUS &= ST_MASK; /* unused bits are forced to 0 */ -#endif - - if (cpustate->STATUS & ST_OP) - cpustate->lastparity = 1; - else - cpustate->lastparity = 0; - -#if HAS_MAPPING - cpustate->cur_map = (cpustate->STATUS & ST_MF) ? 1 : 0; -#endif -} - -/* - A few words about the following functions. - - A big portability issue is the behavior of the ">>" instruction with the sign bit, which has - not been normalised. Every compiler does whatever it thinks smartest. - My code assumed that when shifting right signed numbers, the operand is left-filled with a - copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s. - This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time - (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers - are bound to disagree. - - So, I had to create special functions with predefined tables included, so that this code work - on every compiler. BUT this is a real slow-down. - So, you might have to include a few lines in assembly to make this work better. - Sorry about this, this problem is really unpleasant and absurd, but it is not my fault. -*/ - - -static const uint16_t right_shift_mask_table[17] = -{ - 0xFFFF, - 0x7FFF, - 0x3FFF, - 0x1FFF, - 0x0FFF, - 0x07FF, - 0x03FF, - 0x01FF, - 0x00FF, - 0x007F, - 0x003F, - 0x001F, - 0x000F, - 0x0007, - 0x0003, - 0x0001, - 0x0000 -}; - -static const uint16_t inverted_right_shift_mask_table[17] = -{ - 0x0000, - 0x8000, - 0xC000, - 0xE000, - 0xF000, - 0xF800, - 0xFC00, - 0xFE00, - 0xFF00, - 0xFF80, - 0xFFC0, - 0xFFE0, - 0xFFF0, - 0xFFF8, - 0xFFFC, - 0xFFFE, - 0xFFFF -}; - -static inline uint16_t logical_right_shift(uint16_t val, int c) -{ - return((val>>c) & right_shift_mask_table[c]); -} - -static inline int16_t arithmetic_right_shift(int16_t val, int c) -{ - if (val < 0) - return((val>>c) | inverted_right_shift_mask_table[c]); - else - return((val>>c) & right_shift_mask_table[c]); -} - - - - - -/* - Set lae -*/ -static inline void setst_lae(tms99xx_state *cpustate, int16_t val) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); - - if (val > 0) - cpustate->STATUS |= (ST_LGT | ST_AGT); - else if (val < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; -} - - -/* - Set laep (BYTE) -*/ -static inline void setst_byte_laep(tms99xx_state *cpustate, int8_t val) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); - - if (val > 0) - cpustate->STATUS |= (ST_LGT | ST_AGT); - else if (val < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - cpustate->lastparity = val; -} - -/* - For COC, CZC, and TB -*/ -static inline void setst_e(tms99xx_state *cpustate, uint16_t val, uint16_t to) -{ - if (val == to) - cpustate->STATUS |= ST_EQ; - else - cpustate->STATUS &= ~ ST_EQ; -} - -/* - For CI, C, CB -*/ -static inline void setst_c_lae(tms99xx_state *cpustate, uint16_t to, uint16_t val) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); - - if (val == to) - cpustate->STATUS |= ST_EQ; - else - { - if ( ((int16_t) val) > ((int16_t) to) ) - cpustate->STATUS |= ST_AGT; - if ( ((uint16_t) val) > ((uint16_t) to) ) - cpustate->STATUS |= ST_LGT; - } -} - -/* - Set laeco for add -*/ -static inline int16_t setst_add_laeco(tms99xx_state *cpustate, int a, int b) -{ - uint32_t res; - int16_t res2; - - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); - - res = (a & 0xffff) + (b & 0xffff); - - if (res & 0x10000) - cpustate->STATUS |= ST_C; - - if ((res ^ b) & (res ^ a) & 0x8000) - cpustate->STATUS |= ST_OV; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (((a & b) | ((a | b) & ~ res)) & 0x0800) - cpustate->STATUS |= ST_DC; -#endif - - res2 = (int16_t) res; - - if (res2 > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (res2 < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return res2; -} - - -/* - Set laeco for subtract -*/ -static inline int16_t setst_sub_laeco(tms99xx_state *cpustate, int a, int b) -{ - uint32_t res; - int16_t res2; - - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); - - res = (a & 0xffff) - (b & 0xffff); - - if (! (res & 0x10000)) - cpustate->STATUS |= ST_C; - - if ((a ^ b) & (a ^ res) & 0x8000) - cpustate->STATUS |= ST_OV; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800) - cpustate->STATUS |= ST_DC; -#endif - - res2 = (int16_t) res; - - if (res2 > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (res2 < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return res2; -} - - -/* - Set laecop for add (BYTE) -*/ -static inline int8_t setst_addbyte_laecop(tms99xx_state *cpustate, int a, int b) -{ - unsigned int res; - int8_t res2; - - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); - - res = (a & 0xff) + (b & 0xff); - - if (res & 0x100) - cpustate->STATUS |= ST_C; - - if ((res ^ b) & (res ^ a) & 0x80) - cpustate->STATUS |= ST_OV; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (((a & b) | ((a | b) & ~ res)) & 0x08) - cpustate->STATUS |= ST_DC; -#endif - - res2 = (int8_t) res; - - if (res2 > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (res2 < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - cpustate->lastparity = res2; - - return res2; -} - - -/* - Set laecop for subtract (BYTE) -*/ -static inline int8_t setst_subbyte_laecop(tms99xx_state *cpustate, int a, int b) -{ - unsigned int res; - int8_t res2; - - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); - - res = (a & 0xff) - (b & 0xff); - - if (! (res & 0x100)) - cpustate->STATUS |= ST_C; - - if ((a ^ b) & (a ^ res) & 0x80) - cpustate->STATUS |= ST_OV; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08) - cpustate->STATUS |= ST_DC; -#endif - - res2 = (int8_t) res; - - if (res2 > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (res2 < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - cpustate->lastparity = res2; - - return res2; -} - - - -/* - For NEG -*/ -static inline void setst_laeo(tms99xx_state *cpustate, int16_t val) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV); - - if (val > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (val < 0) - { - cpustate->STATUS |= ST_LGT; - if (((uint16_t) val) == 0x8000) - cpustate->STATUS |= ST_OV; - } - else - cpustate->STATUS |= ST_EQ; -} - - - -/* - Meat of SRA -*/ -static inline uint16_t setst_sra_laec(tms99xx_state *cpustate, int16_t a, uint16_t c) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); - - if (c != 0) - { - a = arithmetic_right_shift(a, c-1); - if (a & 1) // The carry bit equals the last bit that is shifted out - cpustate->STATUS |= ST_C; - a = arithmetic_right_shift(a, 1); - } - - if (a > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (a < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return a; -} - - -/* - Meat of SRL. Same algorithm as SRA, except that we fills in with 0s. -*/ -static inline uint16_t setst_srl_laec(tms99xx_state *cpustate, uint16_t a,uint16_t c) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); - - if (c != 0) - { - a = logical_right_shift(a, c-1); - if (a & 1) - cpustate->STATUS |= ST_C; - a = logical_right_shift(a, 1); - } - - if (((int16_t) a) > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (((int16_t) a) < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return a; -} - - -// -// Meat of SRC -// -static inline uint16_t setst_src_laec(tms99xx_state *cpustate, uint16_t a,uint16_t c) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); - - if (c != 0) - { - a = logical_right_shift(a, c) | (a << (16-c)); - if (a & 0x8000) // The carry bit equals the last bit that is shifted out - cpustate->STATUS |= ST_C; - } - - if (((int16_t) a) > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (((int16_t) a) < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return a; -} - - -// -// Meat of SLA -// -static inline uint16_t setst_sla_laeco(tms99xx_state *cpustate, uint16_t a, uint16_t c) -{ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); - - if (c != 0) - { - { - register uint16_t mask; - register uint16_t ousted_bits; - - mask = 0xFFFF << (16-c-1); - ousted_bits = a & mask; - - if (ousted_bits) // If ousted_bits is neither all 0s - if (ousted_bits ^ mask) // nor all 1s, - cpustate->STATUS |= ST_OV; // we set overflow - } - - a <<= c-1; - if (a & 0x8000) // The carry bit equals the last bit that is shifted out - cpustate->STATUS |= ST_C; - - a <<= 1; - } - - if (((int16_t) a) > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (((int16_t) a) < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - return a; -} - -/**************************************************************************/ - -static void register_for_save_state(device_t *device) -{ - tms99xx_state *cpustate = get_safe_token(device); - device->save_item(NAME(cpustate->WP)); - device->save_item(NAME(cpustate->PC)); - device->save_item(NAME(cpustate->STATUS)); - device->save_item(NAME(cpustate->interrupt_pending)); - -#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) - device->save_item(NAME(cpustate->load_state)); -#endif - -#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) - device->save_item(NAME(cpustate->irq_level)); - device->save_item(NAME(cpustate->irq_state)); -#elif (TMS99XX_MODEL == TMS9995_ID) - device->save_item(NAME(cpustate->irq_level)); - device->save_item(NAME(cpustate->int_state)); - device->save_item(NAME(cpustate->int_latch)); -#endif - - device->save_item(NAME(cpustate->IDLE)); - -#if HAS_MAPPING - device->save_item(NAME(cpustate->mapping_on)); - device->save_item(NAME(cpustate->map_files[0].L)); - device->save_item(NAME(cpustate->map_files[0].B)); - device->save_item(NAME(cpustate->map_files[0].limit)); - device->save_item(NAME(cpustate->map_files[0].bias)); - device->save_item(NAME(cpustate->map_files[1].L)); - device->save_item(NAME(cpustate->map_files[1].B)); - device->save_item(NAME(cpustate->map_files[1].limit)); - device->save_item(NAME(cpustate->map_files[1].bias)); - device->save_item(NAME(cpustate->map_files[2].L)); - device->save_item(NAME(cpustate->map_files[2].B)); - device->save_item(NAME(cpustate->map_files[2].limit)); - device->save_item(NAME(cpustate->map_files[2].bias)); - device->save_item(NAME(cpustate->cur_map)); - device->save_item(NAME(cpustate->cur_src_map)); - device->save_item(NAME(cpustate->cur_dst_map)); - -#if (TMS99XX_MODEL == TI990_10_ID) - device->save_item(NAME(cpustate->reset_maperr)); - device->save_item(NAME(cpustate->mapper_address_latch)); - device->save_item(NAME(cpustate->mapper_cru_read_register)); - device->save_item(NAME(cpustate->diaglat)); - device->save_item(NAME(cpustate->latch_control)); -#endif -#endif - -#if (TMS99XX_MODEL == TI990_10_ID) - device->save_item(NAME(cpustate->error_interrupt_register)); -#endif - -#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) - device->save_item(NAME(cpustate->RAM)); -#endif - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) - device->save_item(NAME(cpustate->decrementer_enabled)); - device->save_item(NAME(cpustate->decrementer_interval)); - device->save_item(NAME(cpustate->decrementer_count)); -#endif - -#if (TMS99XX_MODEL == TMS9995_ID) - device->save_item(NAME(cpustate->flag)); - device->save_item(NAME(cpustate->MID_flag)); - device->save_item(NAME(cpustate->memory_wait_states_byte)); - device->save_item(NAME(cpustate->memory_wait_states_word)); - device->save_item(NAME(cpustate->is_mp9537)); -#endif - - device->save_item(NAME(cpustate->disable_interrupt_recognition)); -} - - -static CPU_INIT( tms99xx ) -{ - const TMS99XX_RESET_PARAM *param = (const TMS99XX_RESET_PARAM *) device->static_config(); - tms99xx_state *cpustate = get_safe_token(device); - - register_for_save_state(device); - - cpustate->irq_level = 16; - cpustate->irq_callback = irqcallback; - cpustate->device = device; - cpustate->program = &device->space(AS_PROGRAM); - cpustate->io = &device->space(AS_IO); - -#if (TMS99XX_MODEL == TMS9995_ID) - cpustate->timer = device->machine().scheduler().timer_alloc(FUNC(decrementer_callback), cpustate); -#endif - - cpustate->idle_callback = param ? param->idle_callback : nullptr; - #if (TMS99XX_MODEL == TI990_10_ID) - cpustate->rset_callback = param ? param->rset_callback : nullptr; - cpustate->lrex_callback = param ? param->lrex_callback : nullptr; - cpustate->ckon_ckof_callback = param ? param->ckon_ckof_callback : nullptr; - - cpustate->error_interrupt_callback = param ? param->error_interrupt_callback : nullptr; - #endif - -#if (TMS99XX_MODEL == TMS9995_ID) - /* we can ask at reset time that the CPU always generates one wait state automatically */ - if (param == nullptr) - { /* if no param, the default is currently "wait state added" */ - cpustate->memory_wait_states_byte = 4; - cpustate->memory_wait_states_word = 12; - cpustate->is_mp9537 = 0; - } - else - { - cpustate->memory_wait_states_byte = (param->auto_wait_state) ? 4 : 0; - cpustate->memory_wait_states_word = (param->auto_wait_state) ? 12 : 4; - cpustate->is_mp9537 = param->is_mp9537; - } -#endif - -} - -/* - TMS9900 hard reset -*/ -static CPU_RESET( tms99xx ) -{ - tms99xx_state *cpustate = get_safe_token(device); - - cpustate->STATUS = 0; /* TMS9980 and TMS9995 Data Books say so */ - getstat(cpustate); - - #if HAS_MAPPING - cpustate->mapping_on = 0; - { - int i,j; - - for (i=0; i<3; i++) - for (j=0; j<3; j++) - { - cpustate->map_files[i].L[j] = 0; - cpustate->map_files[i].limit[j] = 0xffff; - cpustate->map_files[i].B[j] = 0; - cpustate->map_files[i].bias[j] = 0; - } - } - cpustate->cur_map = 0; /* equivalent to ST_MF status bit */ - cpustate->cur_src_map = 0; /* set to 2 by LDS */ - cpustate->cur_dst_map = 0; /* set to 2 by LDD */ - - cpustate->reset_maperr = 0; - #endif - - if (cpustate->IDLE) - { - cpustate->IDLE = 0; /* clear IDLE condition */ - if (cpustate->idle_callback) - (*cpustate->idle_callback)(device, 0); - } - -#if (TMS99XX_MODEL == TMS9995_ID) - cpustate->MID_flag = 0; - - /* Clear flag bits 0 & 1 */ - set_flag0(cpustate, 0); - set_flag1(cpustate, 0); - - /* Clear internal interrupt latches */ - cpustate->int_latch = 0; - cpustate->flag &= 0xFFE3; -#endif - - /* The ST register and interrupt latches changed, didn't they ? */ - field_interrupt(cpustate); - - contextswitchX(cpustate, 0x0000); - - CYCLES(6, 26, 14); -} - -static CPU_EXIT( tms99xx ) -{ - /* nothing to do ? */ -} - -/* fetch : read one word at * PC, and increment PC. */ -static inline uint16_t fetch(tms99xx_state *cpustate) -{ - uint16_t value = readword(cpustate, cpustate->PC); - cpustate->PC += 2; - return value; -} - - -static CPU_EXECUTE( tms99xx ) -{ - tms99xx_state *cpustate = get_safe_token(device); - - cpustate->lds_flag = 0; - cpustate->ldd_flag = 0; - - do - { - /* all TMS9900 chips I know do not honor interrupts after XOP, BLWP or MID (after any - interrupt-like instruction, actually), and they do not either after LDS and LDD - (There are good reasons for this). */ - if ((cpustate->interrupt_pending) && (! cpustate->disable_interrupt_recognition)) - { - int level; - - level = cpustate->irq_level; - - - if (cpustate->load_state) - { /* LOAD has the highest priority */ - - contextswitchX(cpustate, 0xFFFC); /* load vector, save PC, WP and ST */ - - cpustate->STATUS &= ~ST_IM; /* clear interrupt mask */ - - /* clear IDLE status if necessary */ - if (cpustate->IDLE) - { - cpustate->IDLE = 0; /* clear IDLE condition */ - if (cpustate->idle_callback) - (*cpustate->idle_callback)(device, 0); - } - - CYCLES(6/*to be confirmed*/, 22, 14); - } - else if (level <= IMASK) - { /* a maskable interrupt is honored only if its level isn't greater than IMASK */ - - contextswitchX(cpustate, level*4); /* load vector, save PC, WP and ST */ - - /* change interrupt mask */ - if (level) - { - cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (level -1); /* decrement mask */ - cpustate->interrupt_pending = 0; /* as a consequence, the interrupt request will be subsequently ignored */ - } - else - cpustate->STATUS &= ~ST_IM; /* clear mask (is this correct???) */ - -#if (TMS99XX_MODEL == TMS9995_ID) - cpustate->STATUS &= 0xFE00; -#endif - - /* clear IDLE status if necessary */ - if (cpustate->IDLE) - { - cpustate->IDLE = 0; /* clear IDLE condition */ - if (cpustate->idle_callback) - (*cpustate->idle_callback)(device, 0); - } - -#if (TMS99XX_MODEL == TMS9995_ID) - /* Clear bit in latch */ - /* I think tms9989 does this, too */ - if (level != 2) - { /* Only do this on level 1, 3, 4 interrupts */ - int mask = 1 << level; - int flag_mask = (level == 1) ? 4 : mask; - - cpustate->int_latch &= ~ mask; - cpustate->flag &= ~ flag_mask; - - /* unlike tms9900, we can call the callback */ - if (level == 1) - (* cpustate->irq_callback)(cpustate->device, 0); - else if (level == 4) - (* cpustate->irq_callback)(cpustate->device, 1); - } -#endif - - CYCLES(6, 22, 14); - } - else - { - logerror("tms9900l.c : the interrupt_pending flag was set incorrectly\n"); - cpustate->interrupt_pending = 0; - } - } - - debugger_instruction_hook(device, cpustate->PC); - - if (cpustate->IDLE) - { /* IDLE instruction has halted execution */ - #if EXTERNAL_INSTRUCTION_DECODING - external_instruction_notify(cpustate, 2); - CYCLES(Moof!, 2, 2); /* 2 cycles per CRU write */ - #else - cpustate->icount = 0; /* much simpler... */ - #endif - } - else - { /* we execute an instruction */ - cpustate->disable_interrupt_recognition = 0; /* default value */ - cpustate->IR = fetch(cpustate); - execute(cpustate, cpustate->IR); - #if HAS_MAPPING - if (cpustate->lds_flag) - { - cpustate->lds_flag = 0; - cpustate->cur_src_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/; - } - else - cpustate->cur_src_map = cpustate->cur_map; - if (cpustate->ldd_flag) - { - cpustate->ldd_flag = 0; - cpustate->cur_dst_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/; - } - else - cpustate->cur_dst_map = cpustate->cur_map; - #if (TMS99XX_MODEL == TI990_10_ID) - cpustate->write_inhibit = 0; - #endif - #endif - - #if (HAS_OVERFLOW_INTERRUPT) - #if (TMS99XX_MODEL == TMS9995_ID) - /* Note that TI had some problem implementing this... I don't know if this feature works on - a real-world TMS9995. */ - if ((cpustate->STATUS & ST_OVIE) && (cpustate->STATUS & ST_OV) && (cpustate->irq_level > 2)) - cpustate->irq_level = 2; /* interrupt request */ - #else - #warning "todo..." - #endif - #endif - } - - } while (cpustate->icount > 0); -} - -#if (TMS99XX_MODEL == TI990_10_ID) - -static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) -{ - if (irqline == INPUT_LINE_NMI) - { - cpustate->load_state = state; /* save new state */ - - field_interrupt(cpustate); /* interrupt status changed */ - } - else - { - /*if (cpustate->irq_state == state) - return;*/ - - cpustate->irq_state = state; - - if (state == CLEAR_LINE) - cpustate->irq_level = 16; - /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ - else - cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0); - - field_interrupt(cpustate); /* interrupt state is likely to have changed */ - } -} - -#elif (TMS99XX_MODEL == TMS9900_ID) - -/* -void tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, int state) : change the state of the LOAD* line - - state == 0 -> LOAD* goes high (inactive) - state != 0 -> LOAD* goes low (active) - - While LOAD* is low, we keep triggering LOAD interrupts... - - A problem : some peripherals lower the LOAD* line for a fixed time interval (causing the 1st - instruction of the LOAD interrupt routine to be repeated while the line is low), and will be - perfectly happy with the current scheme, but others might be more clever and wait for the IAQ - (Instruction acquisition) line to go high, and this needs a callback function to emulate. -*/ - -/* -void tms99xx_set_irq_line(cpustate, int irqline, int state) : sets the state of the interrupt line. - - irqline is ignored, and should always be 0. - - state == 0 -> INTREQ* goes high (inactive) - state != 0 -> INTREQ* goes low (active) -*/ -/* - R Nabet 991020, revised 991218 : - In short : interrupt code should call "cpu_set_irq_line(0, 0, ASSERT_LINE);" to set an - interrupt request (level-triggered interrupts). Also, there MUST be a call to - "cpu_set_irq_line(0, 0, CLEAR_LINE);" in the machine code, when the interrupt line is released by - the hardware (generally in response to an action performed by the interrupt routines). - On tms9995 (9989 ?), you can use PULSE_LINE, too, since the processor latches the line... - - **Note** : HOLD_LINE *NEVER* makes sense on the TMS9900 (or 9980, 9995...). The reason is the - TMS9900 does NOT tell the world it acknoledges an interrupt, so no matter how much hardware you - use, you cannot know when the CPU takes the interrupt, hence you cannot release the line when - the CPU takes the interrupt. Generally, the interrupt condition is cleared by the interrupt - routine (with some CRU or memory access). - - Note that cpu_generate_interrupt uses HOLD_LINE, so your driver interrupt code - should always use the new style, i.e. return "ignore_interrupt(cpustate)" and call - "cpu_set_irq_line(0, 0, ASSERT_LINE);" explicitely. - - Last, many TMS9900-based hardware use a TMS9901 interrupt-handling chip. If anybody wants - to emulate some hardware which uses it, note that I am writing some emulation in the TI99/4(A) - driver in MESS, so you should ask me. -*/ -/* - * HJB 990430: changed to use irq_callback(cpustate) to retrieve the vector - * instead of using 16 irqlines. - * - * R Nabet 990830 : My mistake, I rewrote all these once again ; I think it is now correct. - * A driver using the TMS9900 should do : - * cpu_0_irq_line_vector_w(0, level); - * cpu_set_irq_line(0,0,ASSERT_LINE); - * - * R Nabet 991108 : revised once again, with advice from Juergen Buchmueller, after a discussion - * with Nicola... - * We use the callback to retreive the interrupt level as soon as INTREQ* is asserted. - * As a consequence, I do not support HOLD_LINE normally... However, we do not really have to - * support HOLD_LINE, since no real world TMS9900-based system can support this. - * FYI, there are two alternatives to retreiving the interrupt level with the callback : - * a) using 16 pseudo-IRQ lines. Mostly OK, though it would require a few core changes. - * However, this could cause some problems if someone tried to set two lines simulteanously... - * And TMS9900 did NOT have 16 lines ! This is why Juergen and I did not retain this solution. - * b) modifying the interrupt system in order to provide an extra int to every xxx_set_irq_line - * function. I think this solution would be fine, but it would require quite a number of - * changes in the MAME core. (And I did not feel the courage to check out 4000 drivers and 25 - * cpu cores ;-) .) - * - * Note that this does not apply to tms9995. -*/ -static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) -{ - if (irqline == INPUT_LINE_NMI) - { - cpustate->load_state = state; /* save new state */ - - field_interrupt(cpustate); /* interrupt status changed */ - } - else - { - /*if (cpustate->irq_state == state) - return;*/ - - cpustate->irq_state = state; - - if (state == CLEAR_LINE) - cpustate->irq_level = 16; - /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ - else - cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0); - - field_interrupt(cpustate); /* interrupt state is likely to have changed */ - } -} - -#elif (TMS99XX_MODEL == TMS9980_ID) -/* - interrupt system similar to tms9900, but only 3 interrupt pins (IC0-IC2) -*/ - -static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) -{ - if (state == CLEAR_LINE) - { - cpustate->load_state = 0; - cpustate->irq_state = 0; - cpustate->irq_level = 16; - /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ - } - else - { - int level; - - if (irqline == INPUT_LINE_NMI) - level = 2; /* translate MAME's convention to CPU's representation */ - else - level = (* cpustate->irq_callback)(cpustate->device, 0); - - switch (level) - { - case 0: - case 1: - cpustate->load_state = 0; - cpustate->irq_state = 0; - cpustate->irq_level = 16; - CPU_RESET_NAME(tms99xx)(cpustate->device); - break; - case 2: - cpustate->load_state = 1; - cpustate->irq_state = 0; - cpustate->irq_level = 16; - break; - case 7: - cpustate->load_state = 0; - cpustate->irq_state = 0; - cpustate->irq_level = 16; - break; - default: /* external levels 1, 2, 3, 4 */ - cpustate->load_state = 0; - cpustate->irq_state = 1; - cpustate->irq_level = level - 2; - break; - } - } - - field_interrupt(cpustate); /* interrupt state is likely to have changed */ -} - -#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) -/* - 2 interrupt pins (int1 and int2) -*/ - -static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) -{ - int mask; - - if (irqline == 0) - /* INT1 */ - mask = 1; - else if (irqline == 1) - /* INT2 */ - mask = 4; - else - /* What on earth??? */ - return; - - if (state) - cpustate->irq_state |= mask; - else - cpustate->irq_state &= ~mask; - - field_interrupt(cpustate); /* interrupt state is likely to have changed */ -} - -#elif (TMS99XX_MODEL == TMS9995_ID) -/* - this call-back is called by MESS timer system when the timer reaches 0. -*/ -static TIMER_CALLBACK( decrementer_callback ) -{ - tms99xx_state *cpustate = (tms99xx_state *)ptr; - - /* request decrementer interrupt */ - cpustate->int_latch |= 0x8; - cpustate->flag |= 0x8; - - field_interrupt(cpustate); -} - - -/* - reset and load the timer/decrementer - - Note that I don't know whether toggling flag0/flag1 causes the decrementer to be reloaded or not -*/ -static void reset_decrementer(tms99xx_state *cpustate) -{ - cpustate->timer->adjust(attotime::never); - - /* reload count */ - cpustate->decrementer_count = cpustate->decrementer_interval; - - /* decrementer / timer enabled ? */ - cpustate->decrementer_enabled = ((cpustate->flag & 2) && (cpustate->decrementer_interval)); - - if (cpustate->decrementer_enabled && ! (cpustate->flag & 1)) - { /* timer */ - attotime period = cpustate->device->cycles_to_attotime(cpustate->decrementer_interval * 16L); - cpustate->timer->adjust(period, 0, period); - } -} - -/* - You have two interrupt line : one triggers level-1 interrupts, the other triggers level-4 - interrupts (or decrements the decrementer register). - - According to the hardware, you may use PULSE_LINE (edge-triggered interrupts), or ASSERT_LINE - (level-triggered interrupts). Edge-triggered interrupts are way simpler, but if multiple devices - share the same line, they must use level-triggered interrupts. -*/ -static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) -{ - if (irqline == INPUT_LINE_NMI) - { - cpustate->load_state = state; /* save new state */ - - field_interrupt(cpustate); /* interrupt status changed */ - } - else - { - int mask = (irqline == 0) ? 0x2 : 0x10; - int flag_mask = (irqline == 0) ? 0x4 : 0x10; - - if (((cpustate->int_state & mask) != 0) ^ (state != 0)) - { /* only if state changes */ - if (state) - { - cpustate->int_state |= mask; - - if ((irqline == 1) && (cpustate->flag & 1)) - { /* event counter mode : INT4* triggers no interrupt... */ - if (cpustate->decrementer_enabled) - { /* decrement, then interrupt if reach 0 */ - if ((-- cpustate->decrementer_count) == 0) - { - decrementer_callback(cpustate->device->machine(), cpustate, 0); - cpustate->decrementer_count = cpustate->decrementer_interval; /* reload */ - } - } - } - else - { /* plain interrupt mode */ - cpustate->int_latch |= mask; - cpustate->flag |= flag_mask; - } - } - else - { - cpustate->int_state &= ~ mask; - } - - field_interrupt(cpustate); /* interrupt status changed */ - } - } -} - -#else - -#error "interrupt system not implemented" - -#endif - -/* - * field_interrupt - * - * Determines whether if an interrupt is pending, and sets the relevant flag. - * - * Called when an interrupt pin (LOAD*, INTREQ*, IC0-IC3) is changed, and when the interrupt mask - * is modified. - * - * By using this flag, we save some compares in the execution loop. Subtle, isn't it ;-) ? - * - * R Nabet. - */ -#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) - -static void field_interrupt(tms99xx_state *cpustate) -{ - cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state)); -} - -#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - -static void field_interrupt(tms99xx_state *cpustate) -{ - if (cpustate->irq_state & 1) - cpustate->irq_level = 1; - else if (cpustate->irq_state & 2) - cpustate->irq_level = 2; - else if (cpustate->irq_state & 4) - cpustate->irq_level = 3; - else - cpustate->irq_level = 4; - /* trick : 4 will always be bigger than the IM (0-3), so there will never be interrupts */ - - cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state)); -} - -#elif (TMS99XX_MODEL == TMS9995_ID) - -static void field_interrupt(tms99xx_state *cpustate) -{ - if (cpustate->load_state) - { - cpustate->interrupt_pending = 1; - } - else - { - int current_int; - int level; - - if (cpustate->flag & 1) - /* event counter mode : ignore int4* line... */ - current_int = (cpustate->int_state & ~0x10) | cpustate->int_latch; - else - /* normal behavior */ - current_int = cpustate->int_state | cpustate->int_latch; - - if (current_int) - /* find first bit to 1 */ - /* possible values : 1, 3, 4 */ - for (level=0; ! (current_int & 1); current_int >>= 1, level++) - ; - else - level=16; - - cpustate->irq_level = level; - - cpustate->interrupt_pending = (level <= IMASK); - } -} - -#else - -#error "field_interrupt(cpustate) not written" - -#endif - -static CPU_DISASSEMBLE( tms99xx ) -{ - extern unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const uint8_t *oprom, const uint8_t *opram); - return Dasm9900(buffer, pc, TMS99XX_MODEL, oprom, opram); -} - - -/*****************************************************************************/ -/* - CRU support code - - The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address. - Special instructions are dedicated to reading and writing one or several consecutive bits. - - - - Note that TMS99000 additionally supports parallel CRU operations, although I don't know how - this feature is implemented. -*/ - -enum -{ -#if (TMS99XX_MODEL == TI990_10_ID) - /* 3 MSBs do exist, although they are not connected (don't ask...) */ - CRUAddrBit = 15 -#elif (TMS99XX_MODEL == TMS9900_ID) - /* 3 MSBs are always 0 to support external instructions */ - CRUAddrBit = 12 -#elif (TMS99XX_MODEL == TMS9980_ID) - /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */ - CRUAddrBit = 11 -#elif (TMS99XX_MODEL == TMS9940_ID) - /* 9 internal address lines (8 external) */ - CRUAddrBit = 9 -#elif (TMS99XX_MODEL == TMS9995_ID) - /* no such problem here : data bus lines D0-D2 provide the external instruction code */ - CRUAddrBit = 15 -#else - #warning "I don't know how your processor handles CRU." - CRUAddrBit = 15 -#endif -}; - -enum -{ - rCRUAddrMask = (1 << (CRUAddrBit - 3)) - 1, - wCRUAddrMask = (1 << CRUAddrBit) - 1 -}; - - -#if (TMS99XX_MODEL == TMS9995_ID) - -/* set decrementer mode flag */ -static void set_flag0(tms99xx_state *cpustate, int val) -{ - if (val) - cpustate->flag |= 1; - else - cpustate->flag &= ~ 1; - - reset_decrementer(cpustate); -} - -/* set decrementer enable flag */ -static void set_flag1(tms99xx_state *cpustate, int val) -{ - if (val) - cpustate->flag |= 2; - else - cpustate->flag &= ~ 2; - - reset_decrementer(cpustate); -} - -#endif - -enum cru_error_code -{ - CRU_OK = 0, - CRU_PRIVILEGE_VIOLATION = -1 -}; - -#define WRITEPORT(cs, port, data) (cs)->io->write_byte(port, data) - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) -/* on tms9940, we have to handle internal CRU ports */ -static void write_single_CRU(tms99xx_state *cpustate, int port, int data) -{ - int mask; - - if (! (port & 0x100)) - { - /*if (cpustate->config & CB0)*/ - /* External CRU */ - WRITEPORT(cpustate, port, (data & 0x01)); - } - else - { - /* internal CRU */ - switch ((port >> 4) & 0xf) - { - case 0x8: - if (port == 0x181) - { - /* clear decrementer interrupt */ - cpustate->irq_state &= ~2; - } - if (port >= 0x183) && (port <= 0x186) - { - /* write configuration register */ - mask = 1 << (port - 0x183); - /* ... */ - } - break; - - case 0x9: - if (port <= 0x19D) - { - /* write decrementer latch */ - mask = 1 << (port - 0x190); - /* ... */ - } - else if (port == 0x19E) - { - /* set decrementer as timer (1) or event counter (0) */ - /* ... */ - } - break; - - case 0xA: - /* multiprocessor system interface */ - mask = 1 << (port - 0x1A0); - /* ... */ - break; - - case 0xB: - /* flags */ - mask = 1 << (port - 0x1B0); - /* ... */ - break; - - case 0xC: - case 0xD: - /* direction for P0-P31 */ - mask = 1 << (port - 0x1C0); - /* ... */ - break; - - case 0xE: - case 0xF: - /* data for P0-P31 */ - mask = 1 << (port - 0x1E0); - /* ... */ - break; - } - } -} -#elif (TMS99XX_MODEL == TMS9995_ID) -/* on tms9995, we have to handle internal CRU ports */ -static void write_single_CRU(tms99xx_state *cpustate, int port, int data) -{ - /* Internal CRU */ - switch (port) - { - case 0xF70: - set_flag0(cpustate, data & 0x01); - break; - case 0xF71: - set_flag1(cpustate, data & 0x01); - break; - case 0xF72: - case 0xF73: - case 0xF74: - break; /* ignored */ - case 0xF75: - case 0xF76: - case 0xF77: - case 0xF78: - case 0xF79: - case 0xF7A: - case 0xF7B: - case 0xF7C: - case 0xF7D: - case 0xF7E: - case 0xF7F: - { /* user defined flags */ - int mask = 1 << (port - 0xF70); - if (data & 0x01) - cpustate->flag |= mask; - else - cpustate->flag &= ~ mask; - } - break; - - case 0x0FED: - /* MID flag */ - cpustate->MID_flag = data & 0x01; - break; - } - /* External CRU */ - /* Even though all the registers above are implemented internally, accesses - are passed to the external bus, too, and an external device might respond - to a write to these CRU address as well (particularly a write to the user - flag registers). */ - WRITEPORT(cpustate, port, (data & 0x01)); -} -#else -#define write_single_CRU(cs, port, data) WRITEPORT(cs, port, data) -#endif - -/* - performs a normal write to CRU bus (used by SBZ, SBO, LDCR : address range 0 -> 0xFFF) -*/ -static cru_error_code writeCRU(tms99xx_state *cpustate, int CRUAddr, int Number, uint16_t Value) -{ - int count; - - /*logerror("PC %4.4x Write CRU %x for %x =%x\n",cpustate->PC,CRUAddr,Number,Value);*/ - - CRUAddr &= wCRUAddrMask; - - /* Write Number bits from CRUAddr */ - - for(count=0; count<Number; count++) - { - #if HAS_PRIVILEGE - if ((cpustate->STATUS & ST_PR) && (CRUAddr >= 0xE00)) - return CRU_PRIVILEGE_VIOLATION; - #endif - - write_single_CRU(cpustate, CRUAddr, (Value & 0x01)); - Value >>= 1; - CRUAddr = (CRUAddr + 1) & wCRUAddrMask; - } - - return CRU_OK; -} - -#if EXTERNAL_INSTRUCTION_DECODING -/* - Some opcodes perform a dummy write to a special CRU address, so that an external function may be - triggered. - - Only the first 3 MSBs of the address matter : other address bits and the written value itself - are undefined. - - How should we support this ? With callback functions ? Actually, as long as we do not support - hardware which makes use of this feature, it does not really matter :-) . -*/ -static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID) -{ -#if 1 - /* I guess we can support this like normal CRU operations */ -#if (TMS99XX_MODEL == TMS9900_ID) - WRITEPORT(cpustate, ext_op_ID << 12, 0); /* or is it 1 ??? */ -#elif (TMS99XX_MODEL == TMS9980_ID) - WRITEPORT(cpustate, (ext_op_ID & 3) << 11, (ext_op_ID & 4) ? 1 : 0); -#elif (TMS99XX_MODEL == TMS9995_ID) - WRITEPORT(cpustate, ext_op_ID << 15, 0); /* or is it 1 ??? */ -#else - #warning "I don't know how your processor handles external opcodes (maybe you don't need them, though)." -#endif - -#else - switch (ext_op_ID) - { - case 2: /* IDLE */ - - break; - case 3: /* RSET */ - - break; - case 5: /* CKON */ - - break; - case 6: /* CKOF */ - - break; - case 7: /* LREX */ - - break; - case 0: - /* normal CRU write !!! */ - logerror("PC %4.4x : external_instruction_notify : wrong ext_op_ID",cpustate->PC); - break; - default: - /* unknown address */ - logerror("PC %4.4x : external_instruction_notify : unknown ext_op_ID",cpustate->PC); - break; - } -#endif -} -#endif - -/* - performs a normal read to CRU bus (used by TB, STCR : address range 0->0xFFF) - - Note that on some hardware, e.g. TI99/4(a), all normal memory operations cause unwanted CRU - read at the same address. This seems to be impossible to emulate efficiently, so, if you need - to emulate this, you're in trouble. -*/ -#define READPORT(cs, port) (cs)->io->read_byte(port) - - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) -/* on tms9940, we have to handle internal CRU ports */ -static int read_single_CRU(tms99xx_state *cpustate, int port) -{ - int reply; - int shift; - - if (! (port & 0x20)) - { - /*if (cpustate->config & CB0)*/ - /* External CRU */ - reply = READPORT(cpustate, port, (data & 0x01)); - } - else - { - /* internal CRU */ - switch (port) - { - case 0x10: - /* read interrupt state */ - reply = cpustate->irq_state; - break; - - case 0x12: - /* read decrementer LSB */ - /* ... */ - break; - case 0x13: - /* read decrementer MSB */ - /* ... */ - break; - - case 0x14: - /* read multiprocessor system interface LSB */ - /* ... */ - break; - case 0x15: - /* read multiprocessor system interface MSB */ - /* ... */ - break; - - case 0x16: - /* read flags LSB */ - /* ... */ - break; - case 0x17: - /* read flags MSB */ - /* ... */ - break; - - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - /* direction for P0-P31 */ - shift = (port - 0x18) << 3; - /* ... */ - break; - - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - /* data for P0-P31 */ - shift = (port - 0x1C) << 3; - /* ... */ - break; - - default: - reply = 0; - break; - } - } - - return reply; -} -#elif (TMS99XX_MODEL == TMS9995_ID) -/* on tms9995, we have to handle internal CRU ports */ -static int read_single_CRU(tms99xx_state *cpustate, int port) -{ - switch (port) - { - case 0x1EE: - /* flag, bits 0-7 */ - return cpustate->flag & 0xFF; - case 0x1EF: - /* flag, bits 8-15 */ - return (cpustate->flag >> 8) & 0xFF; - case 0x1FD: - /* MID flag, and external devices */ - if (cpustate->MID_flag) - return READPORT(cpustate, port) | 0x10; - else - return READPORT(cpustate, port) & ~ 0x10; - default: - /* external devices */ - return READPORT(cpustate, port); - } -} -#else -#define read_single_CRU(cs, port) READPORT(cs, port) -#endif - -static int readCRU(tms99xx_state *cpustate, int CRUAddr, int Number) -{ - static const int BitMask[] = - { - 0, /* filler - saves a subtract to find mask */ - 0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF, - 0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF - }; - - int Offset,Location,Value; - - /*logerror("Read CRU %x for %x\n",CRUAddr,Number);*/ - - Location = (CRUAddr >> 3) & rCRUAddrMask; - Offset = CRUAddr & 07; - - /* Read 8 bits */ - #if HAS_PRIVILEGE - if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) - return CRU_PRIVILEGE_VIOLATION; - #endif - Value = read_single_CRU(cpustate, Location); - - if ((Offset+Number) > 8) - { - /* Read next 8 bits */ - Location = (Location + 1) & rCRUAddrMask; - #if HAS_PRIVILEGE - if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) - return CRU_PRIVILEGE_VIOLATION; - #endif - Value |= read_single_CRU(cpustate, Location) << 8; - - if ((Offset+Number) > 16) - { - /* Read next 8 bits */ - Location = (Location + 1) & rCRUAddrMask; - #if HAS_PRIVILEGE - if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) - return CRU_PRIVILEGE_VIOLATION; - #endif - Value |= read_single_CRU(cpustate, Location) << 16; - } - } - - /* Allow for Offset */ - Value >>= Offset; - - /* Mask out what we want */ - Value &= BitMask[Number]; - - /* And update */ - return Value; -} - -/*****************************************************************************/ - -#if HAS_MAPPING -/* load a map file from memory */ -static void load_map_file(tms99xx_state *cpustate, uint16_t src_addr, int src_map_file, int dst_file) -{ - int i; - - - /* load mapped address into the memory address register */ - if ((src_map_file == 0) && (src_addr >= 0xf800)) - { /* intercept TPCS and CPU ROM */ - if (src_addr < 0xfc00) - /* TPCS */ - cpustate->mapper_address_latch = 0x1f0000+src_addr; - else - /* CPU ROM */ - cpustate->mapper_address_latch = 0x1f0000+src_addr; /* hack... */ - } - else if (! cpustate->mapping_on) - { - cpustate->mapper_address_latch = src_addr; - } - else - { - int map_index; - - if (src_addr <= cpustate->map_files[src_map_file].limit[0]) - map_index = 0; - else if (src_addr <= cpustate->map_files[src_map_file].limit[1]) - map_index = 1; - else if (src_addr <= cpustate->map_files[src_map_file].limit[2]) - map_index = 2; - else - { - if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) - { - cpustate->error_interrupt_register |= EIR_MAPERR; - cpustate->write_inhibit = 1; - } - cpustate->mapper_address_latch = src_addr; - map_index = -1; - } - if (map_index != -1) - cpustate->mapper_address_latch = cpustate->map_files[src_map_file].bias[map_index]+src_addr; - } - - - for (i=0; i<3; i++) - { - cpustate->map_files[dst_file].L[i] = cpustate->program->read_word(cpustate->mapper_address_latch) & 0xffe0; - cpustate->map_files[dst_file].limit[i] = (cpustate->map_files[dst_file].L[i] ^ 0xffe0) | 0x001f; - cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff; - cpustate->map_files[dst_file].B[i] = cpustate->program->read_word(cpustate->mapper_address_latch); - cpustate->map_files[dst_file].bias[i] = ((unsigned int) cpustate->map_files[dst_file].B[i]) << 5; - cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff; - } -} -#endif - -/* contextswitch : performs a BLWP, i.e. load PC, WP, and save old PC, old WP and ST... */ -static void contextswitch(tms99xx_state *cpustate, uint16_t addr) -{ - uint16_t oldWP, oldpc; - - /* save old state */ - oldWP = cpustate->WP; - oldpc = cpustate->PC; - - /* load vector */ - cpustate->WP = readword(cpustate, addr) & ~1; - cpustate->PC = readword(cpustate, addr+2) & ~1; - - /* write old state to regs */ - WRITEREG(R13, oldWP); - WRITEREG(R14, oldpc); - setstat(cpustate); - WRITEREG(R15, cpustate->STATUS); -} - -#if HAS_MAPPING || HAS_PRIVILEGE - -/* privileged context switch, that occurs after a reset, interrupt or XOP: -we enter privileged mode and select map file 0 before doing the context switch */ -/* For CPU that have no privilege support, contextswitchX would behave -identically to contextswitch, so we can call contextswitch in all cases. */ -static void contextswitchX(tms99xx_state *cpustate, uint16_t addr) -{ - uint16_t oldWP, oldpc, oldST; - - /* save old state */ - oldWP = cpustate->WP; - oldpc = cpustate->PC; - setstat(cpustate); - oldST = cpustate->STATUS; - - /* enter privileged mode and select map file 0 */ - #if HAS_PRIVILEGE - cpustate->STATUS &= ~ ST_PR; - #endif - #if HAS_MAPPING - cpustate->STATUS &= ~ ST_MF; - #endif - getstat(cpustate); - - /* load vector */ - cpustate->WP = readword(cpustate, addr) & ~1; - cpustate->PC = readword(cpustate, addr+2) & ~1; - - /* write old state to regs */ - WRITEREG(R13, oldWP); - WRITEREG(R14, oldpc); - WRITEREG(R15, oldST); -} - -#endif - -/* - * decipheraddr : compute and return the effective address in word instructions. - * - * NOTA : the LSBit is always ignored in word addresses, - * but we do not set it to 0 because of XOP... - */ -static uint16_t decipheraddr(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t ts = opcode & 0x30; - register uint16_t reg = opcode & 0xF; - - reg += reg; - - if (ts == 0) - /* Rx */ - return(reg + cpustate->WP); - else if (ts == 0x10) - { /* *Rx */ - CYCLES(0, 4, 1); - return(readword(cpustate, reg + cpustate->WP)); - } - else if (ts == 0x20) - { - register uint16_t imm; - - imm = fetch(cpustate); - - if (reg) - { /* @>xxxx(Rx) */ - CYCLES(1, 8, 3); - return(readword(cpustate, reg + cpustate->WP) + imm); - } - else - { /* @>xxxx */ - CYCLES(3, 8, 1); - return(imm); - } - } - else /*if (ts == 0x30)*/ - { /* *Rx+ */ - register uint16_t response; - - reg += cpustate->WP; /* reg now contains effective address */ - - CYCLES(1, 8, 3); - - response = readword(cpustate, reg); - writeword(cpustate, reg, response+2); /* we increment register content */ - return(response); - } -} - -/* decipheraddrbyte : compute and return the effective address in byte instructions. */ -static uint16_t decipheraddrbyte(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t ts = opcode & 0x30; - register uint16_t reg = opcode & 0xF; - - reg += reg; - - if (ts == 0) - /* Rx */ - return(reg + cpustate->WP); - else if (ts == 0x10) - { /* *Rx */ - CYCLES(0, 4, 1); - return(readword(cpustate, reg + cpustate->WP)); - } - else if (ts == 0x20) - { - register uint16_t imm; - - imm = fetch(cpustate); - - if (reg) - { /* @>xxxx(Rx) */ - CYCLES(1, 8, 3); - return(readword(cpustate, reg + cpustate->WP) + imm); - } - else - { /* @>xxxx */ - CYCLES(3, 8, 1); - return(imm); - } - } - else /*if (ts == 0x30)*/ - { /* *Rx+ */ - register uint16_t response; - - reg += cpustate->WP; /* reg now contains effective address */ - - CYCLES(1, 6, 3); - - response = readword(cpustate, reg); - writeword(cpustate, reg, response+1); /* we increment register content */ - return(response); - } -} - - -/*************************************************************************/ - -#if (TMS99XX_MODEL == TI990_10_ID) - /* TI990/10 generates an error interrupt */ - /* timings are unknown */ - #define HANDLE_ILLEGAL \ - { \ - cpustate->error_interrupt_register |= EIR_ILLOP; \ - if (cpustate->error_interrupt_callback) \ - (*cpustate->error_interrupt_callback)(cpustate->device, 1); \ - } -#elif TMS99XX_MODEL <= TMS9989_ID - /* TMS9900/TMS9980 merely ignore the instruction */ - #define HANDLE_ILLEGAL cpustate->icount -= 6 -#elif TMS99XX_MODEL == TMS9995_ID - /* TMS9995 generates a MID interrupt */ - #define HANDLE_ILLEGAL \ - { \ - cpustate->MID_flag = 1; \ - contextswitchX(cpustate, 0x0008); \ - cpustate->STATUS = (cpustate->STATUS & 0xFE00) | 0x1; \ - cpustate->disable_interrupt_recognition = 1; \ - } -#else -#define HANDLE_ILLEGAL -#warning "don't know" -#endif - -#if HAS_PRIVILEGE - #if (TMS99XX_MODEL == TI990_10_ID) - /* TI990/10 generates an error interrupt */ - /* timings are unknown */ - #define HANDLE_PRIVILEGE_VIOLATION \ - { \ - cpustate->error_interrupt_register |= EIR_PRIVOP; \ - if (cpustate->error_interrupt_callback) \ - (*cpustate->error_interrupt_callback)(cpustate->device, 1); \ - } - #else - #define HANDLE_PRIVILEGE_VIOLATION - #warning "don't know" - #endif -#endif - -/*========================================================================== - Illegal instructions >0000->01FF (not for 9989 and later) - >0C00->0FFF (not for 990/12 and 99110) -============================================================================*/ - -static void illegal(tms99xx_state *cpustate, uint16_t opcode) -{ - HANDLE_ILLEGAL; -} - - -#if 0 /* ti990/12 only */ -/*========================================================================== - Additionnal instructions, >0000->002F - Additionnal single-register instruction, >0030->003F - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | - | o p c o d e | reg # | - --------------------------------- - -============================================================================*/ -static void h0000(tms99xx_state *cpustate, uint16_t opcode) -{ - if (opcode >= 0x30) - { /* STPC STore Program Counter */ - - } - else - { - switch (opcode /*& 0x3F*/) - { - case 0x1C: /* SRAM */ - /* SRAM -- Shift Right Arithmetic Multiple precision */ - case 0x1D: /* SLAM */ - /* SLAM -- Shift Left Arithmetic Multiple precision */ - case 0x1E: - /* RTO --- Right Test for Ones */ - case 0x1F: - /* LTO --- Left Test for Ones */ - case 0x20: - /* CNTO -- CouNT Ones */ - case 0x21: - /* SLSL -- Search LiSt Logical address */ - case 0x22: - /* SLSP -- Search LiSt Physical address */ - case 0x23: - /* BDC --- Binary to Decimal ascii Conversion */ - case 0x24: - /* DBC --- Decimal to Binary ascii Conversion */ - case 0x25: - /* SWPM -- SWaP Multiple precision */ - case 0x26: - /* XORM -- eXclusive OR Multiple precision */ - case 0x27: - /* ORM --- OR Multiple precision */ - case 0x28: - /* ANDM -- AND Multiple precision */ - case 0x29: /* SM */ - /* SM ---- Subtract Multiple precision integer */ - case 0x2A: /* AM */ - /* AM ---- Add Multiple precision integer */ - case 0x2B: - /* MOVA -- MOVe Address */ - case 0x2D: - /* EMD --- Execute Micro-Diagnostics */ - case 0x2E: - /* EINT -- Enable INTerrupts */ - case 0x2F: - /* DINT -- Disable INTerrupts */ - - break; - - default: - HANDLE_ILLEGAL; - break; - } - } -} -#endif - - -#if HAS_9995_OPCODES -/*========================================================================== - Additionnal single-register instructions, >0040->00FF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | reg # | - --------------------------------- - -tms9989 and later : LST, LWP -============================================================================*/ -static void h0040(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t addr; - - addr = opcode & 0xF; - addr = ((addr + addr) + cpustate->WP) & ~1; - - switch ((opcode & 0xF0) >> 4) - { - case 8: /* LST */ - /* LST --- Load STatus register */ - /* ST = *Reg */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20); - else - cpustate->STATUS = readword(cpustate, addr); - #else - cpustate->STATUS = readword(cpustate, addr); - #endif - getstat(cpustate); /* set last_parity */ - break; - - case 9: /* LWP */ - /* LWP --- Load Workspace Pointer */ - /* WP = *Reg */ - cpustate->WP = readword(cpustate, addr) & ~1; - break; - -#if 0 /* 990/12 opcodes */ - case 4: - /* CS ---- Compare Strings */ - case 5: - /* SEQB -- Search string for EQual Byte */ - case 6: - /* MOVS -- MOVe String */ - case 7: - /* LIM --- Load Interrupt Mask */ - - case 10: - /* LCS --- Load writable Control Store */ - - case 11: /* BLSK */ - /* BLSK -- Branch immediate and push Link to StacK */ - - case 12: - /* MVSR -- MoVe String Reverse */ - case 13: - /* MVSK -- MoVe string from StacK */ - case 14: - /* POPS -- POP String from stack */ - case 15: - /* PSHS -- PuSH String to stack */ - - break; -#endif - - default: - HANDLE_ILLEGAL; - break; - } -} - - -/*========================================================================== - Additionnal single-operand instructions, >0100->01FF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e |TS | S | - --------------------------------- - -tms9989 and later : DIVS, MPYS -tms99xxx : BIND -============================================================================*/ -static void h0100(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t src; -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; -#endif - - src = decipheraddr(cpustate, opcode) & ~1; - - switch ((opcode & 0xC0) >> 6) - { -#if HAS_BIND_OPCODE - case 1: /* BIND */ - /* BIND -- Branch INDirect */ - cpustate->PC = readwordX(cpustate, src, src_map) & ~1; - CYCLES(Mooof!, Mooof!, 4 /*don't know*/); - break; -#endif - - case 2: /* DIVS */ - /* DIVS -- DIVide Signed */ - /* R0 = (R0:R1)/S R1 = (R0:R1)%S */ - { - int16_t d = readwordX(cpustate, src, src_map); - int32_t divq = (READREG(R0) << 16) | READREG(R1); - int32_t q = divq/d; - - if ((q < -32768L) || (q > 32767L)) - { - cpustate->STATUS |= ST_OV; - CYCLES(Mooof!, Mooof!, 10); - } - else - { - cpustate->STATUS &= ~ST_OV; - setst_lae(cpustate, q); - WRITEREG(R0, q); - WRITEREG(R1, divq%d); - /* tms9995 : 33 is the worst case */ - CYCLES(Mooof!, Mooof!, 33); - } - } - break; - - case 3: /* MPYS */ - /* MPYS -- MultiPlY Signed */ - /* Results: R0:R1 = R0*S */ - { - int32_t prod = ((int32_t) (int16_t) readwordX(cpustate, src, src_map)); - prod = prod*((int32_t) (int16_t) READREG(R0)); - - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); - if (prod > 0) - cpustate->STATUS |= (ST_LGT | ST_AGT); - else if (prod < 0) - cpustate->STATUS |= ST_LGT; - else - cpustate->STATUS |= ST_EQ; - - WRITEREG(R0, prod >> 16); - WRITEREG(R1, prod); - } - CYCLES(Mooof!, Mooof!, 25); - break; - -#if 0 /* Origin unknown */ - case 0: /* EVAD */ - /* EVAD -- EValuate ADdress instruction */ - - break; -#endif - - default: - HANDLE_ILLEGAL; - break; - } -} -#endif - - -/*========================================================================== - Immediate, Control instructions, >0200->03FF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e |0| reg # | - --------------------------------- - - LI, AI, ANDI, ORI, CI, STWP, STST, LIMI, LWPI, IDLE, RSET, RTWP, CKON, CKOF, LREX -systems with memory mapper: LMF -============================================================================*/ -static void h0200(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t addr; - register uint16_t value; /* used for anything */ - - addr = opcode & 0xF; - addr = ((addr + addr) + cpustate->WP) & ~1; - - #if HAS_MAPPING - if ((opcode >= 0x0320) && (opcode < 0x0340)) - { /* LMF */ - /* LMF --- Load memory Map File */ - /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610 - mapper chip to be associated with tms99000. - Syntax: "LMF Rn,m" loads map file m (0 or 1) with six words of memory, starting at address - specified in workspace register Rn (0 through 15). */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - return; - } - #endif - - /* read address pointer */ - addr = readword(cpustate, addr); - - load_map_file(cpustate, addr, cpustate->cur_map, (opcode & 0x10) ? 1 : 0); - - CYCLES(3, Mooof!, Mooof!); - return; - } - #endif - - #if BETTER_0200_DECODING - /* better instruction decoding on ti990/10 */ - if (opcode & 0x10) - { - HANDLE_ILLEGAL; - return; - } - #elif COMPLETE_0200_DECODING - /* full instruction decoding on tms9995 */ - if (((opcode < 0x2E0) && (opcode & 0x10)) || ((opcode >= 0x2E0) && (opcode & 0x1F))) - { -#if 0 - /* tms99110 opcode (not supported by 990/12) */ - if (opcode == 0x0301) - { /* CR ---- Compare Reals */ - } - else - /* tms99105+tms99110 opcode (not supported by 990/12) */ - if (opcode == 0x0302) - { /* MM ---- Multiply Multiple */ - } - else -#endif - #if 0 /* ti990/12 only */ - if (opcode >= 0x03F0) - { /* EP ---- Extended Precision */ - } - else - #endif - HANDLE_ILLEGAL; - return; - } - #endif - - switch ((opcode & 0x1e0) >> 5) - { - case 0: /* LI */ - /* LI ---- Load Immediate */ - /* *Reg = *PC+ */ - value = fetch(cpustate); - writeword(cpustate, addr, value); - setst_lae(cpustate, value); - CYCLES(3, 12, 3); - break; - - case 1: /* AI */ - /* AI ---- Add Immediate */ - /* *Reg += *PC+ */ - value = fetch(cpustate); - value = setst_add_laeco(cpustate, readword(cpustate, addr), value); - writeword(cpustate, addr, value); - CYCLES(4, 14, 4); - break; - - case 2: /* ANDI */ - /* ANDI -- AND Immediate */ - /* *Reg &= *PC+ */ - value = fetch(cpustate); - value = readword(cpustate, addr) & value; - writeword(cpustate, addr, value); - setst_lae(cpustate, value); - CYCLES(4, 14, 4); - break; - - case 3: /* ORI */ - /* ORI --- OR Immediate */ - /* *Reg |= *PC+ */ - value = fetch(cpustate); - value = readword(cpustate, addr) | value; - writeword(cpustate, addr, value); - setst_lae(cpustate, value); - CYCLES(4, 14, 4); - break; - - case 4: /* CI */ - /* CI ---- Compare Immediate */ - /* status = (*Reg-*PC+) */ - value = fetch(cpustate); - setst_c_lae(cpustate, value, readword(cpustate, addr)); - CYCLES(6, 14, 4); - break; - - case 5: /* STWP */ - /* STWP -- STore Workspace Pointer */ - /* *Reg = WP */ - writeword(cpustate, addr, cpustate->WP); - CYCLES(2, 8, 3); - break; - - case 6: /* STST */ - /* STST -- STore STatus register */ - /* *Reg = ST */ - setstat(cpustate); - writeword(cpustate, addr, cpustate->STATUS); - CYCLES(2, 8, 3); - break; - - case 7: /* LWPI */ - /* LWPI -- Load Workspace Pointer Immediate */ - /* WP = *PC+ */ - cpustate->WP = fetch(cpustate) & ~1; - CYCLES(3, 10, 4); - break; - - case 8: /* LIMI */ - /* LIMI -- Load Interrupt Mask Immediate */ - /* ST&15 |= (*PC+)&15 */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - value = fetch(cpustate); - cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (value & ST_IM); - field_interrupt(cpustate); /*IM has been modified.*/ - CYCLES(3, 16, 5); - break; - - case 9: /* LMF is implemented elsewhere - when it is implemented */ - HANDLE_ILLEGAL; - break; - - case 10: /* IDLE */ - /* IDLE -- IDLE until a reset, interrupt, load */ - /* The TMS99000 locks until an interrupt happen (like with 68k STOP instruction), - and continuously performs a special CRU write (code 2). */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - cpustate->IDLE = 1; - #if EXTERNAL_INSTRUCTION_DECODING - external_instruction_notify(cpustate, 2); - #endif - if (cpustate->idle_callback) - (*cpustate->idle_callback)(cpustate->device, 1); - CYCLES(4, 12, 7); - /* we take care of further external_instruction_notify(cpustate, 2); in execute(cpustate) */ - break; - - case 12: /* RTWP */ - /* RTWP -- Return with Workspace Pointer */ - /* WP = R13, PC = R14, ST = R15 */ - addr = (cpustate->WP + R13) & ~1; - cpustate->WP = readword(cpustate, addr) & ~1; - addr += 2; - cpustate->PC = readword(cpustate, addr) & ~1; - addr += 2; - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20); - else - cpustate->STATUS = readword(cpustate, addr); - #else - cpustate->STATUS = readword(cpustate, addr); - #endif - getstat(cpustate); /* set last_parity */ - - field_interrupt(cpustate); /*IM has been modified.*/ - CYCLES(3, 14, 6); - break; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - - case 11: /* RSET */ - case 13: /* CKON */ - case 14: /* CKOF */ - case 15: /* LREX */ - HANDLE_ILLEGAL; /* These instruction "have been deleted" on the TMS9940 */ - break; - -#else - - case 11: /* RSET */ - /* RSET -- ReSET */ - /* Reset the Interrupt Mask, and perform a special CRU write (code 3). */ - /* The CRU write is supposed to reset external devices. */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - cpustate->STATUS &= 0xFFF0; /*clear IM.*/ - field_interrupt(cpustate); /*IM has been modified.*/ - - #if (TMS99XX_MODEL == TMS9995_ID) - /*cpustate->MID_flag = 0;*/ /* not sure about this */ - #endif - #if (TMS99XX_MODEL == TI990_10_ID) - cpustate->error_interrupt_register = 0; - cpustate->mapping_on = 0; - - cpustate->reset_maperr = 0; - cpustate->mapper_cru_read_register = 0; - cpustate->latch_control[0] = cpustate->latch_control[1] = cpustate->latch_control[2] = 0; - - cpustate->diaglat = 0; - #endif - - #if EXTERNAL_INSTRUCTION_DECODING - external_instruction_notify(cpustate, 3); - #endif - - #if EXTERNAL_INSTRUCTION_CALLBACK - if (cpustate->rset_callback) - (*cpustate->rset_callback)(cpustate->device); - #endif - - CYCLES(5, 12, 7); - break; - -#if EXTERNAL_INSTRUCTION_DECODING - - case 13: /* CKON */ - case 14: /* CKOF */ - case 15: /* LREX */ - /* CKON -- ClocK ON */ - /* Perform a special CRU write (code 5). */ - /* An external circuitery could, for instance, enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */ - /* CKOF -- ClocK OFf */ - /* Perform a special CRU write (code 6). */ - /* An external circuitery could, for instance, disable the line clock interrupt. */ - /* LREX -- Load or REstart eXecution */ - /* Perform a special CRU write (code 7). */ - /* An external circuitery could, for instance, activate the LOAD* line, - causing a non-maskable LOAD interrupt (vector -1). */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - external_instruction_notify(cpustate, (opcode & 0x00e0) >> 5); - - #if EXTERNAL_INSTRUCTION_CALLBACK - #warning "todo..." - #endif - - CYCLES(Mooof!, 12, 7); - break; - -#elif EXTERNAL_INSTRUCTION_CALLBACK - - case 13: /* CKON */ - case 14: /* CKOF */ - /* CKON -- ClocK ON */ - /* Enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */ - /* CKOF -- ClocK OFf */ - /* Disable the line clock interrupt. */ - /* We use a callback because the line clock is implemented in machine - code, not in the CPU core. */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - if (cpustate->ckon_ckof_callback) - (*cpustate->ckon_ckof_callback)(cpustate->device, (opcode & 0x0020) ? 1 : 0); - - - CYCLES(5, Mooof!, Mooof!); - break; - - case 15: /* LREX */ - /* LREX -- Load or REstart eXecution */ - /* Trigger a LOAD interrupt (vector -1). (We use a callback, and I - have forgotten the reason why.) */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - if (cpustate->lrex_callback) - (*cpustate->lrex_callback)(cpustate->device); - - CYCLES(6, Mooof!, Mooof!); - break; - -#else - - #warning "Should not happen..." - -#endif - -#endif - } -} - - -/*========================================================================== - Single-operand instructions, >0400->07FF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e |TS | S | - --------------------------------- - - BLWP, B, X, CLR, NEG, INV, INC, INCT, DEC, DECT, BL, SWPB, SETO, ABS -systems with memory mapper: LDD, LDS -============================================================================*/ -static void h0400(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t addr = decipheraddr(cpustate, opcode) & ~1; - register uint16_t value; /* used for anything */ -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; -#endif - - switch ((opcode & 0x3C0) >> 6) - { - case 0: /* BLWP */ - /* BLWP -- Branch and Link with Workspace Pointer */ - /* Result: WP = *S+, PC = *S */ - /* New R13=old WP, New R14=Old PC, New R15=Old ST */ - contextswitch(cpustate, addr); - CYCLES(3, 26, 11); - cpustate->disable_interrupt_recognition = 1; - break; - case 1: /* B */ - /* B ----- Branch */ - /* PC = S */ -#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) - (void) readwordX(cpustate, addr, src_map); -#endif - cpustate->PC = addr; - CYCLES(2, 8, 3); - break; - case 2: /* X */ - /* X ----- eXecute */ - /* Executes instruction *S */ - execute(cpustate, readwordX(cpustate, addr, src_map)); - /* On tms9900, the X instruction actually takes 8 cycles, but we gain 2 cycles on the next - instruction, as we don't need to fetch it. */ - CYCLES(1, 6, 2); - break; - case 3: /* CLR */ - /* CLR --- CLeaR */ - /* *S = 0 */ -#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) - (void) readwordX(cpustate, addr, src_map); -#endif - writewordX(cpustate, addr, 0, src_map); - CYCLES(2, 10, 3); - break; - case 4: /* NEG */ - /* NEG --- NEGate */ - /* *S = -*S */ - value = - (int16_t) readwordX(cpustate, addr, src_map); - if (value) - cpustate->STATUS &= ~ ST_C; - else - cpustate->STATUS |= ST_C; - - #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (value & 0x0FFF) - cpustate->STATUS &= ~ ST_DC; - else - cpustate->STATUS |= ST_DC; - #endif - - setst_laeo(cpustate, value); - writewordX(cpustate, addr, value, src_map); - CYCLES(3, 12, 3); - break; - case 5: /* INV */ - /* INV --- INVert */ - /* *S = ~*S */ - value = ~ readwordX(cpustate, addr, src_map); - writewordX(cpustate, addr, value, src_map); - setst_lae(cpustate, value); - CYCLES(2, 10, 3); - break; - case 6: /* INC */ - /* INC --- INCrement */ - /* (*S)++ */ - value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 1); - writewordX(cpustate, addr, value, src_map); - CYCLES(2, 10, 3); - break; - case 7: /* INCT */ - /* INCT -- INCrement by Two */ - /* (*S) +=2 */ - value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 2); - writewordX(cpustate, addr, value, src_map); - CYCLES(2, 10, 3); - break; - case 8: /* DEC */ - /* DEC --- DECrement */ - /* (*S)-- */ - value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 1); - writewordX(cpustate, addr, value, src_map); - CYCLES(2, 10, 3); - break; - case 9: /* DECT */ - /* DECT -- DECrement by Two */ - /* (*S) -= 2 */ - value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 2); - writewordX(cpustate, addr, value, src_map); - CYCLES(2, 10, 3); - break; - case 10: /* BL */ - /* BL ---- Branch and Link */ - /* IP=S, R11=old IP */ -#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) - (void) readwordX(cpustate, addr, src_map); -#endif - WRITEREG(R11, cpustate->PC); - cpustate->PC = addr; - CYCLES(3, 12, 5); - break; - case 11: /* SWPB */ - /* SWPB -- SWaP Bytes */ - /* *S = swab(*S) */ - value = readwordX(cpustate, addr, src_map); - value = logical_right_shift(value, 8) | (value << 8); - writewordX(cpustate, addr, value, src_map); - CYCLES(2, 10, 13); - break; - case 12: /* SETO */ - /* SETO -- SET to Ones */ - /* *S = #$FFFF */ -#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) - (void) readwordX(cpustate, addr, src_map); -#endif - writewordX(cpustate, addr, 0xFFFF, src_map); - CYCLES(2, 10, 3); - break; - case 13: /* ABS */ - /* ABS --- ABSolute value */ - /* *S = |*S| */ - /* clearing ST_C seems to be necessary, although ABS will never set it. */ -#if (TMS99XX_MODEL <= TMS9985_ID) - - /* ti990/10 and tms9900/tms9980 only write the result if it has changed */ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); - - #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - /* I guess ST_DC is cleared here, too*/ - cpustate->STATUS &= ~ ST_DC; - #endif - - value = readwordX(cpustate, addr, src_map); - - CYCLES(5, 12, Mooof!); - - if (((int16_t) value) > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (((int16_t) value) < 0) - { - cpustate->STATUS |= ST_LGT; - if (value == 0x8000) - cpustate->STATUS |= ST_OV; - - #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - if (! (value & 0x0FFF)) - cpustate->STATUS |= ST_DC; - #endif - - writewordX(cpustate, addr, - ((int16_t) value), src_map); - CYCLES(0, 2, Mooof!); - } - else - cpustate->STATUS |= ST_EQ; - - break; - -#else - - /* tms9995 always write the result */ - cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); - value = readwordX(cpustate, addr, src_map); - - CYCLES(Mooof!, Mooof!, 3); - if (((int16_t) value) > 0) - cpustate->STATUS |= ST_LGT | ST_AGT; - else if (((int16_t) value) < 0) - { - cpustate->STATUS |= ST_LGT; - if (value == 0x8000) - cpustate->STATUS |= ST_OV; - value = - ((int16_t) value); - } - else - cpustate->STATUS |= ST_EQ; - - writewordX(cpustate, addr, value, src_map); - - break; - -#endif - - -#if HAS_MAPPING - /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610 - mapper chip to be associated with tms99000. */ - /* These opcode allow access to another page without the need of switching a page someplace. */ - /* Note that, if I read the 990/10 schematics correctly, two consecutive LDS or LDD would - cause some trouble. */ - case 14: /* LDS */ - /* LDS --- Long Distance Source */ - - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - load_map_file(cpustate, addr, src_map, 2); - cpustate->lds_flag = 1; - cpustate->disable_interrupt_recognition = 1; - break; - case 15: /* LDD */ - /* LDD --- Long Distance Destination */ - #if HAS_PRIVILEGE - if (cpustate->STATUS & ST_PR) - { - HANDLE_PRIVILEGE_VIOLATION - break; - } - #endif - - load_map_file(cpustate, addr, src_map, 2); - cpustate->ldd_flag = 1; - cpustate->disable_interrupt_recognition = 1; - break; - -#else - - default: - /* illegal instructions */ - HANDLE_ILLEGAL; - break; - -#endif - } -} - - -/*========================================================================== - Shift instructions, >0800->0BFF - -------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | C | W | - --------------------------------- - - SRA, SRL, SLA, SRC -============================================================================*/ -static void h0800(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t addr; - register uint16_t cnt = (opcode & 0xF0) >> 4; - register uint16_t value; - - addr = (opcode & 0xF); - addr = ((addr+addr) + cpustate->WP) & ~1; - - CYCLES(3, 12, 5); - - if (cnt == 0) - { - CYCLES(2, 8, 2); - - cnt = READREG(R0) & 0xF; - - if (cnt == 0) - cnt = 16; - } - - CYCLES(cnt, cnt+cnt, cnt); - - switch ((opcode & 0x300) >> 8) - { - case 0: /* SRA */ - /* SRA --- Shift Right Arithmetic */ - /* *W >>= C (*W is filled on the left with a copy of the sign bit) */ - value = setst_sra_laec(cpustate, readword(cpustate, addr), cnt); - writeword(cpustate, addr, value); - break; - case 1: /* SRL */ - /* SRL --- Shift Right Logical */ - /* *W >>= C (*W is filled on the left with 0) */ - value = setst_srl_laec(cpustate, readword(cpustate, addr), cnt); - writeword(cpustate, addr, value); - break; - case 2: /* SLA */ - /* SLA --- Shift Left Arithmetic */ - /* *W <<= C */ - value = setst_sla_laeco(cpustate, readword(cpustate, addr), cnt); - writeword(cpustate, addr, value); - break; - case 3: /* SRC */ - /* SRC --- Shift Right Circular */ - /* *W = rightcircularshift(*W, C) */ - value = setst_src_laec(cpustate, readword(cpustate, addr), cnt); - writeword(cpustate, addr, value); - break; - } -} - - -#if 0 /* 990/12 opcodes */ -/*========================================================================== - Additionnal instructions, >0C00->0C0F - Additionnal single-register instructions, >0C10->0C3F - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | - | o p c o d e | reg # | - --------------------------------- - -============================================================================*/ -static void h0c00(tms99xx_state *cpustate, uint16_t opcode) -{ - if (opcode & 0x30) - { - switch ((opcode & 0x30) >> 4) - { - case 1: - /* INSF -- INSert Field */ - break; - case 2: - /* XV ---- eXtract Value */ - break; - case 3: - /* XF ---- eXtract Field */ - break; - } - } - else - { - switch (opcode & 0x0F) - { - /* floating point instructions */ - case 0: - /* CRI --- Convert Real to Integer */ - break; - case 2: - /* NEGR -- NEGate Real */ - break; - case 4: - /* CRE --- Convert Real to Extended integer */ - break; - case 6: - /* CER --- Convert Extended integer to Real */ - break; - - case 1: - /* CDI --- Convert Double precision real to Integer */ - break; - case 3: - /* NEGD -- NEGate Double precision real */ - break; - case 5: - /* CDE --- Convert Double precision real to Extended integer */ - break; - case 7: - /* CED --- Convert Extended integer to Double precision real */ - break; - - case 8: - /* NRM --- NoRMalize */ - break; - - case 9: - /* TMB --- Test Memory Bit */ - break; - case 10: - /* TCMB -- Test and Clear Memory Bit */ - break; - case 11: - /* TSMB -- Test and Set Memory Bit */ - break; - - case 12: - /* SRJ --- Subtract from Register and Jump */ - case 13: - /* ARJ --- Add to Register and Jump */ - - case 14: - case 15: - /* XIT --- eXIT from floating point interpreter */ - /* Generated by some compilers, but equivalent to NOP on TI990/12. May have been used - by some software floating-point emulators. */ - break; - - default: - HANDLE_ILLEGAL; - break; - } - } -} - - -/*========================================================================== - Additionnal single-operand instructions, >0C40->0DFF - >0E40->0FFF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e |TS | S | - --------------------------------- - -============================================================================*/ -static void h0c40(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t src; - -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; -#endif - - src = decipheraddr(cpustate, opcode) & ~1; - - switch ((opcode & 0x03C0) >> 6) - { - case 1: - /* AR ---- Add Real */ - break; - case 2: - /* CIR --- Convert Integer to Real */ - break; - case 3: - /* SR ---- Subtract Real */ - break; - case 4: - /* MR ---- Multiply Real */ - break; - case 5: - /* DR ---- Divide Real */ - break; - case 6: - /* LR ---- Load Real */ - break; - case 7: - /* STR --- STore Real */ - break; - case 9: - /* AD ---- Add Double */ - break; - case 10: - /* CID --- Convert Integer to Double */ - break; - case 11: - /* SD ---- Subtract Double */ - break; - case 12: - /* MD ---- Multiply Double */ - break; - case 13: - /* DD ---- Divide Double */ - break; - case 14: - /* LD ---- Load Double */ - break; - case 15: - /* SD ---- Store Double */ - break; - default: - HANDLE_ILLEGAL; - break; - } -} - -/*========================================================================== - Additionnal single-register instructions, >0E00->0E3F - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | reg # | - --------------------------------- - -============================================================================*/ -static void h0e00(tms99xx_state *cpustate, uint16_t opcode) -{ - switch ((opcode & 0x30) >> 4) - { - case 1: - /* IOF --- Invert Order of Field */ - break; - case 1: - /* SNEB -- Search string for Not Equal Byte */ - break; - case 2: - /* CRC --- Cyclic Redundancy Code calculation */ - break; - case 3: - /* TS ---- Translate String */ - break; - } -} -#endif - - -/*========================================================================== - Jump, CRU bit instructions, >1000->1FFF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | o p c o d e | signed offset | - --------------------------------- - - JMP, JLT, JLE, JEQ, JHE, JGT, JNE, JNC, JOC, JNO, JL, JH, JOP - SBO, SBZ, TB -============================================================================*/ -static void h1000(tms99xx_state *cpustate, uint16_t opcode) -{ - /* we convert 8 bit signed word offset to a 16 bit effective word offset. */ - register int16_t offset = ((int8_t) opcode); - - - switch ((opcode & 0xF00) >> 8) - { - case 0: /* JMP */ - /* JMP --- unconditional JuMP */ - /* PC += offset */ - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - break; - case 1: /* JLT */ - /* JLT --- Jump if Less Than (arithmetic) */ - /* if (A==0 && EQ==0), PC += offset */ - if (! (cpustate->STATUS & (ST_AGT | ST_EQ))) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 2: /* JLE */ - /* JLE --- Jump if Lower or Equal (logical) */ - /* if (L==0 || EQ==1), PC += offset */ - if ((! (cpustate->STATUS & ST_LGT)) || (cpustate->STATUS & ST_EQ)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 3: /* JEQ */ - /* JEQ --- Jump if EQual */ - /* if (EQ==1), PC += offset */ - if (cpustate->STATUS & ST_EQ) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 4: /* JHE */ - /* JHE --- Jump if Higher or Equal (logical) */ - /* if (L==1 || EQ==1), PC += offset */ - if (cpustate->STATUS & (ST_LGT | ST_EQ)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 5: /* JGT */ - /* JGT --- Jump if Greater Than (arithmetic) */ - /* if (A==1), PC += offset */ - if (cpustate->STATUS & ST_AGT) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 6: /* JNE */ - /* JNE --- Jump if Not Equal */ - /* if (EQ==0), PC += offset */ - if (! (cpustate->STATUS & ST_EQ)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 7: /* JNC */ - /* JNC --- Jump if No Carry */ - /* if (C==0), PC += offset */ - if (! (cpustate->STATUS & ST_C)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 8: /* JOC */ - /* JOC --- Jump On Carry */ - /* if (C==1), PC += offset */ - if (cpustate->STATUS & ST_C) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 9: /* JNO */ - /* JNO --- Jump if No Overflow */ - /* if (OV==0), PC += offset */ - if (! (cpustate->STATUS & ST_OV)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 10: /* JL */ - /* JL ---- Jump if Lower (logical) */ - /* if (L==0 && EQ==0), PC += offset */ - if (! (cpustate->STATUS & (ST_LGT | ST_EQ))) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 11: /* JH */ - /* JH ---- Jump if Higher (logical) */ - /* if (L==1 && EQ==0), PC += offset */ - if ((cpustate->STATUS & ST_LGT) && ! (cpustate->STATUS & ST_EQ)) - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - break; - case 12: /* JOP */ - /* JOP --- Jump On (odd) Parity */ - /* if (P==1), PC += offset */ - { - /* Let's set ST_OP. */ - int i; - uint8_t a; - a = cpustate->lastparity; - i = 0; - - while (a != 0) - { - if (a & 1) /* If current bit is set, */ - i++; /* increment bit count. */ - a >>= 1U; /* Next bit. */ - } - - /* Set ST_OP bit. */ - /*if (i & 1) - cpustate->STATUS |= ST_OP; - else - cpustate->STATUS &= ~ ST_OP;*/ - - /* Jump accordingly. */ - if (i & 1) /*(cpustate->STATUS & ST_OP)*/ - { - cpustate->PC += (offset + offset); - CYCLES(3, 10, 3); - } - else - CYCLES(2, 8, 3); - } - - break; - case 13: /* SBO */ - /* SBO --- Set Bit to One */ - /* CRU Bit = 1 */ - #if HAS_PRIVILEGE - if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1) == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - #else - writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1); - #endif - - CYCLES(4, 12, 8); - break; - - case 14: /* SBZ */ - /* SBZ --- Set Bit to Zero */ - /* CRU Bit = 0 */ - #if HAS_PRIVILEGE - if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0) == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - #else - writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0); - #endif - - CYCLES(4, 12, 8); - break; - - case 15: /* TB */ - /* TB ---- Test Bit */ - /* EQ = (CRU Bit == 1) */ - #if HAS_PRIVILEGE - { - int value; - - value = readCRU(cpustate, (READREG(R12)>> 1) + offset, 1); - if (value == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - else - setst_e(cpustate, value & 1, 1); - } - #else - setst_e(cpustate, readCRU(cpustate, (READREG(R12)>> 1) + offset, 1) & 1, 1); - #endif - CYCLES(5, 12, 8); - break; - } -} - - -/*========================================================================== - General and One-Register instructions >2000->3FFF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - --------------------------------- - | opcode | D |TS | S | - --------------------------------- - - COC, CZC, XOR, LDCR, STCR, XOP, MPY, DIV -tms9940 : DCA, DCS, LIIM -==========================================================================*/ - -/* xop, ldcr and stcr are handled elsewhere */ -static void h2000(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t dest = (opcode & 0x3C0) >> 6; - register uint16_t src; - register uint16_t value; - -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; -#endif - - src = decipheraddr(cpustate, opcode) & ~1; - dest = ((dest+dest) + cpustate->WP) & ~1; - - switch ((opcode & 0x1C00) >> 10) - { - case 0: /* COC */ - /* COC --- Compare Ones Corresponding */ - /* status E bit = (S&D == S) */ - value = readwordX(cpustate, src, src_map); - setst_e(cpustate, value & readword(cpustate, dest), value); - CYCLES(5, 14, 4); - break; - case 1: /* CZC */ - /* CZC --- Compare Zeroes Corresponding */ - /* status E bit = (S&~D == S) */ - value = readwordX(cpustate, src, src_map); - setst_e(cpustate, value & (~ readword(cpustate, dest)), value); - CYCLES(5, 14, 4); - break; - case 2: /* XOR */ - /* XOR --- eXclusive OR */ - /* D ^= S */ - value = readwordX(cpustate, src, src_map); - value ^= readword(cpustate, dest); - setst_lae(cpustate, value); - writeword(cpustate, dest,value); - CYCLES(3, 14, 4); - break; - /*case 3:*/ /* XOP is implemented elsewhere */ - /*case 4:*/ /* LDCR is implemented elsewhere */ - /*case 5:*/ /* STCR is implemented elsewhere */ - case 6: /* MPY */ - /* MPY --- MultiPlY (unsigned) */ - /* Results: D:D+1 = D*S */ - /* Note that early TMS9995 reportedly performs an extra dummy read in PC space */ - { - unsigned long prod = ((unsigned long) readwordX(cpustate, src, src_map)); - prod = prod * ((unsigned long) readword(cpustate, dest)); - writeword(cpustate, dest, prod >> 16); - writeword(cpustate, (dest+2)&0xffff, prod); - } - /* ti990/10 : from 19 to 35, possibly 19 + (number of bits to 1 in one operand) */ - CYCLES(35, 52, 23); - break; - case 7: /* DIV */ - /* DIV --- DIVide (unsigned) */ - /* D = D/S D+1 = D%S */ - { - uint16_t d = readwordX(cpustate, src, src_map); - uint16_t hi = readword(cpustate, dest); - unsigned long divq = (((unsigned long) hi) << 16) | readword(cpustate, (dest+2)&0xffff); - - if (d <= hi) - { - cpustate->STATUS |= ST_OV; - CYCLES(4, 16, 6); - } - else - { - cpustate->STATUS &= ~ST_OV; - writeword(cpustate, dest, divq/d); - writeword(cpustate, (dest+2)&0xffff, divq%d); - /* tms9900 : from 92 to 124, possibly 92 + 2*(number of bits to 1 (or 0?) in quotient) */ - /* tms9995 : 28 is the worst case */ - /* ti990/10 : from 41 to 58, possibly 41 + (number of bits to 1 (or 0?) in quotient) */ - CYCLES(41, 92, 28); - } - } - break; - } -} - -static void xop(tms99xx_state *cpustate, uint16_t opcode) -{ /* XOP */ - /* XOP --- eXtended OPeration */ - /* WP = *(40h+D), PC = *(42h+D) */ - /* New R13=old WP, New R14=Old IP, New R15=Old ST */ - /* New R11=S */ - /* Xop bit set */ - - register uint16_t immediate = (opcode & 0x3C0) >> 6; - register uint16_t operand; - - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - switch (immediate) - { - case 0: /* DCA */ - /* DCA --- Decimal Correct Addition */ - operand = decipheraddrbyte(cpustate, opcode); - { - int value = readbyte(cpustate, operand); - int X = (value >> 4) & 0xf; - int Y = value & 0xf; - - if (Y >= 10) - { - Y -= 10; - cpustate->STATUS |= ST_DC; - X++; - } - else if (cpustate->STATUS & ST_DC) - { - Y += 6; - } - - if (X >= 10) - { - X -= 10; - cpustate->STATUS |= ST_C; - } - else if (cpustate->STATUS & ST_C) - { - X += 6; - } - - writebyte(cpustate, operand, (X << 4) | Y); - } - break; - case 1: /* DCS */ - /* DCS --- Decimal Correct Substraction */ - operand = decipheraddrbyte(cpustate, opcode); - { - int value = readbyte(cpustate, operand); - - if (! (cpustate->STATUS & ST_DC)) - { - value += 10; - } - - if (! (cpustate->STATUS & ST_C)) - { - value += 10 << 4; - } - - cpustate->STATUS ^= ST_DC; - - writebyte(cpustate, operand, value); - } - break; - case 2: /* LIIM */ - case 3: /* LIIM */ - /* LIIM - Load Immediate Interrupt Mask */ - /* Does the same job as LIMI, with a different opcode format. */ - /* Note that, unlike TMS9900, the interrupt mask is only 2-bit long. */ - (void)decipheraddr(cpustate, opcode); /* dummy decode (personnal guess) */ - - cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (opcode & ST_IM); - break; - default: /* normal XOP */ -#endif - - /* TODO : emulate 990/10 hardware XOP */ - operand = decipheraddr(cpustate, opcode); - - #if ((TMS99XX_MODEL <= TMS9989_ID) && (TMS99XX_MODEL != TI990_10_ID)) - (void)readword(cpustate, operand & ~1); /*dummy read (personnal guess)*/ - #endif - - contextswitchX(cpustate, 0x40 + (immediate << 2)); - - #if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) - /* The bit is not set on tms9940 */ - cpustate->STATUS |= ST_X; - #endif - - WRITEREG(R11, operand); - CYCLES(7, 36, 15); - cpustate->disable_interrupt_recognition = 1; - -#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) - break; - } -#endif -} - -/* LDCR and STCR */ -static void ldcr_stcr(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t cnt = (opcode & 0x3C0) >> 6; - register uint16_t addr; - int value; - -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; -#endif - - if (cnt == 0) - cnt = 16; - - if (cnt <= 8) - addr = decipheraddrbyte(cpustate, opcode); - else - addr = decipheraddr(cpustate, opcode) & ~1; - - if (opcode < 0x3400) - { /* LDCR */ - /* LDCR -- LoaD into CRu */ - /* CRU R12--CRU R12+D-1 set to S */ - if (cnt <= 8) - { -#if (TMS99XX_MODEL != TMS9995_ID) - value = readbyteX(cpustate, addr, src_map); -#else - /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */ - /* this must be because instruction decoding is too complex */ - value = readwordX(cpustate, addr & ~1, src_map); - if (addr & 1) - value &= 0xFF; - else - value = (value >> 8) & 0xFF; -#endif - - (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ - - setst_byte_laep(cpustate, value); - } - else - { - value = readwordX(cpustate, addr, src_map); - - (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ - - setst_lae(cpustate, value); - } - - #if HAS_PRIVILEGE - if (writeCRU(cpustate, (READREG(R12) >> 1), cnt, value) == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - #else - writeCRU(cpustate, (READREG(R12) >> 1), cnt, value); - #endif - - CYCLES(4+cnt, 20 + cnt+cnt, 9 + cnt+cnt); - } - else - { /* STCR */ - /* STCR -- STore from CRu */ - /* S = CRU R12--CRU R12+D-1 */ - if (cnt <= 8) - { -#if (TMS99XX_MODEL != TMS9995_ID) - - (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/ - // MZ: Read before write - int value2 = readwordX(cpustate, addr & ~1, src_map); - - #if HAS_PRIVILEGE - value = readCRU(cpustate, (READREG(R12) >> 1), cnt); - - if (value == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - else - { - setst_byte_laep(cpustate, value); - writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map); - } - #else - value = readCRU(cpustate, (READREG(R12) >> 1), cnt); - setst_byte_laep(cpustate, value); - - writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map); - #endif - CYCLES(18+cnt, (cnt != 8) ? 42 : 44, 19 + cnt); -#else - /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */ - /* this must be because instruction decoding is too complex */ - int value2 = readwordX(cpustate, addr & ~1, src_map); - - (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/ - - value = readCRU(cpustate, (READREG(R12) >> 1), cnt); - setst_byte_laep(cpustate, value); - - if (addr & 1) - writewordX(cpustate, addr & ~1, (value & 0x00FF) | (value2 & 0xFF00), src_map); - else - writewordX(cpustate, addr & ~1, (value2 & 0x00FF) | ((value << 8) & 0xFF00), src_map); - - CYCLES(Mooof!, Mooof!, 19 + cnt); -#endif - } - else - { - (void)readwordX(cpustate, addr, src_map); /*dummy read*/ - - (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ - - #if HAS_PRIVILEGE - value = readCRU(cpustate, (READREG(R12) >> 1), cnt); - if (value == CRU_PRIVILEGE_VIOLATION) - HANDLE_PRIVILEGE_VIOLATION - else - { - setst_lae(cpustate, value); - writewordX(cpustate, addr, value, src_map); - } - #else - value = readCRU(cpustate, (READREG(R12) >> 1), cnt); - setst_lae(cpustate, value); - writewordX(cpustate, addr, value, src_map); - #endif - CYCLES(24+cnt, (cnt != 16) ? 58 : 60, 27 + cnt); - } - } -} - - -/*========================================================================== - Two-Operand instructions >4000->FFFF - --------------------------------------------------------------------------- - - 0 1 2 3-4 5 6 7+8 9 A B-C D E F - ---------------------------------- - |opcode|B|TD | D |TS | S | - ---------------------------------- - - SZC, SZCB, S, SB, C, CB, A, AB, MOV, MOVB, SOC, SOCB -============================================================================*/ - -/* word instructions */ -static void h4000w(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t src; - register uint16_t dest; - register uint16_t value; - -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; - int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map; -#endif - - src = decipheraddr(cpustate, opcode) & ~1; - dest = decipheraddr(cpustate, opcode >> 6) & ~1; - - value = readwordX(cpustate, src, src_map); - - switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */ - { - case 2: /* SZC */ - /* SZC --- Set Zeros Corresponding */ - /* D &= ~S */ - value = readwordX(cpustate, dest, dst_map) & (~ value); - setst_lae(cpustate, value); - writewordX(cpustate, dest, value, dst_map); - CYCLES(2, 14, 4); - break; - case 3: /* S */ - /* S ----- Subtract */ - /* D -= S */ - value = setst_sub_laeco(cpustate, readwordX(cpustate, dest, dst_map), value); - writewordX(cpustate, dest, value, dst_map); - CYCLES(2, 14, 4); - break; - case 4: /* C */ - /* C ----- Compare */ - /* ST = (D - S) */ - setst_c_lae(cpustate, readwordX(cpustate, dest, dst_map), value); - CYCLES(5, 14, 4); - break; - case 5: /* A */ - /* A ----- Add */ - /* D += S */ - value = setst_add_laeco(cpustate, readwordX(cpustate, dest, dst_map), value); - writewordX(cpustate, dest, value, dst_map); - CYCLES(2, 14, 4); - break; - case 6: /* MOV */ - /* MOV --- MOVe */ - /* D = S */ - setst_lae(cpustate, value); - #if ((TMS99XX_MODEL >= TMS9900_ID) && (TMS99XX_MODEL <= TMS9985_ID)) - /* MOV performs a dummy read with tms9900/9980 (but neither ti990/10 nor tms9995) */ - (void)readwordX(cpustate, dest, dst_map); - #endif - writewordX(cpustate, dest, value, dst_map); - CYCLES(1, 14, 3); - break; - case 7: /* SOC */ - /* SOC --- Set Ones Corresponding */ - /* D |= S */ - value = value | readwordX(cpustate, dest, dst_map); - setst_lae(cpustate, value); - writewordX(cpustate, dest, value, dst_map); - CYCLES(2, 14, 4); - break; - } -} - -/* byte instruction */ -static void h4000b(tms99xx_state *cpustate, uint16_t opcode) -{ - register uint16_t src; - register uint16_t dest; - register uint16_t value; - -#if HAS_MAPPING - int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; - int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map; -#endif - - src = decipheraddrbyte(cpustate, opcode); - dest = decipheraddrbyte(cpustate, opcode >> 6); - - value = readbyteX(cpustate, src, src_map); - - switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */ - { - case 2: /* SZCB */ - /* SZCB -- Set Zeros Corresponding, Byte */ - /* D &= ~S */ - value = readbyteX(cpustate, dest, dst_map) & (~ value); - setst_byte_laep(cpustate, value); - writebyteX(cpustate, dest, value, dst_map); - CYCLES(3, 14, 4); - break; - case 3: /* SB */ - /* SB ---- Subtract, Byte */ - /* D -= S */ - value = setst_subbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value); - writebyteX(cpustate, dest, value, dst_map); - CYCLES(3, 14, 4); - break; - case 4: /* CB */ - /* CB ---- Compare Bytes */ - /* ST = (D - S) */ - setst_c_lae(cpustate, readbyteX(cpustate, dest, dst_map)<<8, value<<8); - cpustate->lastparity = value; - CYCLES(5, 14, 4); - break; - case 5: /* AB */ - /* AB ---- Add, Byte */ - /* D += S */ - value = setst_addbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value); - writebyteX(cpustate, dest, value, dst_map); - CYCLES(3, 14, 4); - break; - case 6: /* MOVB */ - /* MOVB -- MOVe Bytes */ - /* D = S */ - setst_byte_laep(cpustate, value); - #if (TMS99XX_MODEL <= TMS9985_ID) - /* On ti990/10 and tms9900, MOVB needs to read destination, because it cannot actually - read one single byte. It reads a word, replaces the relevant byte, then write - the result. A tms9980 should not need to do so, but still does, because it is just - a tms9900 with a 16 to 8 bit multiplexer (instead of a new chip design, like tms9995). */ - (void)readbyteX(cpustate, dest, dst_map); - #endif - writebyteX(cpustate, dest, value, dst_map); - CYCLES(3, 14, 3); - break; - case 7: /* SOCB */ - /* SOCB -- Set Ones Corresponding, Byte */ - /* D |= S */ - value = value | readbyteX(cpustate, dest, dst_map); - setst_byte_laep(cpustate, value); - writebyteX(cpustate, dest, value, dst_map); - CYCLES(3, 14, 4); - break; - } -} - - -static inline void execute(tms99xx_state *cpustate, uint16_t opcode) -{ -#if (! HAS_9995_OPCODES) - - /* tms9900-like instruction set*/ - - static void (*const jumptable_short[128])(tms99xx_state *,uint16_t) = - { - &illegal,&h0200,&h0400,&h0400,&h0800,&h0800,&illegal,&illegal, - &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, - &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&xop,&xop, - &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&h2000,&h2000,&h2000,&h2000, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b - }; - - (* jumptable_short[opcode >> 9])(cpustate, opcode); - -#else - - /* tms9989 and tms9995 include 4 extra instructions, and one additionnal instruction type */ - /* tms99000 includes yet another additional instruction */ - - static void (*const jumptable_long[256])(tms99xx_state *,uint16_t) = - { - &h0040,&h0100,&h0200,&h0200,&h0400,&h0400,&h0400,&h0400, - &h0800,&h0800,&h0800,&h0800,&illegal,&illegal,&illegal,&illegal, - &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, - &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, - &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000, - &h2000,&h2000,&h2000,&h2000,&xop,&xop,&xop,&xop, - &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr, - &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, - &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b - }; - - (* jumptable_long[opcode >> 8])(cpustate, opcode); - -#endif -} - -/************************************************************************** - * Generic set_info - **************************************************************************/ - -static CPU_SET_INFO( tms99xx ) -{ - tms99xx_state *cpustate = get_safe_token(device); - switch (state) - { - /* --- the following bits of info are set as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, info->i); break; - case CPUINFO_INT_INPUT_STATE + 0: tms99xx_set_irq_line(cpustate, 0, info->i); break; - case CPUINFO_INT_INPUT_STATE + 1: tms99xx_set_irq_line(cpustate, 1, info->i); break; - case CPUINFO_INT_INPUT_STATE + 2: tms99xx_set_irq_line(cpustate, 2, info->i); break; - -#if (TMS99XX_MODEL == TI990_10_ID) - case CPUINFO_INT_PC: - { - const unsigned top = (cpustate->cur_map == 0) ? 0xf800 : 0x10000; - - if ((cpustate->cur_map == 0) && (info->i >= 0x1ff800)) - /* intercept TPCS and CPU ROM */ - cpustate->PC = info->i - 0x1f0000; - else if (! cpustate->mapping_on) - cpustate->PC = (info->i < top) ? info->i : 0; - else - { - if ((info->i >= cpustate->map_files[cpustate->cur_map].bias[0]) - && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[0]+cpustate->map_files[cpustate->cur_map].limit[0]))) - cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[0]; - else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[0])) - && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[1]))) - cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[1]; - else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[0])) - && (info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[1])) - && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[2]))) - cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[2]; - else - { - /*if ((info->i < top) - && (info->i > cpustate->map_files[cpustate->cur_map].limit[0]) - && (info->i > cpustate->map_files[cpustate->cur_map].limit[1]) - && (info->i > cpustate->map_files[cpustate->cur_map].limit[2])) - cpustate->PC = info->i; - else*/ - cpustate->PC = 0; - } - /*if (info->i >= top) - cpustate->PC = 0;*/ - } - cpustate->PC &= 0xfffe; - } - break; -#else - case CPUINFO_INT_PC: -#endif - case CPUINFO_INT_REGISTER + TMS9900_PC: cpustate->PC = info->i & 0xfffe; break; - case CPUINFO_INT_REGISTER + TMS9900_IR: cpustate->IR = info->i; break; - case CPUINFO_INT_SP: - case CPUINFO_INT_REGISTER + TMS9900_WP: cpustate->WP = info->i & 0xfffe; break; - case CPUINFO_INT_REGISTER + TMS9900_STATUS: cpustate->STATUS = info->i; getstat(cpustate); break; - case CPUINFO_INT_REGISTER + TMS9900_R0: WRITEREG_DEBUG(cpustate, R0, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R1: WRITEREG_DEBUG(cpustate, R1, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R2: WRITEREG_DEBUG(cpustate, R2, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R3: WRITEREG_DEBUG(cpustate, R3, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R4: WRITEREG_DEBUG(cpustate, R4, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R5: WRITEREG_DEBUG(cpustate, R5, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R6: WRITEREG_DEBUG(cpustate, R6, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R7: WRITEREG_DEBUG(cpustate, R7, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R8: WRITEREG_DEBUG(cpustate, R8, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R9: WRITEREG_DEBUG(cpustate, R9, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R10: WRITEREG_DEBUG(cpustate, R10, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R11: WRITEREG_DEBUG(cpustate, R11, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R12: WRITEREG_DEBUG(cpustate, R12, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R13: WRITEREG_DEBUG(cpustate, R13, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R14: WRITEREG_DEBUG(cpustate, R14, info->i); break; - case CPUINFO_INT_REGISTER + TMS9900_R15: WRITEREG_DEBUG(cpustate, R15, info->i); break; - } -} - - - -/************************************************************************** - * Generic get_info - **************************************************************************/ - -void TMS99XX_GET_INFO(legacy_cpu_device *device, uint32_t state, cpuinfo *info) -{ - tms99xx_state *cpustate = (device != nullptr && device->token() != nullptr) ? get_safe_token(device) : nullptr; - switch (state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms99xx_state); break; - case CPUINFO_INT_INPUT_LINES: info->i = 3; break; - case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; - case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; - case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; - case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; - case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; - case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6;/*8 with 990/12, 99105, 99110*/break; - case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; - case CPUINFO_INT_MAX_CYCLES: info->i = 10;/*TODO: compute this value*/break; - -#if (USE_16_BIT_ACCESSORS) - case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break; -#else - case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break; -#endif - case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: -#if (TMS99XX_MODEL == TI990_10_ID) - /* this CPU has a mapper to expand the address space */ - info->i = 21; -#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) - /* basic 16-bit address bus */ - info->i = 16; -#elif (TMS99XX_MODEL == TMS9980_ID) - /* 2 address MSBits are unconnected */ - info->i = 14; -#else - #warning "Please check how many address bits your CPU has." - info->i = 16; -#endif - break; - case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; - case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; - case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break; - case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: -#if (TMS99XX_MODEL == TI990_10_ID) - /* 3 MSBs do exist, although they are not connected (don't ask...) */ - info->i = 15; -#elif (TMS99XX_MODEL == TMS9900_ID) - /* 3 MSBs are external instruction code */ - info->i = 12; -#elif (TMS99XX_MODEL == TMS9980_ID) - /* 2 bits unused, and 2 MSBs are external instruction code */ - info->i = 13; -#elif (TMS99XX_MODEL == TMS9940_ID) - /* 9 internal address lines (8 external) */ - info->i = 9; -#elif (TMS99XX_MODEL == TMS9995_ID) - /* 15-bit address and data bus lines D0-D2 provide the external instruction code */ - info->i = 15+3; -#else - #warning "I don't know how your processor handles CRU." - info->i = 15; -#endif - break; - case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; - -/* not implemented */ -/* case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = get_irq_line(INPUT_LINE_NMI); break; - case CPUINFO_INT_INPUT_STATE + 0: info->i = get_irq_line(0); break; - case CPUINFO_INT_INPUT_STATE + 1: info->i = get_irq_line(1); break; - case CPUINFO_INT_INPUT_STATE + 2: info->i = get_irq_line(2); break;*/ - - case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; - -#if (TMS99XX_MODEL == TI990_10_ID) - case CPUINFO_INT_PC: - if ((cpustate->cur_map == 0) && (cpustate->PC >= 0xf800)) - /* intercept TPCS and CPU ROM */ - info->i = 0x1f0000+cpustate->PC; - else if (! cpustate->mapping_on) - info->i = cpustate->PC; - else - { - int map_index; - - if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[0]) - map_index = 0; - else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[1]) - map_index = 1; - else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[2]) - map_index = 2; - else - { - info->i = cpustate->PC; - break; - } - - info->i = cpustate->map_files[cpustate->cur_map].bias[map_index]+cpustate->PC; - } - break; -#else - case CPUINFO_INT_PC: -#endif - case CPUINFO_INT_REGISTER + TMS9900_PC: info->i = cpustate->PC; break; - case CPUINFO_INT_REGISTER + TMS9900_IR: info->i = cpustate->IR; break; - case CPUINFO_INT_SP: - case CPUINFO_INT_REGISTER + TMS9900_WP: info->i = cpustate->WP; break; - case CPUINFO_INT_REGISTER + TMS9900_STATUS: setstat(cpustate); info->i = cpustate->STATUS; break; - case CPUINFO_INT_REGISTER + TMS9900_R0: info->i = READREG_DEBUG(cpustate, R0); break; - case CPUINFO_INT_REGISTER + TMS9900_R1: info->i = READREG_DEBUG(cpustate, R1); break; - case CPUINFO_INT_REGISTER + TMS9900_R2: info->i = READREG_DEBUG(cpustate, R2); break; - case CPUINFO_INT_REGISTER + TMS9900_R3: info->i = READREG_DEBUG(cpustate, R3); break; - case CPUINFO_INT_REGISTER + TMS9900_R4: info->i = READREG_DEBUG(cpustate, R4); break; - case CPUINFO_INT_REGISTER + TMS9900_R5: info->i = READREG_DEBUG(cpustate, R5); break; - case CPUINFO_INT_REGISTER + TMS9900_R6: info->i = READREG_DEBUG(cpustate, R6); break; - case CPUINFO_INT_REGISTER + TMS9900_R7: info->i = READREG_DEBUG(cpustate, R7); break; - case CPUINFO_INT_REGISTER + TMS9900_R8: info->i = READREG_DEBUG(cpustate, R8); break; - case CPUINFO_INT_REGISTER + TMS9900_R9: info->i = READREG_DEBUG(cpustate, R9); break; - case CPUINFO_INT_REGISTER + TMS9900_R10: info->i = READREG_DEBUG(cpustate, R10); break; - case CPUINFO_INT_REGISTER + TMS9900_R11: info->i = READREG_DEBUG(cpustate, R11); break; - case CPUINFO_INT_REGISTER + TMS9900_R12: info->i = READREG_DEBUG(cpustate, R12); break; - case CPUINFO_INT_REGISTER + TMS9900_R13: info->i = READREG_DEBUG(cpustate, R13); break; - case CPUINFO_INT_REGISTER + TMS9900_R14: info->i = READREG_DEBUG(cpustate, R14); break; - case CPUINFO_INT_REGISTER + TMS9900_R15: info->i = READREG_DEBUG(cpustate, R15); break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(tms99xx); break; - case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(tms99xx); break; - case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(tms99xx); break; - case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(tms99xx); break; - case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(tms99xx); break; - case CPUINFO_FCT_BURN: info->burn = nullptr; break; - case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(tms99xx); break; - case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, TMS99XX_device_get_name); break; - case CPUINFO_STR_SHORTNAME: strcpy(info->s, TMS99XX_device_get_shortname); break; - - case CPUINFO_STR_FAMILY: strcpy(info->s, "Texas Instruments 9900L"); break; - case CPUINFO_STR_VERSION: strcpy(info->s, "2.0"); break; - case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case CPUINFO_STR_CREDITS: strcpy(info->s, "C TMS9900 emulator by Edward Swartz, initially converted for Mame by M.Coates, updated by R. Nabet"); break; - - case CPUINFO_STR_FLAGS: - sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", - cpustate->WP & 0x8000 ? 'L':'.', - cpustate->WP & 0x4000 ? 'A':'.', - cpustate->WP & 0x2000 ? 'E':'.', - cpustate->WP & 0x1000 ? 'C':'.', - cpustate->WP & 0x0800 ? 'V':'.', - cpustate->WP & 0x0400 ? 'P':'.', - cpustate->WP & 0x0200 ? 'X':'.', - cpustate->WP & 0x0100 ? '?':'.', - cpustate->WP & 0x0080 ? '?':'.', - cpustate->WP & 0x0040 ? '?':'.', - cpustate->WP & 0x0020 ? '?':'.', - cpustate->WP & 0x0010 ? '?':'.', - cpustate->WP & 0x0008 ? 'I':'.', - cpustate->WP & 0x0004 ? 'I':'.', - cpustate->WP & 0x0002 ? 'I':'.', - cpustate->WP & 0x0001 ? 'I':'.'); - break; - - case CPUINFO_STR_REGISTER + TMS9900_PC: sprintf(info->s, "PC :%04X", cpustate->PC); break; - case CPUINFO_STR_REGISTER + TMS9900_IR: sprintf(info->s, "IR :%04X", cpustate->IR); break; - case CPUINFO_STR_REGISTER + TMS9900_WP: sprintf(info->s, "WP :%04X", cpustate->WP); break; - case CPUINFO_STR_REGISTER + TMS9900_STATUS: sprintf(info->s, "ST :%04X", cpustate->STATUS); break; - - case CPUINFO_STR_REGISTER + TMS9900_R0: sprintf(info->s, "R0 :%04X", READREG_DEBUG(cpustate, R0)); break; - case CPUINFO_STR_REGISTER + TMS9900_R1: sprintf(info->s, "R1 :%04X", READREG_DEBUG(cpustate, R1)); break; - case CPUINFO_STR_REGISTER + TMS9900_R2: sprintf(info->s, "R2 :%04X", READREG_DEBUG(cpustate, R2)); break; - case CPUINFO_STR_REGISTER + TMS9900_R3: sprintf(info->s, "R3 :%04X", READREG_DEBUG(cpustate, R3)); break; - case CPUINFO_STR_REGISTER + TMS9900_R4: sprintf(info->s, "R4 :%04X", READREG_DEBUG(cpustate, R4)); break; - case CPUINFO_STR_REGISTER + TMS9900_R5: sprintf(info->s, "R5 :%04X", READREG_DEBUG(cpustate, R5)); break; - case CPUINFO_STR_REGISTER + TMS9900_R6: sprintf(info->s, "R6 :%04X", READREG_DEBUG(cpustate, R6)); break; - case CPUINFO_STR_REGISTER + TMS9900_R7: sprintf(info->s, "R7 :%04X", READREG_DEBUG(cpustate, R7)); break; - case CPUINFO_STR_REGISTER + TMS9900_R8: sprintf(info->s, "R8 :%04X", READREG_DEBUG(cpustate, R8)); break; - case CPUINFO_STR_REGISTER + TMS9900_R9: sprintf(info->s, "R9 :%04X", READREG_DEBUG(cpustate, R9)); break; - case CPUINFO_STR_REGISTER + TMS9900_R10: sprintf(info->s, "R10:%04X", READREG_DEBUG(cpustate, R10)); break; - case CPUINFO_STR_REGISTER + TMS9900_R11: sprintf(info->s, "R11:%04X", READREG_DEBUG(cpustate, R11)); break; - case CPUINFO_STR_REGISTER + TMS9900_R12: sprintf(info->s, "R12:%04X", READREG_DEBUG(cpustate, R12)); break; - case CPUINFO_STR_REGISTER + TMS9900_R13: sprintf(info->s, "R13:%04X", READREG_DEBUG(cpustate, R13)); break; - case CPUINFO_STR_REGISTER + TMS9900_R14: sprintf(info->s, "R14:%04X", READREG_DEBUG(cpustate, R14)); break; - case CPUINFO_STR_REGISTER + TMS9900_R15: sprintf(info->s, "R15:%04X", READREG_DEBUG(cpustate, R15)); break; - } -} |