mirror of
https://github.com/holub/mame
synced 2025-05-30 01:23:07 +03:00

*** This is required for Rise of the Robots, whose boot code jumps into the middle of the bootloader ROM. Changes tested with primrage, sfrush and speedup.
892 lines
24 KiB
C
892 lines
24 KiB
C
/***************************************************************************
|
|
|
|
tms32031.c
|
|
|
|
TMS32031/2 emulator
|
|
|
|
****************************************************************************
|
|
|
|
Copyright Aaron Giles
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the
|
|
distribution.
|
|
* Neither the name 'MAME' nor the names of its contributors may be
|
|
used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "debugger.h"
|
|
#include "tms32031.h"
|
|
|
|
|
|
//**************************************************************************
|
|
// CONSTANTS
|
|
//**************************************************************************
|
|
|
|
// indexes into the register file
|
|
enum
|
|
{
|
|
TMR_R0 = 0,
|
|
TMR_R1,
|
|
TMR_R2,
|
|
TMR_R3,
|
|
TMR_R4,
|
|
TMR_R5,
|
|
TMR_R6,
|
|
TMR_R7,
|
|
TMR_AR0,
|
|
TMR_AR1,
|
|
TMR_AR2,
|
|
TMR_AR3,
|
|
TMR_AR4,
|
|
TMR_AR5,
|
|
TMR_AR6,
|
|
TMR_AR7,
|
|
TMR_DP,
|
|
TMR_IR0,
|
|
TMR_IR1,
|
|
TMR_BK,
|
|
TMR_SP,
|
|
TMR_ST,
|
|
TMR_IE,
|
|
TMR_IF,
|
|
TMR_IOF,
|
|
TMR_RS,
|
|
TMR_RE,
|
|
TMR_RC,
|
|
TMR_R8, // 3204x only
|
|
TMR_R9, // 3204x only
|
|
TMR_R10, // 3204x only
|
|
TMR_R11, // 3204x only
|
|
TMR_TEMP1, // used by the interpreter
|
|
TMR_TEMP2, // used by the interpreter
|
|
TMR_TEMP3 // used by the interpreter
|
|
};
|
|
|
|
// flags
|
|
const int CFLAG = 0x0001;
|
|
const int VFLAG = 0x0002;
|
|
const int ZFLAG = 0x0004;
|
|
const int NFLAG = 0x0008;
|
|
const int UFFLAG = 0x0010;
|
|
const int LVFLAG = 0x0020;
|
|
const int LUFFLAG = 0x0040;
|
|
const int OVMFLAG = 0x0080;
|
|
const int RMFLAG = 0x0100;
|
|
const int CFFLAG = 0x0400;
|
|
const int CEFLAG = 0x0800;
|
|
const int CCFLAG = 0x1000;
|
|
const int GIEFLAG = 0x2000;
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// MACROS
|
|
//**************************************************************************
|
|
|
|
#define IREG(rnum) (m_r[rnum].i32[0])
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// GLOBAL VARIABLES
|
|
//**************************************************************************
|
|
|
|
// device type definition
|
|
const device_type TMS32031 = &device_creator<tms32031_device>;
|
|
const device_type TMS32032 = &device_creator<tms32032_device>;
|
|
|
|
|
|
// internal memory maps
|
|
static ADDRESS_MAP_START( internal_32031, AS_PROGRAM, 32, tms32031_device )
|
|
AM_RANGE(0x809800, 0x809fff) AM_RAM
|
|
ADDRESS_MAP_END
|
|
|
|
static ADDRESS_MAP_START( internal_32032, AS_PROGRAM, 32, tms32032_device )
|
|
AM_RANGE(0x87fe00, 0x87ffff) AM_RAM
|
|
ADDRESS_MAP_END
|
|
|
|
|
|
// ROM definitions for the internal boot loader programs
|
|
// (Using assembled versions until the code ROMs are extracted from both DSPs)
|
|
ROM_START( tms32031 )
|
|
ROM_REGION(0x4000, "tms32031", 0)
|
|
ROM_LOAD( "c31boot.bin", 0x0000, 0x4000, BAD_DUMP CRC(bddc2763) SHA1(96b2170ecee5bec5abaa1741bb2d3b6096ecc262) ) // Assembled from c31boot.asm (02-07-92)
|
|
ROM_END
|
|
|
|
ROM_START( tms32032 )
|
|
ROM_REGION(0x4000, "tms32032", 0)
|
|
ROM_LOAD( "c32boot.bin", 0x0000, 0x4000, BAD_DUMP CRC(ecf84729) SHA1(4d32ead450f921f563514b061ea561a222283616) ) // Assembled from c32boot.asm (03-04-96)
|
|
ROM_END
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// TMSREG REGISTER
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// as_float - interpret the contents of a tmsreg
|
|
// as a DSP-encoded floating-point value, and
|
|
// extract a 32-bit IEEE float from it
|
|
//-------------------------------------------------
|
|
|
|
float tms3203x_device::tmsreg::as_float() const
|
|
{
|
|
int_double id;
|
|
|
|
// map 0 to 0
|
|
if (mantissa() == 0 && exponent() == -128)
|
|
return 0;
|
|
|
|
// handle positive numbers
|
|
else if (mantissa() >= 0)
|
|
{
|
|
int exp = (exponent() + 127) << 23;
|
|
id.i[0] = exp + (mantissa() >> 8);
|
|
}
|
|
|
|
// handle negative numbers
|
|
else
|
|
{
|
|
int exp = (exponent() + 127) << 23;
|
|
INT32 man = -mantissa();
|
|
id.i[0] = 0x80000000 + exp + ((man >> 8) & 0x00ffffff);
|
|
}
|
|
|
|
// return the converted float
|
|
return id.f[0];
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// as_double - interpret the contents of a tmsreg
|
|
// as a DSP-encoded floating-point value, and
|
|
// extract a 64-bit IEEE double from it
|
|
//-------------------------------------------------
|
|
|
|
double tms3203x_device::tmsreg::as_double() const
|
|
{
|
|
int_double id;
|
|
|
|
// map 0 to 0
|
|
if (mantissa() == 0 && exponent() == -128)
|
|
return 0;
|
|
|
|
// handle positive numbers
|
|
else if (mantissa() >= 0)
|
|
{
|
|
int exp = (exponent() + 1023) << 20;
|
|
id.i[BYTE_XOR_BE(0)] = exp + (mantissa() >> 11);
|
|
id.i[BYTE_XOR_BE(1)] = (mantissa() << 21) & 0xffe00000;
|
|
}
|
|
|
|
// handle negative numbers
|
|
else
|
|
{
|
|
int exp = (exponent() + 1023) << 20;
|
|
INT32 man = -mantissa();
|
|
id.i[BYTE_XOR_BE(0)] = 0x80000000 + exp + ((man >> 11) & 0x001fffff);
|
|
id.i[BYTE_XOR_BE(1)] = (man << 21) & 0xffe00000;
|
|
}
|
|
|
|
// return the converted double
|
|
return id.d;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// from_double - import a 64-bit IEEE double into
|
|
// the DSP's internal floating point format
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::tmsreg::from_double(double val)
|
|
{
|
|
// extract mantissa and exponent from the IEEE input
|
|
int_double id;
|
|
id.d = val;
|
|
INT32 mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21);
|
|
INT32 exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023;
|
|
|
|
// if we're too small, map to 0
|
|
if (exponent < -128)
|
|
{
|
|
set_mantissa(0);
|
|
set_exponent(-128);
|
|
}
|
|
|
|
// if we're too large, map to the maximum value
|
|
else if (exponent > 127)
|
|
{
|
|
if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
|
|
set_mantissa(0x7fffffff);
|
|
else
|
|
set_mantissa(0x80000001);
|
|
set_exponent(127);
|
|
}
|
|
|
|
// if we're positive, map directly
|
|
else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
|
|
{
|
|
set_mantissa(mantissa);
|
|
set_exponent(exponent);
|
|
}
|
|
|
|
// if we're negative with a non-zero mantissa, remove the leading sign bit
|
|
else if (mantissa != 0)
|
|
{
|
|
set_mantissa(0x80000000 | -mantissa);
|
|
set_exponent(exponent);
|
|
}
|
|
|
|
// if we're negative with a zero mantissa, normalize
|
|
else
|
|
{
|
|
set_mantissa(0x80000000);
|
|
set_exponent(exponent - 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// DEVICE INTERFACE
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// tms3203x_device - constructor
|
|
//-------------------------------------------------
|
|
|
|
tms3203x_device::tms3203x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, address_map_constructor internal_map)
|
|
: cpu_device(mconfig, type, name, tag, owner, clock),
|
|
m_program_config("program", ENDIANNESS_LITTLE, 32, 24, -2, internal_map),
|
|
m_chip_type(chiptype),
|
|
m_pc(0),
|
|
m_bkmask(0),
|
|
m_irq_state(0),
|
|
m_delayed(false),
|
|
m_irq_pending(false),
|
|
m_is_idling(false),
|
|
m_icount(0),
|
|
m_irq_callback(0),
|
|
m_program(0),
|
|
m_direct(0)
|
|
{
|
|
m_mcbl_mode = false;
|
|
m_xf0_w = NULL;
|
|
m_xf1_w = NULL;
|
|
m_iack_w = NULL;
|
|
|
|
// initialize remaining state
|
|
memset(&m_r, 0, sizeof(m_r));
|
|
|
|
// set our instruction counter
|
|
m_icountptr = &m_icount;
|
|
|
|
#if (TMS_3203X_LOG_OPCODE_USAGE)
|
|
memset(m_hits, 0, sizeof(m_hits));
|
|
#endif
|
|
}
|
|
|
|
tms32031_device::tms32031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
: tms3203x_device(mconfig, TMS32031, "TMS32031", tag, owner, clock, CHIP_TYPE_TMS32031, ADDRESS_MAP_NAME(internal_32031))
|
|
{
|
|
m_shortname = "tms32031";
|
|
}
|
|
|
|
tms32032_device::tms32032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
: tms3203x_device(mconfig, TMS32032, "TMS32032", tag, owner, clock, CHIP_TYPE_TMS32032, ADDRESS_MAP_NAME(internal_32032))
|
|
{
|
|
m_shortname = "tms32032";
|
|
}
|
|
|
|
|
|
DIRECT_UPDATE_MEMBER( tms3203x_device::direct_handler )
|
|
{
|
|
// internal boot loader ROM
|
|
if (m_mcbl_mode && address < (0x1000 << 2))
|
|
{
|
|
direct.explicit_configure(0x000000, 0x003fff, 0x003fff, m_bootrom);
|
|
return (offs_t)-1;
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// ~tms3203x_device - destructor
|
|
//-------------------------------------------------
|
|
|
|
tms3203x_device::~tms3203x_device()
|
|
{
|
|
#if (TMS_3203X_LOG_OPCODE_USAGE)
|
|
for (int i = 0; i < ARRAY_LENGTH(m_hits); i++)
|
|
if (m_hits[i] != 0)
|
|
printf("%10d - %03X.%X\n", m_hits[i], i / 4, i % 4);
|
|
#endif
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// static_set_config - set the configuration
|
|
// structure
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::static_set_config(device_t &device, const tms3203x_config &config)
|
|
{
|
|
tms3203x_device &tms = downcast<tms3203x_device &>(device);
|
|
static_cast<tms3203x_config &>(tms) = config;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rom_region - return a pointer to the device's
|
|
// internal ROM region
|
|
//-------------------------------------------------
|
|
|
|
const rom_entry *tms3203x_device::device_rom_region() const
|
|
{
|
|
switch (m_chip_type)
|
|
{
|
|
default:
|
|
case CHIP_TYPE_TMS32031: return ROM_NAME( tms32031 );
|
|
case CHIP_TYPE_TMS32032: return ROM_NAME( tms32032 );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// ROPCODE - fetch an opcode
|
|
//-------------------------------------------------
|
|
|
|
inline UINT32 tms3203x_device::ROPCODE(offs_t pc)
|
|
{
|
|
return m_direct->read_decrypted_dword(pc << 2);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// RMEM - read memory
|
|
//-------------------------------------------------
|
|
|
|
inline UINT32 tms3203x_device::RMEM(offs_t addr)
|
|
{
|
|
if (m_mcbl_mode && addr < 0x1000)
|
|
return m_bootrom[addr];
|
|
|
|
return m_program->read_dword(addr << 2);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// WMEM - write memory
|
|
//-------------------------------------------------
|
|
|
|
inline void tms3203x_device::WMEM(offs_t addr, UINT32 data)
|
|
{
|
|
m_program->write_dword(addr << 2, data);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_start - start up the device
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::device_start()
|
|
{
|
|
// find address spaces
|
|
m_program = &space(AS_PROGRAM);
|
|
m_direct = &m_program->direct();
|
|
|
|
// set up the internal boot loader ROM
|
|
m_bootrom = reinterpret_cast<UINT32*>(memregion(m_shortname)->base());
|
|
m_direct->set_direct_update(direct_update_delegate(FUNC(tms3203x_device::direct_handler), this));
|
|
|
|
// save state
|
|
save_item(NAME(m_pc));
|
|
for (int regnum = 0; regnum < 36; regnum++)
|
|
save_item(NAME(m_r[regnum].i32), regnum);
|
|
save_item(NAME(m_bkmask));
|
|
save_item(NAME(m_irq_state));
|
|
save_item(NAME(m_delayed));
|
|
save_item(NAME(m_irq_pending));
|
|
save_item(NAME(m_is_idling));
|
|
|
|
// register our state for the debugger
|
|
state_add(TMS3203X_PC, "PC", m_pc);
|
|
state_add(STATE_GENPC, "GENPC", m_pc).noshow();
|
|
state_add(STATE_GENFLAGS, "GENFLAGS", m_r[TMR_ST].i32[0]).mask(0xff).noshow().formatstr("%8s");
|
|
state_add(TMS3203X_R0, "R0", m_r[TMR_R0].i32[0]);
|
|
state_add(TMS3203X_R1, "R1", m_r[TMR_R1].i32[0]);
|
|
state_add(TMS3203X_R2, "R2", m_r[TMR_R2].i32[0]);
|
|
state_add(TMS3203X_R3, "R3", m_r[TMR_R3].i32[0]);
|
|
state_add(TMS3203X_R4, "R4", m_r[TMR_R4].i32[0]);
|
|
state_add(TMS3203X_R5, "R5", m_r[TMR_R5].i32[0]);
|
|
state_add(TMS3203X_R6, "R6", m_r[TMR_R6].i32[0]);
|
|
state_add(TMS3203X_R7, "R7", m_r[TMR_R7].i32[0]);
|
|
state_add(TMS3203X_R0F, "R0F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R1F, "R1F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R2F, "R2F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R3F, "R3F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R4F, "R4F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R5F, "R5F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R6F, "R6F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_R7F, "R7F", m_iotemp).callimport().callexport().formatstr("%12s");
|
|
state_add(TMS3203X_AR0, "AR0", m_r[TMR_AR0].i32[0]);
|
|
state_add(TMS3203X_AR1, "AR1", m_r[TMR_AR1].i32[0]);
|
|
state_add(TMS3203X_AR2, "AR2", m_r[TMR_AR2].i32[0]);
|
|
state_add(TMS3203X_AR3, "AR3", m_r[TMR_AR3].i32[0]);
|
|
state_add(TMS3203X_AR4, "AR4", m_r[TMR_AR4].i32[0]);
|
|
state_add(TMS3203X_AR5, "AR5", m_r[TMR_AR5].i32[0]);
|
|
state_add(TMS3203X_AR6, "AR6", m_r[TMR_AR6].i32[0]);
|
|
state_add(TMS3203X_AR7, "AR7", m_r[TMR_AR7].i32[0]);
|
|
state_add(TMS3203X_DP, "DP", m_r[TMR_DP].i32[0]).mask(0xff);
|
|
state_add(TMS3203X_IR0, "IR0", m_r[TMR_IR0].i32[0]);
|
|
state_add(TMS3203X_IR1, "IR1", m_r[TMR_IR1].i32[0]);
|
|
state_add(TMS3203X_BK, "BK", m_r[TMR_BK].i32[0]);
|
|
state_add(TMS3203X_SP, "SP", m_r[TMR_SP].i32[0]);
|
|
state_add(TMS3203X_ST, "ST", m_r[TMR_ST].i32[0]);
|
|
state_add(TMS3203X_IE, "IE", m_r[TMR_IE].i32[0]);
|
|
state_add(TMS3203X_IF, "IF", m_r[TMR_IF].i32[0]);
|
|
state_add(TMS3203X_IOF, "IOF", m_r[TMR_IOF].i32[0]);
|
|
state_add(TMS3203X_RS, "RS", m_r[TMR_RS].i32[0]);
|
|
state_add(TMS3203X_RE, "RE", m_r[TMR_RE].i32[0]);
|
|
state_add(TMS3203X_RC, "RC", m_r[TMR_RC].i32[0]);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_reset - reset the device
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::device_reset()
|
|
{
|
|
m_pc = RMEM(0);
|
|
|
|
// reset some registers
|
|
IREG(TMR_IE) = 0;
|
|
IREG(TMR_IF) = 0;
|
|
IREG(TMR_ST) = 0;
|
|
IREG(TMR_IOF) = 0;
|
|
|
|
// update IF with the external interrupt state (required for boot loader operation)
|
|
IREG(TMR_IF) |= m_irq_state & 0x0f;
|
|
|
|
// reset internal stuff
|
|
m_delayed = m_irq_pending = m_is_idling = false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// memory_space_config - return the configuration
|
|
// of the specified address space, or NULL if
|
|
// the space doesn't exist
|
|
//-------------------------------------------------
|
|
|
|
const address_space_config *tms3203x_device::memory_space_config(address_spacenum spacenum) const
|
|
{
|
|
return (spacenum == AS_PROGRAM) ? &m_program_config : NULL;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// state_import - import state into the device,
|
|
// after it has been set
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::state_import(const device_state_entry &entry)
|
|
{
|
|
switch (entry.index())
|
|
{
|
|
case TMS3203X_R0F:
|
|
case TMS3203X_R1F:
|
|
case TMS3203X_R2F:
|
|
case TMS3203X_R3F:
|
|
case TMS3203X_R4F:
|
|
case TMS3203X_R5F:
|
|
case TMS3203X_R6F:
|
|
case TMS3203X_R7F:
|
|
m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].from_double(*(float *)&m_iotemp);
|
|
break;
|
|
|
|
default:
|
|
fatalerror("CPU_IMPORT_STATE(tms3203x) called for unexpected value\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// state_export - export state into the device,
|
|
// before returning it to the caller
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::state_export(const device_state_entry &entry)
|
|
{
|
|
switch (entry.index())
|
|
{
|
|
case TMS3203X_R0F:
|
|
case TMS3203X_R1F:
|
|
case TMS3203X_R2F:
|
|
case TMS3203X_R3F:
|
|
case TMS3203X_R4F:
|
|
case TMS3203X_R5F:
|
|
case TMS3203X_R6F:
|
|
case TMS3203X_R7F:
|
|
*(float *)&m_iotemp = m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].as_float();
|
|
break;
|
|
|
|
default:
|
|
fatalerror("CPU_IMPORT_STATE(tms3203x) called for unexpected value\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// state_string_export - export state as a string
|
|
// for the debugger
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::state_string_export(const device_state_entry &entry, astring &string)
|
|
{
|
|
switch (entry.index())
|
|
{
|
|
case TMS3203X_R0F:
|
|
case TMS3203X_R1F:
|
|
case TMS3203X_R2F:
|
|
case TMS3203X_R3F:
|
|
case TMS3203X_R4F:
|
|
case TMS3203X_R5F:
|
|
case TMS3203X_R6F:
|
|
case TMS3203X_R7F:
|
|
string.printf("%12g", m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].as_double());
|
|
break;
|
|
|
|
case STATE_GENFLAGS:
|
|
UINT32 temp = m_r[TMR_ST].i32[0];
|
|
string.printf("%c%c%c%c%c%c%c%c",
|
|
(temp & 0x80) ? 'O':'.',
|
|
(temp & 0x40) ? 'U':'.',
|
|
(temp & 0x20) ? 'V':'.',
|
|
(temp & 0x10) ? 'u':'.',
|
|
(temp & 0x08) ? 'n':'.',
|
|
(temp & 0x04) ? 'z':'.',
|
|
(temp & 0x02) ? 'v':'.',
|
|
(temp & 0x01) ? 'c':'.');
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// disasm_min_opcode_bytes - return the length
|
|
// of the shortest instruction, in bytes
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::disasm_min_opcode_bytes() const
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// disasm_max_opcode_bytes - return the length
|
|
// of the longest instruction, in bytes
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::disasm_max_opcode_bytes() const
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// disasm_disassemble - call the disassembly
|
|
// helper function
|
|
//-------------------------------------------------
|
|
|
|
offs_t tms3203x_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
|
|
{
|
|
extern CPU_DISASSEMBLE( tms3203x );
|
|
return CPU_DISASSEMBLE_NAME(tms3203x)(NULL, buffer, pc, oprom, opram, 0);
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// PUBLIC INTERFACES
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// fp_to_float - convert a 32-bit value from DSP
|
|
// floating-point format a 32-bit IEEE float
|
|
//-------------------------------------------------
|
|
|
|
float tms3203x_device::fp_to_float(UINT32 floatdata)
|
|
{
|
|
tmsreg gen(floatdata << 8, (INT32)floatdata >> 24);
|
|
return gen.as_float();
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// fp_to_double - convert a 32-bit value from DSP
|
|
// floating-point format a 64-bit IEEE double
|
|
//-------------------------------------------------
|
|
|
|
double tms3203x_device::fp_to_double(UINT32 floatdata)
|
|
{
|
|
tmsreg gen(floatdata << 8, (INT32)floatdata >> 24);
|
|
return gen.as_double();
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// float_to_fp - convert a 32-bit IEEE float to
|
|
// a 32-bit DSP floating-point value
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::float_to_fp(float fval)
|
|
{
|
|
tmsreg gen(fval);
|
|
return (gen.exponent() << 24) | ((UINT32)gen.mantissa() >> 8);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// double_to_fp - convert a 64-bit IEEE double to
|
|
// a 32-bit DSP floating-point value
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::double_to_fp(double dval)
|
|
{
|
|
tmsreg gen(dval);
|
|
return (gen.exponent() << 24) | ((UINT32)gen.mantissa() >> 8);
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// EXECUTION
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// check_irqs - check for pending IRQs and take
|
|
// them if enabled
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::check_irqs()
|
|
{
|
|
// determine if we have any live interrupts
|
|
UINT16 validints = IREG(TMR_IF) & IREG(TMR_IE) & 0x0fff;
|
|
if (validints == 0 || (IREG(TMR_ST) & GIEFLAG) == 0)
|
|
return;
|
|
|
|
// find the lowest signalled value
|
|
int whichtrap = 0;
|
|
for (int i = 0; i < 12; i++)
|
|
if (validints & (1 << i))
|
|
{
|
|
whichtrap = i + 1;
|
|
break;
|
|
}
|
|
|
|
// no longer idling if we get here
|
|
m_is_idling = false;
|
|
if (!m_delayed)
|
|
{
|
|
UINT16 intmask = 1 << (whichtrap - 1);
|
|
|
|
// bit in IF is cleared when interrupt is taken
|
|
IREG(TMR_IF) &= ~intmask;
|
|
trap(whichtrap);
|
|
|
|
// after auto-clearing the interrupt bit, we need to re-trigger
|
|
// level-sensitive interrupts
|
|
if (m_chip_type == CHIP_TYPE_TMS32031 || (IREG(TMR_ST) & 0x4000) == 0)
|
|
IREG(TMR_IF) |= m_irq_state & 0x0f;
|
|
}
|
|
else
|
|
m_irq_pending = true;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// execute_min_cycles - return minimum number of
|
|
// cycles it takes for one instruction to execute
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::execute_min_cycles() const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// execute_max_cycles - return maximum number of
|
|
// cycles it takes for one instruction to execute
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::execute_max_cycles() const
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// execute_input_lines - return the number of
|
|
// input/interrupt lines
|
|
//-------------------------------------------------
|
|
|
|
UINT32 tms3203x_device::execute_input_lines() const
|
|
{
|
|
return (m_chip_type == CHIP_TYPE_TMS32032) ? 13 : 12;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// execute_set_input - set input and IRQ lines
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::execute_set_input(int inputnum, int state)
|
|
{
|
|
// ignore anything out of range
|
|
if (inputnum >= 13)
|
|
return;
|
|
|
|
if (inputnum == TMS3203X_MCBL)
|
|
{
|
|
// switch between microcomputer/boot loader and microprocessor modes
|
|
m_mcbl_mode = (state == ASSERT_LINE);
|
|
m_direct->force_update();
|
|
return;
|
|
}
|
|
|
|
// update the external state
|
|
UINT16 intmask = 1 << inputnum;
|
|
if (state == ASSERT_LINE)
|
|
{
|
|
m_irq_state |= intmask;
|
|
IREG(TMR_IF) |= intmask;
|
|
}
|
|
else
|
|
m_irq_state &= ~intmask;
|
|
|
|
// external interrupts are level-sensitive on the '31 and can be
|
|
// configured as such on the '32; in that case, if the external
|
|
// signal is high, we need to update the value in IF accordingly
|
|
if (m_chip_type == CHIP_TYPE_TMS32031 || (IREG(TMR_ST) & 0x4000) == 0)
|
|
IREG(TMR_IF) |= m_irq_state & 0x0f;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// execute_run - execute until our icount expires
|
|
//-------------------------------------------------
|
|
|
|
void tms3203x_device::execute_run()
|
|
{
|
|
// check IRQs up front
|
|
check_irqs();
|
|
|
|
// if we're idling, just eat the cycles
|
|
if (m_is_idling)
|
|
{
|
|
m_icount = 0;
|
|
return;
|
|
}
|
|
|
|
// non-debug case
|
|
if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0)
|
|
{
|
|
while (m_icount > 0)
|
|
{
|
|
if ((IREG(TMR_ST) & RMFLAG) && m_pc == IREG(TMR_RE) + 1)
|
|
{
|
|
if ((INT32)--IREG(TMR_RC) >= 0)
|
|
m_pc = IREG(TMR_RS);
|
|
else
|
|
{
|
|
IREG(TMR_ST) &= ~RMFLAG;
|
|
if (m_delayed)
|
|
{
|
|
m_delayed = false;
|
|
if (m_irq_pending)
|
|
{
|
|
m_irq_pending = false;
|
|
check_irqs();
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
execute_one();
|
|
}
|
|
}
|
|
|
|
// debugging case
|
|
else
|
|
{
|
|
while (m_icount > 0)
|
|
{
|
|
// watch for out-of-range stack pointers
|
|
if (IREG(TMR_SP) & 0xff000000)
|
|
debugger_break(machine());
|
|
if ((IREG(TMR_ST) & RMFLAG) && m_pc == IREG(TMR_RE) + 1)
|
|
{
|
|
if ((INT32)--IREG(TMR_RC) >= 0)
|
|
m_pc = IREG(TMR_RS);
|
|
else
|
|
{
|
|
IREG(TMR_ST) &= ~RMFLAG;
|
|
if (m_delayed)
|
|
{
|
|
m_delayed = false;
|
|
if (m_irq_pending)
|
|
{
|
|
m_irq_pending = false;
|
|
check_irqs();
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
debugger_instruction_hook(this, m_pc);
|
|
execute_one();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
// CORE OPCODES
|
|
//**************************************************************************
|
|
|
|
#include "32031ops.c"
|