mirror of
https://github.com/holub/mame
synced 2025-05-25 15:25:33 +03:00
Added cycle-precise implementation of tms9980a; changed tms9900.c to allow for subclassing tms9900 and tms9980a from a common parent. [Michael Zapf]
This commit is contained in:
parent
86dfb47394
commit
ca025ce099
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -563,6 +563,7 @@ src/emu/cpu/tms9900/tms9900.h svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9900l.c svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9900l.h svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9980a.c svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9980a.h svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9980al.c svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9995.c svneol=native#text/plain
|
||||
src/emu/cpu/tms9900/tms9995.h svneol=native#text/plain
|
||||
|
@ -1608,6 +1608,7 @@ ifneq ($(filter TMS9900,$(CPUS)),)
|
||||
OBJDIRS += $(CPUOBJ)/tms9900
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9900.o
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9900l.o
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9980a.o
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9980al.o
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9995.o
|
||||
CPUOBJS += $(CPUOBJ)/tms9900/tms9995l.o
|
||||
@ -1623,13 +1624,18 @@ $(CPUOBJ)/tms9900/tms9900l.o: $(CPUSRC)/tms9900/tms9900l.c \
|
||||
$(CPUSRC)/tms9900/99xxcore.h \
|
||||
$(CPUSRC)/tms9900/99xxstat.h
|
||||
|
||||
$(CPUOBJ)/tms9900/tms9980a.o: $(CPUSRC)/tms9900/tms9980a.c \
|
||||
$(CPUSRC)/tms9900/tms9980a.h \
|
||||
$(CPUSRC)/tms9900/tms9900.c \
|
||||
$(CPUSRC)/tms9900/tms9900.h
|
||||
|
||||
$(CPUOBJ)/tms9900/tms9980al.o: $(CPUSRC)/tms9900/tms9980al.c \
|
||||
$(CPUSRC)/tms9900/tms9900l.h \
|
||||
$(CPUSRC)/tms9900/99xxcore.h \
|
||||
$(CPUSRC)/tms9900/99xxstat.h
|
||||
|
||||
$(CPUOBJ)/tms9900/tms9995.o: $(CPUSRC)/tms9900/tms9995.c \
|
||||
$(CPUSRC)/tms9900/tms9900.h
|
||||
$(CPUSRC)/tms9900/tms9995.h
|
||||
|
||||
$(CPUOBJ)/tms9900/tms9995l.o: $(CPUSRC)/tms9900/tms9995l.c \
|
||||
$(CPUSRC)/tms9900/tms9900l.h \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,12 @@
|
||||
#include "emu.h"
|
||||
#include "debugger.h"
|
||||
|
||||
enum
|
||||
{
|
||||
LOAD_INT = -1,
|
||||
RESET_INT = -2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TI990_10_ID = 1,
|
||||
@ -61,7 +67,7 @@ enum
|
||||
TMS99110A_ID = 12
|
||||
};
|
||||
|
||||
#define MCFG_TMS9900_ADD(_tag, _device, _clock, _prgmap, _iomap, _config) \
|
||||
#define MCFG_TMS99xx_ADD(_tag, _device, _clock, _prgmap, _iomap, _config) \
|
||||
MCFG_DEVICE_ADD(_tag, _device, _clock) \
|
||||
MCFG_DEVICE_PROGRAM_MAP(_prgmap) \
|
||||
MCFG_DEVICE_IO_MAP(_iomap) \
|
||||
@ -76,7 +82,18 @@ enum
|
||||
LREX_OP = 7
|
||||
};
|
||||
|
||||
typedef struct _tms9900_config
|
||||
static const char opname[][5] =
|
||||
{ "ILL ", "A ", "AB ", "ABS ", "AI ", "ANDI", "B ", "BL ", "BLWP", "C ",
|
||||
"CI ", "CB ", "CKOF", "CKON", "CLR ", "COC ", "CZC ", "DEC ", "DECT", "DIV ",
|
||||
"IDLE", "INC ", "INCT", "INV ", "JEQ ", "JGT ", "JH ", "JHE ", "JL ", "JLE ",
|
||||
"JLT ", "JMP ", "JNC ", "JNE ", "JNO ", "JOC ", "JOP ", "LDCR", "LI ", "LIMI",
|
||||
"LREX", "LWPI", "MOV ", "MOVB", "MPY ", "NEG ", "ORI ", "RSET", "RTWP", "S ",
|
||||
"SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ", "SOCB", "SRA ", "SRC ", "SRL ",
|
||||
"STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB", "TB ", "X ", "XOP ", "XOR ",
|
||||
"*int"
|
||||
};
|
||||
|
||||
typedef struct _tms99xx_config
|
||||
{
|
||||
devcb_write8 external_callback;
|
||||
devcb_read8 irq_level;
|
||||
@ -84,15 +101,19 @@ typedef struct _tms9900_config
|
||||
devcb_write_line clock_out;
|
||||
devcb_write_line wait_line;
|
||||
devcb_write_line holda_line;
|
||||
} tms9900_config;
|
||||
} tms99xx_config;
|
||||
|
||||
#define TMS9900_CONFIG(name) \
|
||||
const tms9900_config(name) =
|
||||
#define TMS99xx_CONFIG(name) \
|
||||
const tms99xx_config(name) =
|
||||
|
||||
class tms9900_device : public cpu_device
|
||||
class tms99xx_device : public cpu_device
|
||||
{
|
||||
public:
|
||||
tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
tms99xx_device(const machine_config &mconfig, device_type type, const char *name,
|
||||
const char *tag, int databus_width, int prg_addr_bits, int cru_addr_bits,
|
||||
device_t *owner, UINT32 clock);
|
||||
|
||||
~tms99xx_device();
|
||||
|
||||
// READY input line. When asserted (high), the memory is ready for data exchange.
|
||||
void set_ready(int state);
|
||||
@ -122,7 +143,23 @@ protected:
|
||||
|
||||
const address_space_config* memory_space_config(address_spacenum spacenum) const;
|
||||
|
||||
private:
|
||||
// Let these methods be overloaded by the TMS9980.
|
||||
virtual void mem_read(void);
|
||||
virtual void mem_write(void);
|
||||
virtual void acquire_instruction(void);
|
||||
void decode(UINT16 inst);
|
||||
|
||||
const address_space_config m_program_config;
|
||||
const address_space_config m_io_config;
|
||||
address_space* m_prgspace;
|
||||
address_space* m_cru;
|
||||
|
||||
virtual UINT16 read_workspace_register_debug(int reg);
|
||||
virtual void write_workspace_register_debug(int reg, UINT16 data);
|
||||
|
||||
// Cycle counter
|
||||
int m_icount;
|
||||
|
||||
// TMS9900 hardware registers
|
||||
UINT16 WP; // Workspace pointer
|
||||
UINT16 PC; // Program counter
|
||||
@ -131,38 +168,72 @@ private:
|
||||
// Internal register
|
||||
UINT16 IR; // Instruction register
|
||||
|
||||
// Stored address
|
||||
UINT16 m_address;
|
||||
|
||||
// Stores the recently read word or the word to be written
|
||||
UINT16 m_current_value;
|
||||
|
||||
// Decoded command
|
||||
UINT16 m_command;
|
||||
|
||||
// Issue clock pulses. Note that each machine cycle has two clock cycles.
|
||||
void pulse_clock(int count);
|
||||
|
||||
// For multi-pass operations. For instance, memory word accesses are
|
||||
// executed as two consecutive byte accesses. CRU accesses are repeated
|
||||
// single-bit accesses. (Needed for TMS9980)
|
||||
int m_pass;
|
||||
|
||||
// Data bus width. Needed for TMS9980.
|
||||
int m_databus_width;
|
||||
|
||||
// Needed for TMS9980
|
||||
bool m_lowbyte;
|
||||
|
||||
// Check the READY line?
|
||||
bool m_check_ready;
|
||||
|
||||
// Max address
|
||||
const UINT16 m_prgaddr_mask;
|
||||
const UINT16 m_cruaddr_mask;
|
||||
|
||||
bool m_load_state;
|
||||
bool m_irq_state;
|
||||
bool m_reset;
|
||||
|
||||
// Determine the interrupt level using the IC0-IC2/3 lines
|
||||
virtual int get_intlevel(int state);
|
||||
|
||||
// Interrupt level as acquired from input lines (TMS9900: IC0-IC3, TMS9980: IC0-IC2)
|
||||
// We assume all values right-justified, i.e. TMS9980 also counts up by one
|
||||
int m_irq_level;
|
||||
|
||||
// Used to display the number of consumed cycles in the log.
|
||||
int m_first_cycle;
|
||||
|
||||
// Signal to the outside world that we are now getting an instruction
|
||||
devcb_resolved_write_line m_iaq_line;
|
||||
|
||||
// Get the value of the interrupt level lines
|
||||
devcb_resolved_read8 m_get_intlevel;
|
||||
|
||||
private:
|
||||
// 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();
|
||||
@ -176,7 +247,7 @@ private:
|
||||
typedef const UINT8* microprogram;
|
||||
|
||||
// Method pointer
|
||||
typedef void (tms9900_device::*ophandler)(void);
|
||||
typedef void (tms99xx_device::*ophandler)(void);
|
||||
|
||||
// Opcode list entry
|
||||
typedef struct _tms_instruction
|
||||
@ -201,18 +272,16 @@ private:
|
||||
lookup_entry* m_lotables[32];
|
||||
|
||||
// List of pointers for micro-operations
|
||||
static const tms9900_device::ophandler s_microoperation[];
|
||||
static const tms99xx_device::ophandler s_microoperation[];
|
||||
|
||||
// Opcode table
|
||||
static const tms9900_device::tms_instruction s_command[];
|
||||
static const tms99xx_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 cru_input_operation(void);
|
||||
void cru_output_operation(void);
|
||||
void data_derivation_subprogram(void);
|
||||
void return_from_subprogram(void);
|
||||
void command_completed(void);
|
||||
@ -258,9 +327,6 @@ private:
|
||||
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;
|
||||
@ -278,27 +344,15 @@ private:
|
||||
// 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;
|
||||
|
||||
@ -308,6 +362,10 @@ private:
|
||||
// Intermediate storage for the source operand
|
||||
UINT16 m_source_address;
|
||||
UINT16 m_source_value;
|
||||
UINT16 m_address_saved;
|
||||
|
||||
// Another copy of the address
|
||||
UINT16 m_address_copy;
|
||||
|
||||
// Stores the recently read register contents
|
||||
UINT16 m_register_contents;
|
||||
@ -315,15 +373,15 @@ private:
|
||||
// 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;
|
||||
|
||||
// Copy of the value
|
||||
UINT16 m_value_copy;
|
||||
|
||||
// Another internal register, storing intermediate values
|
||||
// Using 32 bits to support MPY
|
||||
UINT32 m_value;
|
||||
@ -336,9 +394,6 @@ private:
|
||||
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
|
||||
@ -363,12 +418,6 @@ private:
|
||||
// chip emulations we use a dedicated callback.
|
||||
devcb_resolved_write8 m_external_operation;
|
||||
|
||||
// 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.
|
||||
@ -381,6 +430,15 @@ private:
|
||||
devcb_resolved_write_line m_holda_line;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
class tms9900_device : public tms99xx_device
|
||||
{
|
||||
public:
|
||||
tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
};
|
||||
|
||||
|
||||
unsigned Dasm9900(char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram);
|
||||
|
||||
// device type definition
|
||||
|
@ -1,4 +1,245 @@
|
||||
/*
|
||||
This file will contain the re-implementation of the tms9980a. The
|
||||
previous implementation can be found as tms9980al.
|
||||
Cycle-precise implementation of the TMS9980A.
|
||||
Subclassed from tms99xx_device in tms9900.c.
|
||||
|
||||
+----------------+
|
||||
/HOLD | 1 \/ 40| /MEMEN
|
||||
HOLDA | 2 39| READY
|
||||
IAQ | 3 38| /WE
|
||||
LSB +- A13,CRUOUT | 4 37| CRUCLK
|
||||
| A12 | 5 36| Vdd
|
||||
| A11 | 6 35| Vss
|
||||
| A10 | 7 34| CKIN
|
||||
Address A9 | 8 33| D7 --+
|
||||
bus A8 | 9 32| D6 |
|
||||
| A7 |10 31| D5 Data
|
||||
16KiB A6 |11 30| D4 bus
|
||||
| A5 |12 29| D3 |
|
||||
| A4 |13 28| D2 2 * 8 bit
|
||||
| A3 |14 27| D1 |
|
||||
| A2 |15 26| D0 --+
|
||||
| A1 |16 25| INT0 --+
|
||||
MSB +-- A0 |17 24| INT1 | Interrupt levels
|
||||
DBIN |18 23| INT2 --+
|
||||
CRUIN |19 22| /PHI3
|
||||
Vcc |20 21| Vbb
|
||||
+----------------+
|
||||
|
||||
The TMS9980A is similar to the TMS9900, with the following differences:
|
||||
|
||||
- Address bus is only 14 bit wide (16 KiB)
|
||||
- Data bus is 16 bit wide and multiplexed on 8 lines (2 bytes per access)
|
||||
- CRU space is limited to 2048 bits (due to fewer address lines)
|
||||
- Only three interrupt level lines, for a maximum of 8 levels.
|
||||
- No INTREQ, RESET, and LOAD lines. All interrupts are signaled via INT0 -
|
||||
INT2. Reset=00x, Load=010, Level1=011, Level2=100, Level3=101, Level4=110,
|
||||
all interrupts cleared=111.
|
||||
- Memory accesses are always 2 bytes (even address byte, odd address byte)
|
||||
even for byte operations. Thus the 9980A, like the TMS9900, needs to
|
||||
pre-fetch the word at the destination before overwriting it.
|
||||
- On the cycle level both TMS9900 and TMS9980A are equal, except for the
|
||||
additional cycles needed for memory read and write access. Accordingly,
|
||||
the emulation shares the core and the microprograms and redefines the
|
||||
memory access and the interrupt handling only.
|
||||
- The 9980A has the same external instructions as the TMS9900, but it
|
||||
indicates the command via A0, A1, and A13 (instead of A0-A2).
|
||||
|
||||
For pin definitions see tms9900.c
|
||||
|
||||
Michael Zapf, 2012
|
||||
*/
|
||||
|
||||
#include "tms9980a.h"
|
||||
|
||||
#define LOG logerror
|
||||
#define VERBOSE 1
|
||||
|
||||
/****************************************************************************
|
||||
Constructor
|
||||
****************************************************************************/
|
||||
|
||||
tms9980a_device::tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: tms99xx_device(mconfig, TMS9980A, "TMS9980A", tag, 8, 14, 11, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
UINT16 tms9980a_device::read_workspace_register_debug(int reg)
|
||||
{
|
||||
int temp = m_icount;
|
||||
int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask;
|
||||
UINT16 value = (m_prgspace->read_byte(addr) << 8) | (m_prgspace->read_byte(addr+1) & 0xff);
|
||||
m_icount = temp;
|
||||
return value;
|
||||
}
|
||||
|
||||
void tms9980a_device::write_workspace_register_debug(int reg, UINT16 data)
|
||||
{
|
||||
int temp = m_icount;
|
||||
int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask;
|
||||
m_prgspace->write_byte(addr, data>>8);
|
||||
m_prgspace->write_byte(addr+1, data & 0xff);
|
||||
m_icount = temp;
|
||||
}
|
||||
|
||||
/*
|
||||
Interrupt input. Keep in mind that the TMS9980A does not have any INTREQ
|
||||
line but signals interrupts via IC0-IC2 only. Thus we cannot take down any
|
||||
single interrupt; only all interrupts can be cleared at once using level 7.
|
||||
The state parameter is actually not needed.
|
||||
*/
|
||||
void tms9980a_device::execute_set_input(int irqline, int state)
|
||||
{
|
||||
m_irq_level = get_intlevel(state);
|
||||
|
||||
if (m_irq_level != 7)
|
||||
{
|
||||
if (m_irq_level == LOAD_INT)
|
||||
{
|
||||
// Clearing m_reset is a hack to prevent an initial RESET.
|
||||
// Should fix that in tms99xx
|
||||
m_reset = false;
|
||||
m_load_state = true;
|
||||
}
|
||||
else m_irq_state = true;
|
||||
if (VERBOSE>6) LOG("tms9980a: interrupt level=%d, ST=%04x\n", m_irq_level, ST);
|
||||
}
|
||||
}
|
||||
|
||||
int tms9980a_device::get_intlevel(int state)
|
||||
{
|
||||
int level = m_get_intlevel(0) & 0x0007;
|
||||
|
||||
// Just to stay consistent.
|
||||
if (state==CLEAR_LINE) level = 7;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
level = RESET_INT;
|
||||
m_reset = true;
|
||||
break;
|
||||
case 2:
|
||||
level = LOAD_INT;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
level = level - 2;
|
||||
break;
|
||||
case 7:
|
||||
// Clear all interrupts
|
||||
m_load_state = false;
|
||||
m_irq_state = false;
|
||||
if (VERBOSE>6) LOG("tms9980a: clear interrupts\n");
|
||||
break;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Memory read:
|
||||
Clock cycles: 4 + 2W, W = number of wait states
|
||||
*/
|
||||
void tms9980a_device::mem_read()
|
||||
{
|
||||
UINT8 value;
|
||||
if (m_lowbyte)
|
||||
{
|
||||
value = m_prgspace->read_byte((m_address & m_prgaddr_mask) | 1);
|
||||
m_current_value = m_current_value | (value & 0x00ff);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory read low byte %04x -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, m_current_value);
|
||||
m_lowbyte = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = m_prgspace->read_byte(m_address & 0x3ffe);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask, value);
|
||||
m_current_value = (value << 8) & 0xff00;
|
||||
m_lowbyte = true;
|
||||
m_pass = 2; // make the CPU visit this method once more
|
||||
}
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
}
|
||||
|
||||
void tms9980a_device::mem_write()
|
||||
{
|
||||
if (m_lowbyte)
|
||||
{
|
||||
m_prgspace->write_byte((m_address & 0x3ffe) | 1, m_current_value & 0xff);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff);
|
||||
m_lowbyte = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prgspace->write_byte(m_address & 0x3ffe, (m_current_value >> 8)&0xff);
|
||||
if (VERBOSE>7) LOG("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask, (m_current_value >> 8)&0xff);
|
||||
m_lowbyte = true;
|
||||
m_pass = 2; // make the CPU visit this method once more
|
||||
}
|
||||
pulse_clock(2);
|
||||
m_check_ready = true;
|
||||
}
|
||||
|
||||
void tms9980a_device::acquire_instruction()
|
||||
{
|
||||
if (!m_lowbyte)
|
||||
{
|
||||
m_iaq_line(ASSERT_LINE);
|
||||
m_address = PC;
|
||||
m_first_cycle = m_icount;
|
||||
mem_read();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_read();
|
||||
decode(m_current_value);
|
||||
if (VERBOSE>3) LOG("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC);
|
||||
debugger_instruction_hook(this, PC);
|
||||
PC = (PC + 2) & 0xfffe & m_prgaddr_mask;
|
||||
}
|
||||
// IAQ will be cleared in the main loop
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
UINT32 tms9980a_device::execute_min_cycles() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
// TODO: Compute this value, just a wild guess for the average
|
||||
UINT32 tms9980a_device::execute_max_cycles() const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
UINT32 tms9980a_device::execute_input_lines() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// clocks to cycles, cycles to clocks = id
|
||||
// execute_default_irq_vector = 0
|
||||
// execute_burn = nop
|
||||
|
||||
// device_disasm_interface overrides
|
||||
UINT32 tms9980a_device::disasm_min_opcode_bytes() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
UINT32 tms9980a_device::disasm_max_opcode_bytes() const
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
offs_t tms9980a_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
|
||||
{
|
||||
return Dasm9900(buffer, pc, TMS9980_ID, oprom, opram);
|
||||
}
|
||||
|
||||
const device_type TMS9980A = &device_creator<tms9980a_device>;
|
||||
|
54
src/emu/cpu/tms9900/tms9980a.h
Normal file
54
src/emu/cpu/tms9900/tms9980a.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
TMS9980A.
|
||||
|
||||
See tms9980a.c and tms9900.c for documentation
|
||||
*/
|
||||
|
||||
#ifndef __TMS9980A_H__
|
||||
#define __TMS9980A_H__
|
||||
|
||||
#include "emu.h"
|
||||
#include "debugger.h"
|
||||
#include "tms9900.h"
|
||||
|
||||
#define MCFG_TMS9980A_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)
|
||||
|
||||
#define TMS9980A_CONFIG(name) \
|
||||
const tms9900_config(name) =
|
||||
|
||||
|
||||
class tms9980a_device : public tms99xx_device
|
||||
{
|
||||
public:
|
||||
tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
protected:
|
||||
void mem_read(void);
|
||||
void mem_write(void);
|
||||
void acquire_instruction(void);
|
||||
|
||||
UINT16 read_workspace_register_debug(int reg);
|
||||
void write_workspace_register_debug(int reg, UINT16 data);
|
||||
|
||||
UINT32 execute_min_cycles() const;
|
||||
UINT32 execute_max_cycles() const;
|
||||
UINT32 execute_input_lines() const;
|
||||
void execute_set_input(int irqline, int state);
|
||||
|
||||
UINT32 disasm_min_opcode_bytes() const;
|
||||
UINT32 disasm_max_opcode_bytes() const;
|
||||
offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
||||
address_space_config m_program_config80;
|
||||
address_space_config m_io_config80;
|
||||
|
||||
int get_intlevel(int state);
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type TMS9980A;
|
||||
|
||||
#endif /* __TMS9995_H__ */
|
Loading…
Reference in New Issue
Block a user