diff options
Diffstat (limited to 'src/emu/cpu/tms9900/tms9900.h')
-rw-r--r-- | src/emu/cpu/tms9900/tms9900.h | 531 |
1 files changed, 355 insertions, 176 deletions
diff --git a/src/emu/cpu/tms9900/tms9900.h b/src/emu/cpu/tms9900/tms9900.h index c6decc93378..12904b44ad0 100644 --- a/src/emu/cpu/tms9900/tms9900.h +++ b/src/emu/cpu/tms9900/tms9900.h @@ -1,210 +1,389 @@ /* - tms9900.h + TMS9900 processor + This is a re-implementation of the TMS9900 featuring a cycle-precise + behaviour. - C Header file for TMS9900 core -*/ + See tms9900.c for documentation -#pragma once + Types of TMS99xx processors: + TI990/9 Early implementation, used in a few real-world applications, 1974 + very similar to mapper-less 990/10 and tms9900, but the Load + process is different -#ifndef __TMS9900_H__ -#define __TMS9900_H__ + TI990/10 Original multi-chip implementation for minicomputer systems, 1975 + TI990/12 Multi-chip implementation, faster than 990/10. Huge instruction set -/*#define TI990_9_ID 0*//* early implementation, used in a few real-world applications, 1974 */ - /* very similar to mapper-less 990/10 and tms9900, but the Load process */ - /* is different */ - /* ("ti990/9" is likely to be a nickname) */ -#define TI990_10_ID 1 /* original multi-chip implementation for minicomputer systems, 1975 */ -/*#define TI990_12_ID 2*//* multi-chip implementation, faster than 990/10. huge instruction set */ - /* (144 instructions, with up to 16 additional custom instructions simulteanously) */ - /* 1979 (or before) */ -#define TMS9900_ID 3 /* mono-chip implementation, 1976 */ -#define TMS9940_ID 4 /* microcontroller with 2kb ROM, 128b RAM, decrementer, CRU bus, 1979 */ -#define TMS9980_ID 5 /* 8-bit variant of tms9900. Two distinct chips actually : tms9980a, */ - /* and tms9981 with an extra clock and simplified power supply */ -#define TMS9985_ID 6 /* 9940 with 8kb ROM, 256b RAM, and a 8-bit external bus, c. 1978 (never released) */ -#define TMS9989_ID 7 /* improved 9980, used in bombs, missiles, and other *nice* hardware */ -/*#define SBP68689_ID 8*//* improved 9989, built as an ASIC as 9989 was running scarce */ -#define TMS9995_ID 9 /* tms9985-like, with many improvements (but no ROM) */ -#define TMS99000_ID 10/* improved mono-chip implementation, meant to replace 990/10, 1981 */ - /* This chip is available in several variants (tms99105, tms99110...), */ - /* which are similar but emulate additional instructions thanks */ - /* to the so-called macrostore feature. */ -#define TMS99105A_ID 11 -#define TMS99110A_ID 12 - - -/* NPW 25-May-2002 - Added these to get it to compile under windows */ -#define TI9940_ID TMS9940_ID -#define TI9985_ID TMS9985_ID + TMS9900 Mono-chip implementation, 1976. Used in the TI-99/4(A) computer. + TMS9940 Microcontroller with 2kb ROM, 128b RAM, decrementer, CRU bus, 1979 -enum -{ - TMS9900_PC=1, TMS9900_WP, TMS9900_STATUS, TMS9900_IR, - TMS9900_R0, TMS9900_R1, TMS9900_R2, TMS9900_R3, - TMS9900_R4, TMS9900_R5, TMS9900_R6, TMS9900_R7, - TMS9900_R8, TMS9900_R9, TMS9900_R10, TMS9900_R11, - TMS9900_R12, TMS9900_R13, TMS9900_R14, TMS9900_R15 -}; + TMS9980 8-bit variant of tms9900. Two distinct chips actually : tms9980a + and tms9981 with an extra clock and simplified power supply -typedef void (*ti99xx_idle_func)(device_t *device, int state); -typedef void (*ti99xx_rset_func)(device_t *device); -typedef void (*ti99xx_lrex_func)(device_t *device); -typedef void (*ti99xx_ckon_ckof_func)(device_t *device, int state); -typedef void (*ti99xx_error_interrupt_func)(device_t *device, int state); + TMS9985 9940 with 8kb ROM, 256b RAM, and a 8-bit external bus, c. 1978 (never released) + TMS9989 Improved 9980, used in military hardware. -DECLARE_LEGACY_CPU_DEVICE(TI990_10, ti990_10); + SBP68689 Improved 9989, built as an ASIC as 9989 was running scarce -/* - structure with the parameters ti990_10_reset wants. -*/ + TMS9995 TMS9985-like, with many improvements (but no ROM). Used in the + TI-99/8 prototype and the Geneve computer. -typedef struct ti990_10reset_param -{ - ti99xx_idle_func idle_callback; - ti99xx_rset_func rset_callback; - ti99xx_lrex_func lrex_callback; - ti99xx_ckon_ckof_func ckon_ckof_callback; - ti99xx_error_interrupt_func error_interrupt_callback; -} ti990_10reset_param; + TMS99000 Improved mono-chip implementation, meant to replace 990/10, 1981 + TMS99105 This chip is available in several variants which are similar + TMS99110 but emulate additional instructions, thanks to the so-called + macrostore feature. -/* accessor for the internal ROM */ -extern READ16_HANDLER(ti990_10_internal_r); - -/* CRU accessor for the mapper registers (R12 base 0x1fa0) */ -extern READ8_HANDLER(ti990_10_mapper_cru_r); -extern WRITE8_HANDLER(ti990_10_mapper_cru_w); -/* CRU accessor for the error interrupt register (R12 base 0x1fc0) */ -extern READ8_HANDLER(ti990_10_eir_cru_r); -extern WRITE8_HANDLER(ti990_10_eir_cru_w); - - - -DECLARE_LEGACY_CPU_DEVICE(TMS9900, tms9900); - -/* - structure with optional parameters for tms9900_reset. + In this implementation we only consider TMS9900, 9980, and 9995. The + remaining types are implemented on an own code base as they introduce + significant changes (e.g. privileged mode, address mapper). For now we + leave the implementation of the rest up to 99xxcore.h. */ -typedef struct tms9900reset_param -{ - ti99xx_idle_func idle_callback; -} tms9900reset_param; - - - -//DECLARE_LEGACY_CPU_DEVICE(TMS9940, tms9940); - -/* - structure with optional parameters for tms9940_reset. -*/ -typedef struct tms9940reset_param -{ - ti99xx_idle_func idle_callback; -} tms9940reset_param; - - - -DECLARE_LEGACY_CPU_DEVICE(TMS9980, tms9980a); - -/* - structure with optional parameters for tms9980a_reset. -*/ -typedef struct tms9980areset_param -{ - ti99xx_idle_func idle_callback; -} tms9980areset_param; - +#ifndef __TMS9900_H__ +#define __TMS9900_H__ -//DECLARE_LEGACY_CPU_DEVICE(TMS9985, tms9985); +#include "emu.h" +#include "debugger.h" -/*// - structure with optional parameters for tms9985_reset. -*/ -typedef struct tms9985reset_param +enum { - ti99xx_idle_func idle_callback; -} tms9985reset_param; - - + TI990_10_ID = 1, + TMS9900_ID = 3, + TMS9940_ID = 4, + TMS9980_ID = 5, + TMS9985_ID = 6, + TMS9989_ID = 7, + TMS9995_ID = 9, + TMS99000_ID = 10, + TMS99105A_ID = 11, + TMS99110A_ID = 12 +}; -//DECLARE_LEGACY_CPU_DEVICE(TMS9989, tms9989); +#define MCFG_TMS9900_ADD(_tag, _device, _clock, _prgmap, _iomap, _config) \ + MCFG_DEVICE_ADD(_tag, _device, _clock) \ + MCFG_DEVICE_PROGRAM_MAP(_prgmap) \ + MCFG_DEVICE_IO_MAP(_iomap) \ + MCFG_DEVICE_CONFIG(_config) -/* - structure with optional parameters for tms9989_reset. -*/ -typedef struct tms9989reset_param +enum { - ti99xx_idle_func idle_callback; -} tms9989reset_param; - - - -DECLARE_LEGACY_CPU_DEVICE(TMS9995, tms9995); + IDLE_OP = 2, + RSET_OP = 3, + CKOF_OP = 5, + CKON_OP = 6, + LREX_OP = 7 +}; -/* - structure with the parameters tms9995_reset wants. -*/ -typedef struct tms9995reset_param +typedef struct _tms9900_config { - /* auto_wait_state : a non-zero value makes tms9995 generate a wait state automatically on each - memory access */ - int auto_wait_state; - - ti99xx_idle_func idle_callback; - - /* on the tms9995-mp9537, internal RAM and decrementer register are - disabled. This chip is used by the ti99/8 so that internal RAM does - not prevent the mapper from working correctly. */ - int is_mp9537; -} tms9995reset_param; - -/* accessor for the first 252 bytes of internal RAM */ -extern READ8_HANDLER(tms9995_internal1_r); -extern WRITE8_HANDLER(tms9995_internal1_w); -/* accessors for the last 4 bytes of internal RAM */ -extern READ8_HANDLER(tms9995_internal2_r); -extern WRITE8_HANDLER(tms9995_internal2_w); - - - -//DECLARE_LEGACY_CPU_DEVICE(TMS99000, tms99000); - -/* - structure with optional parameters for tms99000_reset. -*/ -typedef struct tms99000reset_param + devcb_write8 external_callback; + devcb_read8 irq_level; + devcb_write_line instruction_acquisition; + devcb_write_line clock_out; + devcb_write_line wait_line; + devcb_write_line holda_line; +} tms9900_config; + +#define TMS9900_CONFIG(name) \ + const tms9900_config(name) = + +class tms9900_device : public cpu_device { - ti99xx_idle_func idle_callback; -} tms99000reset_param; - - +public: + tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // READY input line. When asserted (high), the memory is ready for data exchange. + void set_ready(int state); + + // HOLD input line. When asserted (low), the CPU is requested to release the + // data and address bus and enter the HOLD state. The entrance of this state + // is acknowledged by the HOLDA output line. + void set_hold(int state); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_set_input(int irqline, int state); + virtual void execute_run(); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + const address_space_config* memory_space_config(address_spacenum spacenum) const; + +private: + // TMS9900 hardware registers + UINT16 WP; // Workspace pointer + UINT16 PC; // Program counter + UINT16 ST; // Status register + + // Internal register + UINT16 IR; // Instruction register + + // Decoded command + UINT16 m_command; + + // Indicates if this is a byte-oriented command + inline bool byte_operation(); + + const address_space_config m_program_config; + const address_space_config m_io_config; + address_space* m_prgspace; + address_space* m_cru; + + // Processor states + bool m_idle_state; + bool m_load_state; + bool m_irq_state; + bool m_ready_state; + bool m_wait_state; + bool m_hold_state; + + bool m_reset; + + int m_irq_level; // Interrupt level as acquired from input lines IC0-IC3 + int m_icount; // Cycle counter + + // State / debug management + UINT16 m_state_any; + static const char* s_statename[]; + void state_import(const device_state_entry &entry); + void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, astring &string); + UINT16 read_workspace_register_debug(int reg); + void write_workspace_register_debug(int reg, UINT16 data); + + // Interrupt handling + void service_interrupt(); + + // ================ Microprogram support ======================== + + // Set up lookup table + void build_command_lookup_table(); + + // Sequence of micro-operations + typedef const UINT8* microprogram; + + // Method pointer + typedef void (tms9900_device::*ophandler)(void); + + // Opcode list entry + typedef struct _tms_instruction + { + UINT16 opcode; + int id; + int format; + microprogram prog; // Microprogram + } tms_instruction; + + // Lookup table entry + typedef struct _lookup_entry + { + struct _lookup_entry *next_digit; + const tms_instruction *entry; + } lookup_entry; + + // Pointer to the lookup table + lookup_entry* m_command_lookup_table; + + // List of allocated tables (used for easy clean-up on exit) + lookup_entry* m_lotables[32]; + + // List of pointers for micro-operations + static const tms9900_device::ophandler s_microoperation[]; + + // Opcode table + static const tms9900_device::tms_instruction s_command[]; + + // Micro-operation declarations + void acquire_instruction(void); + void mem_read(void); + void mem_write(void); + void register_read(void); + void register_write(void); + void cru_operation(void); + void data_derivation_subprogram(void); + void return_from_subprogram(void); + void command_completed(void); + + void alu_nop(void); + void alu_clear(void); + void alu_source(void); + void alu_setaddr(void); + void alu_addone(void); + void alu_setaddr_addone(void); + void alu_pcaddr_advance(void); + void alu_add_register(void); + + void alu_imm(void); + void alu_reg(void); + + void alu_f1(void); + void alu_comp(void); + void alu_f3(void); + void alu_multiply(void); + void alu_divide(void); + void alu_xop(void); + void alu_clr_swpb(void); + void alu_abs(void); + void alu_x(void); + void alu_b(void); + void alu_bl(void); + void alu_blwp(void); + void alu_ldcr(void); + void alu_stcr(void); + void alu_sbz_sbo(void); + void alu_tb(void); + void alu_jmp(void); + void alu_shift(void); + void alu_ai_ori(void); + void alu_ci(void); + void alu_li(void); + void alu_lwpi(void); + void alu_limi(void); + void alu_stwp_stst(void); + void alu_external(void); + void alu_rtwp(void); + void alu_int(void); + + void abort_operation(void); + UINT16 pulse_and_read_memory(UINT16 address); + void pulse_and_write_memory(UINT16 address, UINT16 data); + void decode(UINT16 inst); + + // Micro-operation + UINT8 m_op; + + // Micro-operation program counter (as opposed to the program counter PC) + int MPC; + + // Current microprogram + const UINT8* m_program; + + // Calling microprogram (used when data derivation is called) + const UINT8* m_caller; + int m_caller_MPC; + + // State of the micro-operation. Needed for repeated ALU calls. + int m_state; + + // Check the READY line? + bool m_check_ready; + + // Has HOLD been acknowledged yet? + bool m_hold_acknowledged; + + // Issue clock pulses. Note that each machine cycle has two clock cycles. + inline void pulse_clock(int count); + + // Signal the wait state via the external line + inline void set_wait_state(bool state); + + // Used to acknowledge HOLD and enter the HOLD state + inline void acknowledge_hold(); + + // Stored address + UINT16 m_address; + + // Stores the recently read word or the word to be written + UINT16 m_current_value; + + // Was the source operand a byte from an even address? + bool m_source_even; + + // Was the destination operand a byte from an even address? + bool m_destination_even; + + // Intermediate storage for the source operand + UINT16 m_source_address; + UINT16 m_source_value; + + // Stores the recently read register contents + UINT16 m_register_contents; + + // Stores the register number for the next register access + int m_regnumber; + + // CRU support: Indicates whether the CRU shall be configured to output mode + bool m_cru_output; + + // CRU support: Stores the CRU address + UINT16 m_cru_address; + + // CRU support: Stores the number of bits to be transferred + int m_count; + + // Another internal register, storing intermediate values + // Using 32 bits to support MPY + UINT32 m_value; + + // For two-argument commands. Indicates whether this is the second operand. + bool m_get_destination; + + // Status register update + inline void set_status_bit(int bit, bool state); + inline void compare_and_set_lae(UINT16 value1, UINT16 value2); + void set_status_parity(UINT8 value); + + // Used to display the number of consumed cycles in the log. + int m_first_cycle; + + /************************************************************************/ + + // Trigger external operation. This is achieved by putting a special value in + // the most significant three bits of the address bus (TMS9995: data bus) and + // pulsing the CRUCLK line. + // Accordingly, we have + // + // A0 A1 A2 A3 A4 A5 ... A12 A13 A14 A15 + // 0 0 0 x x x x x x - normal CRU access + // 0 1 0 x x x x x x - IDLE + // 0 1 1 x x x x x x - RSET + // 1 0 1 x x x x x x - CKON + // 1 1 0 x x x x x x - CKOF + // 1 1 1 x x x x x x - LREX + // + // so the TMS9900 can only use CRU addresses 0 - 1ffe for CRU operations. + // By moving these three bits to the data bus, the TMS9995 can allow for the + // full range 0000-fffe for its CRU operations. + // + // We could realize this via the CRU access as well, but the data bus access + // is not that simple to emulate. For the sake of homogenity between the + // chip emulations we use a dedicated callback. + devcb_resolved_write8 m_external_operation; -//DECLARE_LEGACY_CPU_DEVICE(TMS99105A, tms99105a); - -/* - structure with optional parameters for tms99105a_reset. -*/ -typedef struct tms99105areset_param -{ - ti99xx_idle_func idle_callback; -} tms99105areset_param; + // Get the value of the interrupt level lines + devcb_resolved_read8 m_get_ic0123; + // Signal to the outside world that we are now getting an instruction + devcb_resolved_write_line m_iaq_line; + // Clock output. This is not a pin of the TMS9900 because the TMS9900 + // needs an external clock, and usually one of those external lines is + // used for this purpose. + devcb_resolved_write_line m_clock_out_line; -//DECLARE_LEGACY_CPU_DEVICE(TMS99110A, tms99110a); + // Wait output. When asserted (high), the CPU is in a wait state. + devcb_resolved_write_line m_wait_line; -/* - structure with optional parameters for tms99110a_reset. -*/ -typedef struct tms99110areset_param -{ - ti99xx_idle_func idle_callback; -} tms99110areset_param; + // HOLD Acknowledge line. When asserted (high), the CPU is in HOLD state. + devcb_resolved_write_line m_holda_line; +}; +unsigned Dasm9900(char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram); -unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram); +// device type definition +extern const device_type TMS9900; #endif /* __TMS9900_H__ */ |