Added internal boot loader programs to the TMS3203x core and support a switch between microcomputer (bootloader) and microprocessor modes via the TMS3203X_MCBL input [Phil Bennett]

***

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.
This commit is contained in:
Phil Bennett 2012-11-24 10:48:17 +00:00
parent 3ea4845b77
commit a93919643d
6 changed files with 87 additions and 89 deletions

View File

@ -5693,8 +5693,6 @@ void tms3203x_device::trap(int trapnum)
IREG(TMR_ST) &= ~GIEFLAG;
if (m_chip_type == CHIP_TYPE_TMS32032)
m_pc = RMEM(((IREG(TMR_IF) >> 16) << 8) + trapnum);
else if (m_mcu_mode)
m_pc = 0x809fc0 + trapnum;
else
m_pc = RMEM(trapnum);
m_icount -= 4*2;

View File

@ -119,16 +119,30 @@ const int GIEFLAG = 0x2000;
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, legacy_cpu_device )
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, legacy_cpu_device )
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
@ -275,14 +289,13 @@ tms3203x_device::tms3203x_device(const machine_config &mconfig, device_type type
m_irq_state(0),
m_delayed(false),
m_irq_pending(false),
m_mcu_mode(false),
m_is_idling(false),
m_icount(0),
m_irq_callback(0),
m_program(0),
m_direct(0)
{
m_bootoffset = 0;
m_mcbl_mode = false;
m_xf0_w = NULL;
m_xf1_w = NULL;
m_iack_w = NULL;
@ -299,10 +312,29 @@ tms3203x_device::tms3203x_device(const machine_config &mconfig, device_type type
}
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)) { }
: 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)) { }
: 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;
}
//-------------------------------------------------
@ -331,6 +363,21 @@ void tms3203x_device::static_set_config(device_t &device, const tms3203x_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
//-------------------------------------------------
@ -347,6 +394,9 @@ inline UINT32 tms3203x_device::ROPCODE(offs_t pc)
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);
}
@ -371,6 +421,10 @@ void tms3203x_device::device_start()
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++)
@ -379,7 +433,6 @@ void tms3203x_device::device_start()
save_item(NAME(m_irq_state));
save_item(NAME(m_delayed));
save_item(NAME(m_irq_pending));
save_item(NAME(m_mcu_mode));
save_item(NAME(m_is_idling));
// register our state for the debugger
@ -431,17 +484,7 @@ void tms3203x_device::device_start()
void tms3203x_device::device_reset()
{
// if we have a config struct, get the boot ROM address
if (m_bootoffset != 0)
{
m_mcu_mode = true;
m_pc = boot_loader(m_bootoffset);
}
else
{
m_mcu_mode = false;
m_pc = RMEM(0);
}
m_pc = RMEM(0);
// reset some registers
IREG(TMR_IE) = 0;
@ -449,6 +492,9 @@ void tms3203x_device::device_reset()
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;
}
@ -718,7 +764,7 @@ UINT32 tms3203x_device::execute_max_cycles() const
UINT32 tms3203x_device::execute_input_lines() const
{
return 11;
return (m_chip_type == CHIP_TYPE_TMS32032) ? 13 : 12;
}
@ -729,9 +775,17 @@ UINT32 tms3203x_device::execute_input_lines() const
void tms3203x_device::execute_set_input(int inputnum, int state)
{
// ignore anything out of range
if (inputnum >= 12)
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)
@ -830,67 +884,6 @@ void tms3203x_device::execute_run()
}
//-------------------------------------------------
// boot_loader - reset the state of the system
// by simulating the internal boot loader
//-------------------------------------------------
UINT32 tms3203x_device::boot_loader(UINT32 boot_rom_addr)
{
// read the size of the data
UINT32 bits = RMEM(boot_rom_addr);
if (bits != 8 && bits != 16 && bits != 32)
return 0;
UINT32 datamask = 0xffffffffUL >> (32 - bits);
UINT32 advance = 32 / bits;
boot_rom_addr += advance;
// read the control register
UINT32 control = RMEM(boot_rom_addr++) & datamask;
for (int i = 1; i < advance; i++)
control |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
// now parse the data
UINT32 start_offset = 0;
bool first = true;
while (1)
{
// read the length of this section
UINT32 len = RMEM(boot_rom_addr++) & datamask;
for (int i = 1; i < advance; i++)
len |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
// stop at 0
if (len == 0)
return start_offset;
// read the destination offset of this section
UINT32 offs = RMEM(boot_rom_addr++) & datamask;
for (int i = 1; i < advance; i++)
offs |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
// if this is the first block, that's where we boot to
if (first)
{
start_offset = offs;
first = false;
}
// now copy the data
while (len--)
{
// extract the 32-bit word
UINT32 data = RMEM(boot_rom_addr++) & datamask;
for (int i = 1; i < advance; i++)
data |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);
// write it out
WMEM(offs++, data);
}
}
}
//**************************************************************************
// CORE OPCODES
//**************************************************************************

View File

@ -69,6 +69,7 @@ const int TMS3203X_TINT1 = 9; // timer 1 interrupt
const int TMS3203X_DINT = 10; // DMA interrupt
const int TMS3203X_DINT0 = 10; // DMA 0 interrupt (32032 only)
const int TMS3203X_DINT1 = 11; // DMA 1 interrupt (32032 only)
const int TMS3203X_MCBL = 12; // Microcomputer/boot loader mode
// register enumeration
enum
@ -138,7 +139,7 @@ typedef void (*tms3203x_iack_func)(tms3203x_device &device, UINT8 val, offs_t ad
struct tms3203x_config
{
UINT32 m_bootoffset;
bool m_mcbl_mode;
tms3203x_xf_func m_xf0_w;
tms3203x_xf_func m_xf1_w;
tms3203x_iack_func m_iack_w;
@ -201,6 +202,8 @@ protected:
virtual void device_start();
virtual void device_reset();
virtual const rom_entry *device_rom_region() const;
// device_execute_interface overrides
virtual UINT32 execute_min_cycles() const;
virtual UINT32 execute_max_cycles() const;
@ -222,13 +225,13 @@ protected:
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
// memory helpers
DECLARE_DIRECT_UPDATE_MEMBER(direct_handler);
UINT32 ROPCODE(offs_t pc);
UINT32 RMEM(offs_t addr);
void WMEM(offs_t addr, UINT32 data);
// misc helpers
void check_irqs();
UINT32 boot_loader(UINT32 boot_rom_addr);
void execute_one();
void update_special(int dreg);
bool condition(int which);
@ -798,7 +801,6 @@ protected:
UINT16 m_irq_state;
bool m_delayed;
bool m_irq_pending;
bool m_mcu_mode;
bool m_is_idling;
int m_icount;
@ -806,6 +808,7 @@ protected:
device_irq_acknowledge_callback m_irq_callback;
address_space * m_program;
direct_read_data * m_direct;
UINT32 * m_bootrom;
// tables
static void (tms3203x_device::*const s_tms32031ops[])(UINT32 op);

View File

@ -603,6 +603,7 @@ void cage_control_w(running_machine &machine, UINT16 data)
if (!(state->control & 3))
{
state->cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
state->cpu->set_input_line(TMS3203X_IRQ1, ASSERT_LINE);
state->dma_enabled = 0;
state->dma_timer_enabled = 0;
@ -619,7 +620,10 @@ void cage_control_w(running_machine &machine, UINT16 data)
state->cage_to_cpu_ready = 0;
}
else
{
state->cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
state->cpu->set_input_line(TMS3203X_IRQ1, CLEAR_LINE);
}
/* update the control state */
update_control_lines(machine);
@ -651,7 +655,7 @@ static WRITE32_HANDLER( speedup_w )
static const tms3203x_config cage_config =
{
0x400000
true
};

View File

@ -980,7 +980,7 @@ static const adsp21xx_config adsp_config =
static const tms3203x_config tms_config =
{
0x1000,
true,
0,
0,
iack_w

View File

@ -496,7 +496,7 @@ static ADDRESS_MAP_START( midvunit_map, AS_PROGRAM, 32, midvunit_state )
ADDRESS_MAP_END
static const tms3203x_config midvplus_config = { 0, NULL, midvplus_xf1_w };
static const tms3203x_config midvplus_config = { false, NULL, midvplus_xf1_w };
static ADDRESS_MAP_START( midvplus_map, AS_PROGRAM, 32, midvunit_state )
AM_RANGE(0x000000, 0x01ffff) AM_RAM AM_SHARE("ram_base")