mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
Original Supermodel code moved to tags/Original.
This commit is contained in:
parent
74d1cec9b8
commit
187c62d3b1
492
core/bridge.c
492
core/bridge.c
|
@ -1,492 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* bridge.c
|
||||
*
|
||||
* MPC105 and MPC106 PCI bridge/memory controller emulation.
|
||||
*
|
||||
* Warning: Portability hazard. Code assumes it is running on a little endian
|
||||
* machine.
|
||||
*
|
||||
* NOTE: Data written to the bridge controller is byte-reversed by the PPC.
|
||||
* This is to make it little endian.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
/******************************************************************/
|
||||
/* Internal Bridge State */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Macros for Register Access
|
||||
*
|
||||
* Assuming a little endian system (portability hazard!)
|
||||
*/
|
||||
|
||||
#define DWORD(addr) *((UINT32 *) ®s[addr])
|
||||
#define WORD(addr) *((UINT16 *) ®s[addr])
|
||||
#define BYTE(addr) regs[addr]
|
||||
|
||||
/*
|
||||
* Bridge State
|
||||
*
|
||||
* This code is intended for use on little-endian systems. Data from the
|
||||
* registers should be returned as if a big endian read was performed (thus
|
||||
* returning the little endian word 0x1057 as 0x5710.)
|
||||
*
|
||||
* The DWORD() and WORD() macros only work on little endian systems and are
|
||||
* intended to set up the bridge state. Reads and writes using the handlers
|
||||
* are done in big endian fashion by manually breaking down the data into
|
||||
* bytes.
|
||||
*
|
||||
* To make this code fully portable, it would probably be enough to remove
|
||||
* the DWORD() and WORD() macros.
|
||||
*/
|
||||
|
||||
static UINT8 regs[0x100];
|
||||
static UINT8 config_data[4]; // data for last CONFIG_ADDR command
|
||||
static UINT32 reg_ptr; // current register address
|
||||
|
||||
/******************************************************************/
|
||||
/* Interface */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Callback for Bus Commands
|
||||
*
|
||||
* Note that there are no callbacks for reads/writes to CONFIG_DATA yet as
|
||||
* the need for them has not yet appeared.
|
||||
*/
|
||||
|
||||
static UINT32 (*config_addr_callback)(UINT32);
|
||||
|
||||
/*
|
||||
* UINT8 bridge_read_8(UINT32 addr);
|
||||
*
|
||||
* Reads directly from a register. The lower 8 bits of the address are the
|
||||
* register to read from. This is intended for the MPC105 which can map its
|
||||
* internal registers to 0xF8FFF0xx.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT8 bridge_read_8(UINT32 addr)
|
||||
{
|
||||
LOG("model3.log", "RB REG%02X\n", addr & 0xff);
|
||||
|
||||
return BYTE(addr & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT16 bridge_read_16(UINT32 addr);
|
||||
*
|
||||
* Reads directly from a register. The lower 8 bits of the address are the
|
||||
* register to read from. This is intended for the MPC105 which can map its
|
||||
* internal registers to 0xF8FFF0xx.
|
||||
*
|
||||
* Bit 0 is masked off to ensure 16-bit alignment (I'm not sure how a real
|
||||
* PCIBMC would handle this.)
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT16 bridge_read_16(UINT32 addr)
|
||||
{
|
||||
LOG("model3.log", "RH REG%02X\n", addr & 0xff);
|
||||
addr &= 0xfe;
|
||||
return (BYTE(addr + 0) << 8) | BYTE(addr + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT32 bridge_read_32(UINT32 addr);
|
||||
*
|
||||
* Reads directly from a register. The lower 8 bits of the address are the
|
||||
* register to read from. This is intended for the MPC105 which can map its
|
||||
* internal registers to 0xF8FFF0xx.
|
||||
*
|
||||
* The lower 2 bits are masked off to ensure 32-bit alignment.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT32 bridge_read_32(UINT32 addr)
|
||||
{
|
||||
LOG("model3.log", "RW REG%02X\n", addr & 0xff);
|
||||
addr &= 0xfc;
|
||||
return (BYTE(addr + 0) << 24) | (BYTE(addr + 1) << 16) |
|
||||
(BYTE(addr + 2) << 8) | BYTE(addr + 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_8(UINT32 addr, UINT8 data);
|
||||
*
|
||||
* Writes directly to a register. Only the lower 8 bits matter. This is
|
||||
* intended for the MPC105.
|
||||
*
|
||||
* Arguments:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_8(UINT32 addr, UINT8 data)
|
||||
{
|
||||
LOG("model3.log", "REG%02X=%02X\n", addr & 0xff, data);
|
||||
BYTE(addr & 0xff) = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_16(UINT32 addr, UINT16 data);
|
||||
*
|
||||
* Writes directly to a register. Only the lower 8 bits matter. This is
|
||||
* intended for the MPC105.
|
||||
*
|
||||
* Bit 0 is masked off to ensure 16-bit alignment.
|
||||
*
|
||||
* Arguments:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_16(UINT32 addr, UINT16 data)
|
||||
{
|
||||
LOG("model3.log", "REG%02X=%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff);
|
||||
addr &= 0xfe;
|
||||
BYTE(addr + 0) = data >> 8;
|
||||
BYTE(addr + 1) = (UINT8) data;
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_32(UINT32 addr, UINT32 data);
|
||||
*
|
||||
* Writes directly to a register. Only the lower 8 bits matter. This is
|
||||
* intended for the MPC105.
|
||||
*
|
||||
* The lower 2 bits are masked off to ensure 32-bit alignment.
|
||||
*
|
||||
* Arguments:
|
||||
* addr = Address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_32(UINT32 addr, UINT32 data)
|
||||
{
|
||||
LOG("model3.log", "REG%02X=%02X%02X%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff);
|
||||
addr &= 0xfc;
|
||||
BYTE(addr + 0) = data >> 24;
|
||||
BYTE(addr + 1) = data >> 16;
|
||||
BYTE(addr + 2) = data >> 8;
|
||||
BYTE(addr + 3) = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT8 bridge_read_config_data_8(UINT32 addr);
|
||||
*
|
||||
* Reads from CONFIG_DATA offset 0 to 3. Only the lower 2 bits of the address
|
||||
* are checked to determine which byte to read. I'm not sure whether this is
|
||||
* correct behavior (perhaps all byte offsets return the same data.)
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address to read from (only lower 2 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT8 bridge_read_config_data_8(UINT32 addr)
|
||||
{
|
||||
return config_data[addr & 3];
|
||||
// return BYTE(reg_ptr + (addr & 3));
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT16 bridge_read_config_data_16(UINT32 addr);
|
||||
*
|
||||
* Reads from CONFIG_DATA offset 0 or 2. Only bit 1 of the address is checked
|
||||
* to determine which word to read. I'm not sure whether this is correct
|
||||
* behavior for word reads (both words might return the same data, for
|
||||
* example.)
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address to read from (only bit 1 matters.)
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT16 bridge_read_config_data_16(UINT32 addr)
|
||||
{
|
||||
return (config_data[(addr & 2) + 0] << 8) | config_data[(addr & 2) + 1];
|
||||
// return (BYTE(reg_ptr + (addr & 2) + 0) << 8) |
|
||||
// BYTE(reg_ptr + (addr & 2) + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT32 bridge_read_config_data_32(UINT32 addr);
|
||||
*
|
||||
* Reads from CONFIG_DATA. The address argument is ignored because it is
|
||||
* assumed that this function is only called for valid CONFIG_DATA addresses.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Ignored.
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT32 bridge_read_config_data_32(UINT32 addr)
|
||||
{
|
||||
LOG("model3.log", "%08X: READ CONFIG DATA\n", ppc_get_pc());
|
||||
return (config_data[0] << 24) | (config_data[1] << 16) |
|
||||
(config_data[2] << 8) | config_data[3];
|
||||
// return (BYTE(reg_ptr + 0) << 24) | (BYTE(reg_ptr + 1) << 16) |
|
||||
// (BYTE(reg_ptr + 2) << 8) | BYTE(reg_ptr + 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_config_addr_32(UINT32 addr, UINT32 data);
|
||||
*
|
||||
* Writes to CONFIG_ADDR. The address argument is ignored because it is
|
||||
* assumed that this function is only called for valid CONFIG_ADDR addresses.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Ignored.
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_config_addr_32(UINT32 addr, UINT32 data)
|
||||
{
|
||||
UINT32 callback_data;
|
||||
|
||||
/*
|
||||
* I'm not sure how the bridge controller distinguishes between indirect
|
||||
* register accesses and accesses which must be passed to some device on
|
||||
* the PCI bus.
|
||||
*
|
||||
* Currently, I test to see if the command is of the format 0x800000XX,
|
||||
* and if so, I return put register data in the return buffer
|
||||
* (config_data), otherwise I invoke the callback.
|
||||
*/
|
||||
|
||||
|
||||
// LOG("model3.log", "CONFIG_ADDR=%02X%02X%02X%02X @ %08X", data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
|
||||
// reg_ptr = data >> 24; // remember, data comes in little endian form
|
||||
// // see page 3-15 of MPC106UM/D REV.1
|
||||
|
||||
if ((data & 0x00ffffff) == 0x00000080) // indirect register access (little endian data, see page 3-15 of MPC106UM/D REV.1)
|
||||
{
|
||||
reg_ptr = data >> 24;
|
||||
config_data[0] = BYTE(reg_ptr + 0);
|
||||
config_data[1] = BYTE(reg_ptr + 1);
|
||||
config_data[2] = BYTE(reg_ptr + 2);
|
||||
config_data[3] = BYTE(reg_ptr + 3);
|
||||
}
|
||||
else // pass it to the callback
|
||||
{
|
||||
if (config_addr_callback != NULL)
|
||||
{
|
||||
callback_data = config_addr_callback(BSWAP32(data));
|
||||
callback_data = BSWAP32(callback_data); // so we can return as little endian
|
||||
}
|
||||
else
|
||||
callback_data = 0xFFFFFFFF;
|
||||
|
||||
config_data[0] = callback_data >> 24;
|
||||
config_data[1] = callback_data >> 16;
|
||||
config_data[2] = callback_data >> 8;
|
||||
config_data[3] = callback_data;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_config_data_8(UINT32 addr, UINT8 data);
|
||||
*
|
||||
* Writes to CONFIG_DATA. The lower 2 bits determine which byte offset to
|
||||
* write to.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address to write to (only lower 2 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_config_data_8(UINT32 addr, UINT8 data)
|
||||
{
|
||||
// LOG("model3.log", "CONFIG_DATA=%02X @ %08X", data, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
|
||||
BYTE(reg_ptr + (addr & 3)) = data;
|
||||
config_data[addr & 3] = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_config_data_16(UINT32 addr, UINT16 data);
|
||||
*
|
||||
* Writes to CONFIG_DATA. Only bit 1 of the address is checked to determine
|
||||
* which word to write to.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Address to write to (only bit 1 matters.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_config_data_16(UINT32 addr, UINT16 data)
|
||||
{
|
||||
BYTE(reg_ptr + (addr & 2) + 0) = data >> 8;
|
||||
BYTE(reg_ptr + (addr & 2) + 1) = (UINT8) data;
|
||||
config_data[(addr & 2) + 0] = data >> 8;
|
||||
config_data[(addr & 2) + 1] = (UINT8) data;
|
||||
// LOG("model3.log", "CONFIG_DATA=%04X @ %08X", WORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_write_config_data_32(UINT32 addr, UINT32 data);
|
||||
*
|
||||
* Writes to CONFIG_DATA. The address argument is ignored because it is
|
||||
* assumed that this function is only called for valid CONFIG_DATA addresses.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Ignored.
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void bridge_write_config_data_32(UINT32 addr, UINT32 data)
|
||||
{
|
||||
BYTE(reg_ptr + 0) = data >> 24;
|
||||
BYTE(reg_ptr + 1) = data >> 16;
|
||||
BYTE(reg_ptr + 2) = data >> 8;
|
||||
BYTE(reg_ptr + 3) = data;
|
||||
config_data[0] = data >> 24;
|
||||
config_data[1] = data >> 16;
|
||||
config_data[2] = data >> 8;
|
||||
config_data[3] = data;
|
||||
// LOG("model3.log", "CONFIG_DATA=%08X @ %08X", DWORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC));
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the bridge controller state by writing it out to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to write to.
|
||||
*/
|
||||
|
||||
void bridge_save_state(FILE *fp)
|
||||
{
|
||||
fwrite(regs, sizeof(UINT8), 0x100, fp);
|
||||
fwrite(config_data, sizeof(UINT8), 4, fp);
|
||||
fwrite(®_ptr, sizeof(UINT32), 1, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the bridge controller state by reading it in from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to read from.
|
||||
*/
|
||||
|
||||
void bridge_load_state(FILE *fp)
|
||||
{
|
||||
fread(regs, sizeof(UINT8), 0x100, fp);
|
||||
fread(config_data, sizeof(UINT8), 4, fp);
|
||||
fread(®_ptr, sizeof(UINT32), 1, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_reset(INT device);
|
||||
*
|
||||
* Initializes the bridge controller's internal state.
|
||||
*
|
||||
* Memory control configuration 1 is to be set to 0xFFn20000, where n is data
|
||||
* sampled from signals sent by hardware to the MPC105 (see the MPC105
|
||||
* manual.) For Model 3, I'm guessing that n == 0.
|
||||
*
|
||||
* Parameters:
|
||||
* device = Device ID of the bridge to emulate (1 = MPC105, 2 = MPC106.)
|
||||
* If it is not one of these values, behavior is undefined.
|
||||
*/
|
||||
|
||||
void bridge_reset(INT device)
|
||||
{
|
||||
if (device == 1)
|
||||
LOG("model3.log", "Using MPC105\n");
|
||||
else if (device == 2)
|
||||
LOG("model3.log", "Using MPC106\n");
|
||||
else
|
||||
LOG("model3.log", "ERROR: Unknown bridge controller device ID (%d)\n", device);
|
||||
|
||||
memset(regs, 0, sizeof(UINT8) * 0x100);
|
||||
memset(config_data, 0, sizeof(UINT8) * 4);
|
||||
reg_ptr = 0;
|
||||
|
||||
/*
|
||||
* Set up common fields
|
||||
*/
|
||||
|
||||
WORD(0x00) = 0x1057; // vendor ID (Motorola)
|
||||
WORD(0x02) = device; // device ID
|
||||
WORD(0x04) = 0x0006; // PCI command
|
||||
WORD(0x06) = 0x0080; // PCI status
|
||||
BYTE(0x08) = 0x00; // revision ID (?)
|
||||
BYTE(0x0b) = 0x06; // class code
|
||||
DWORD(0xa8) = 0xff000010; // processor interface configuration 1
|
||||
DWORD(0xac) = 0x000c060c; // processor interface configuration 2
|
||||
BYTE(0xba) = 0x04; // alternate OS-visible parameters 1
|
||||
BYTE(0xc0) = 0x01; // error enabling 1
|
||||
DWORD(0xf0) = 0xff020000; // memory control configuration 1
|
||||
DWORD(0xf4) = 0x00000003; // memory control configuration 2
|
||||
DWORD(0xfc) = 0x00100000; // memory control configuration 4
|
||||
|
||||
/*
|
||||
* Additional settings for MPC106
|
||||
*/
|
||||
|
||||
if (device == 2) // MPC106
|
||||
{
|
||||
BYTE(0x0c) = 0x08; // cache line size
|
||||
BYTE(0x73) = 0xcd; // output driver control
|
||||
DWORD(0xe0) = 0x0fff0042; // emulation support configuration 1
|
||||
DWORD(0xe8) = 0x00000020; // emulation support configuration 2
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32));
|
||||
*
|
||||
* Initializes the bridge controller by setting up the CONFIG_ADDR callback.
|
||||
* bridge_reset() must still be used to put the controller in a usable (reset)
|
||||
* state.
|
||||
*/
|
||||
|
||||
void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32))
|
||||
{
|
||||
config_addr_callback = config_addr_callback_ptr;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* bridge.h
|
||||
*
|
||||
* MPC105 and MPC106 PCI bridge/memory controller header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_BRIDGE_H
|
||||
#define INCLUDED_BRIDGE_H
|
||||
|
||||
extern UINT8 bridge_read_8(UINT32);
|
||||
extern UINT16 bridge_read_16(UINT32);
|
||||
extern UINT32 bridge_read_32(UINT32);
|
||||
extern void bridge_write_8(UINT32, UINT8);
|
||||
extern void bridge_write_16(UINT32, UINT16);
|
||||
extern void bridge_write_32(UINT32, UINT32);
|
||||
|
||||
extern UINT8 bridge_read_config_data_8(UINT32);
|
||||
extern UINT16 bridge_read_config_data_16(UINT32);
|
||||
extern UINT32 bridge_read_config_data_32(UINT32);
|
||||
extern void bridge_write_config_addr_32(UINT32, UINT32);
|
||||
extern void bridge_write_config_data_8(UINT32, UINT8);
|
||||
extern void bridge_write_config_data_16(UINT32, UINT16);
|
||||
extern void bridge_write_config_data_32(UINT32, UINT32);
|
||||
|
||||
extern void bridge_save_state(FILE *);
|
||||
extern void bridge_load_state(FILE *);
|
||||
|
||||
extern void bridge_reset(INT);
|
||||
extern void bridge_init(UINT32 (*)(UINT32));
|
||||
|
||||
#endif // INCLUDED_BRIDGE_H
|
||||
|
292
core/controls.c
292
core/controls.c
|
@ -1,292 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//TODO: In controls_write(): Is EEPROM only written when bank_select = 1?
|
||||
// This makes little sense because banking affects reg 4 only, right?
|
||||
// Also, should EEPROM reads only be performed when bank_select=1?
|
||||
|
||||
/*
|
||||
* controls.c
|
||||
*
|
||||
* Control emulation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lost World Gun Notes:
|
||||
* ---------------------
|
||||
*
|
||||
* MCU Command Reg = 0x24 (byte)
|
||||
* MCU Arg Reg = 0x28 (byte)
|
||||
*
|
||||
* Procedure for issuing commands:
|
||||
* 1. Arg written first, then command.
|
||||
* 2. Waits on reg 0x34 (see Stefano's post to model3 group for details.)
|
||||
* 3. Reads a byte from 0x2C, then a byte from 0x30.
|
||||
*
|
||||
* Command 0x00: Set address (in arg reg.)
|
||||
* Command 0x87: Read gun data.
|
||||
*
|
||||
* Virtual On 2 Notes:
|
||||
* -------------------
|
||||
*
|
||||
* Control Area Offset 0x08: Lever 1, LRUD??TS (T = Turbo, S = Shot Trigger)
|
||||
* 0x0C: Lever 2
|
||||
* 0x18: Dipswitch, bits 7-0 = DS1-8
|
||||
*
|
||||
* Dipswitch bit 0x20 (DS3) should be cleared otherwise some test is performed
|
||||
* by Virtual On 2 at boot-up.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
/******************************************************************/
|
||||
/* Privates */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Register Set
|
||||
*/
|
||||
|
||||
static UINT8 controls_reg[0x40];
|
||||
static UINT8 controls_reg_bank[2];
|
||||
static BOOL controls_bank_select;
|
||||
|
||||
/*
|
||||
* Gun Data
|
||||
*
|
||||
* Gun data is read by communicating with the MCU. An address is passed and
|
||||
* some data is read back. The total number of data bytes that the MCU stores
|
||||
* and can address is unknown, but I assume 16 (Stefano: Is this correct?)
|
||||
*
|
||||
* Here is how gun data is stored:
|
||||
*
|
||||
* Offset 0: player 1 gun X position, lower 8 bits
|
||||
* 1: player 1 gun X position, upper 3 bits
|
||||
* 2: player 1 gun Y position, lower 8 bits
|
||||
* 3: player 1 gun Y position, upper 3 bits
|
||||
* 4: player 2 gun X position, lower 8 bits
|
||||
* 5: player 2 gun X position, upper 3 bits
|
||||
* 6: player 2 gun Y position, lower 8 bits
|
||||
* 7: player 2 gun Y position, upper 3 bits
|
||||
* 8: bit 0 = player 1 gun position status (0=aquired 1=lost)
|
||||
* bit 1 = player 2 gun position status (0=aquired 1=lost)
|
||||
*
|
||||
* I think Stefano also said that the X and Y may be reversed and that the gun
|
||||
* coordinates are only 10 bits, not 11.
|
||||
*/
|
||||
|
||||
static UINT8 gun_data[16];
|
||||
static int gun_data_ptr; // which address within gun_data[]
|
||||
|
||||
|
||||
static UINT8 analog_axis[8];
|
||||
static int analog_control = 0; // Currently used register
|
||||
|
||||
/******************************************************************/
|
||||
/* Interface */
|
||||
/******************************************************************/
|
||||
|
||||
void controls_shutdown(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void controls_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void controls_reset(UINT32 flags)
|
||||
{
|
||||
memset(controls_reg_bank, 0xFF, 2);
|
||||
memset(controls_reg, 0xFF, 0x40);
|
||||
memset(controls_reg, 0x00, 8);
|
||||
|
||||
// controls_reg[0x18] = 0xDF; // clear bit 0x20 for Virtual On 2
|
||||
controls_reg[0x18] = 0xff;
|
||||
}
|
||||
|
||||
void controls_update(void)
|
||||
{
|
||||
int i;
|
||||
OSD_CONTROLS *c;
|
||||
UINT gun_x, gun_y;
|
||||
|
||||
c = osd_input_update_controls();
|
||||
|
||||
controls_reg_bank[0] = c->system_controls[0];
|
||||
controls_reg_bank[1] = c->system_controls[1];
|
||||
|
||||
controls_reg[0x08] = c->game_controls[0];
|
||||
controls_reg[0x0C] = c->game_controls[1];
|
||||
|
||||
/*
|
||||
* TEMP: This should be changed so that only games with guns have this
|
||||
* updated
|
||||
*/
|
||||
|
||||
/*
|
||||
* Gun Coordinates:
|
||||
*
|
||||
* Coordinates returned by the MCU are sight position coordinates. The OSD
|
||||
* input code returns coordinates in the range of (0,0)-(485,383).
|
||||
*
|
||||
* X adjustment: 400 must be added to the sight position in order to
|
||||
* locate the gun at screen X = 0.
|
||||
*
|
||||
* Y adjustment: Sight coordinate 0 maps to screen coordinate 272. Sight
|
||||
* coordinate 272 maps to screen coordinate 0. Sight coordinate 383 maps
|
||||
* to -111.
|
||||
*/
|
||||
|
||||
gun_y = c->gun_y[0];
|
||||
// if (gun_y <= 272)
|
||||
// gun_y = 272 - gun_y;
|
||||
// else
|
||||
gun_x = c->gun_x[0];// + 400;
|
||||
gun_data[0] = gun_y & 0xFF;
|
||||
gun_data[1] = (gun_y >> 8) & 7;
|
||||
gun_data[2] = gun_x & 0xFF;
|
||||
gun_data[3] = (gun_x >> 8) & 7;
|
||||
|
||||
gun_y = c->gun_y[1];
|
||||
gun_x = c->gun_x[1] + 400;
|
||||
gun_data[4] = gun_y & 0xFF;
|
||||
gun_data[5] = (gun_y >> 8) & 7;
|
||||
gun_data[6] = gun_x & 0xFF;
|
||||
gun_data[7] = (gun_x >> 8) & 7;
|
||||
|
||||
gun_data[8] = (!!c->gun_acquired[0]) | ((!!c->gun_acquired[1]) << 1);
|
||||
|
||||
// Steering Wheel controls
|
||||
// Register 0: Steering wheel, 0x80 is center
|
||||
// Register 1: Acceleration, 0x00 - 0xFF
|
||||
// Register 2: Brake, 0x00 - 0xFF
|
||||
// Registers 3 - 7 are either unused or unknown
|
||||
|
||||
for (i=0; i < 8; i++)
|
||||
{
|
||||
analog_axis[i] = c->analog_axis[i] & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void controls_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the controls to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void controls_save_state(FILE *fp)
|
||||
{
|
||||
fwrite(controls_reg, sizeof(UINT8), 0x40, fp);
|
||||
fwrite(controls_reg_bank, sizeof(UINT8), 2, fp);
|
||||
fwrite(&controls_bank_select, sizeof(BOOL), 1, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void controls_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the controls from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void controls_load_state(FILE *fp)
|
||||
{
|
||||
fread(controls_reg, sizeof(UINT8), 0x40, fp);
|
||||
fread(controls_reg_bank, sizeof(UINT8), 2, fp);
|
||||
fread(&controls_bank_select, sizeof(BOOL), 1, fp);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Access */
|
||||
/******************************************************************/
|
||||
|
||||
/* these are only 8-bit wide, byte-aligned */
|
||||
/* additional data/address adjustement must be performed by the main handler */
|
||||
|
||||
UINT8 controls_read(UINT32 a)
|
||||
{
|
||||
a &= 0x3F;
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0x4:
|
||||
{
|
||||
// should this only be done when bank_select = 1?
|
||||
controls_reg_bank[1] &= ~0x20; // clear data bit before ORing it in
|
||||
controls_reg_bank[1] |= (eeprom_read_bit() & 1) << 5;
|
||||
return controls_reg_bank[controls_bank_select];
|
||||
}
|
||||
case 0x3C:
|
||||
{
|
||||
// I don't know if the register to be read can be selected.
|
||||
UINT8 analog_data = analog_axis[analog_control & 0x7];
|
||||
analog_control++;
|
||||
|
||||
return analog_data;
|
||||
}
|
||||
}
|
||||
|
||||
// LOG("model3.log", "CTRL %02X READ\n", a);
|
||||
|
||||
return controls_reg[a];
|
||||
}
|
||||
|
||||
void controls_write(UINT32 a, UINT8 d)
|
||||
{
|
||||
a &= 0x3F;
|
||||
controls_reg[a] = d;
|
||||
|
||||
switch(a)
|
||||
{
|
||||
case 0x0:
|
||||
{
|
||||
controls_bank_select = d & 1;
|
||||
// if(controls_bank_select == 1)
|
||||
{
|
||||
eeprom_set_clk((d & 0x80) ? 1 : 0);
|
||||
eeprom_set_ce((d & 0x40) ? 1 : 0);
|
||||
eeprom_set_data((d & 0x20) ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x24: // MCU command
|
||||
{
|
||||
switch (d)
|
||||
{
|
||||
case 0x00: // set address for gun data (it's already in the arg reg)
|
||||
gun_data_ptr = controls_reg[0x28] & 0xF;
|
||||
break;
|
||||
|
||||
case 0x87: // read data back from gun
|
||||
controls_reg[0x2c] = 0; // unused?
|
||||
controls_reg[0x30] = gun_data[gun_data_ptr];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// LOG("model3.log", "CTRL%02X = %02X\n", a, d);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* controls.h
|
||||
*
|
||||
* Controls header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_CONTROLS_H
|
||||
#define INCLUDED_CONTROLS_H
|
||||
|
||||
extern void controls_init(void);
|
||||
extern void controls_shutdown(void);
|
||||
extern void controls_reset(UINT32 flags);
|
||||
|
||||
extern void controls_update(void);
|
||||
|
||||
extern void controls_save_state(FILE *);
|
||||
extern void controls_load_state(FILE *);
|
||||
|
||||
extern UINT8 controls_read(UINT32 a);
|
||||
extern void controls_write(UINT32 a, UINT8 d);
|
||||
|
||||
#endif // INCLUDED_CONTROLS_H
|
||||
|
371
core/dma.c
371
core/dma.c
|
@ -1,371 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* dma.c
|
||||
*
|
||||
* Step 2.0+ DMA device emulation. We're unsure whether or not this is a SCSI
|
||||
* controller; it appears to only be used for its DMA capabilities and is
|
||||
* thought to be a Sega custom part.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 0xC2000000 32-bit -W DMA Source
|
||||
* 0xC2000004 32-bit -W DMA Destination
|
||||
* 0xC2000008 32-bit -W DMA Length (in words)
|
||||
* 0xC200000C 8-bit RW DMA Status? AxxxxxxB (A and B must be cleared)
|
||||
* 0xC200000D 8-bit -W DMA Control? xxxxxxx? (bit0 clears C200000C bit0)
|
||||
* 0xC200000E 8-bit -W DMA Config?
|
||||
* 0xC2000010 32-bit -W DMA Command? (Written, result appears at 0x14)
|
||||
* 0xC2000014 32-bit R- DMA Command Result
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
/******************************************************************/
|
||||
/* Private Variables */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Registers
|
||||
*/
|
||||
|
||||
static UINT8 dma_regs[0x20];
|
||||
|
||||
/*
|
||||
* Read/Write Handlers
|
||||
*
|
||||
* These are used as an interface to the rest of the system.
|
||||
*/
|
||||
|
||||
static UINT32 (*read_32)(UINT32);
|
||||
static void (*write_32)(UINT32, UINT32);
|
||||
|
||||
/******************************************************************/
|
||||
/* DMA Transfer */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* do_dma():
|
||||
*
|
||||
* Performs a DMA transfer. The paramaters are expected to be in the
|
||||
* appropriate registers.
|
||||
*/
|
||||
|
||||
#ifdef _PROFILE_
|
||||
extern UINT is_dma;
|
||||
#endif
|
||||
|
||||
static void do_dma(void)
|
||||
{
|
||||
UINT32 src, dest, len;
|
||||
|
||||
PROFILE_SECT_ENTRY("dma");
|
||||
|
||||
#ifdef _PROFILE_
|
||||
is_dma = 1;
|
||||
#endif
|
||||
|
||||
src = *(UINT32 *) &dma_regs[0x00];
|
||||
dest = *(UINT32 *) &dma_regs[0x04];
|
||||
len = (*(UINT32 *) &dma_regs[0x08]) * 4;
|
||||
|
||||
LOG("model3.log", "DMA %08X -> %08X, %X\n", src, dest, len);
|
||||
|
||||
if ((dma_regs[0x0E] & 0x80)) // swap words
|
||||
{
|
||||
/*while (len)
|
||||
{
|
||||
write_32(dest, BSWAP32(read_32(src)));
|
||||
src += 4;
|
||||
dest += 4;
|
||||
len -= 4;
|
||||
}*/
|
||||
|
||||
model3_dma_transfer(src, dest, len, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*while (len)
|
||||
{
|
||||
write_32(dest, read_32(src));
|
||||
src += 4;
|
||||
dest += 4;
|
||||
len -= 4;
|
||||
}*/
|
||||
|
||||
model3_dma_transfer(src, dest, len, FALSE);
|
||||
}
|
||||
|
||||
#ifdef _PROFILE_
|
||||
is_dma = 0;
|
||||
#endif
|
||||
|
||||
*(UINT32 *) &dma_regs[0x08] = 0; // not sure if this is necessary
|
||||
|
||||
/*
|
||||
* An IRQ may be generated by the DMA device after a copy is performed (or
|
||||
* at some other time.)
|
||||
*
|
||||
* Evidence for this is in Harley Davidson's ISR. The subroutine at 0x8ABE8
|
||||
* appears to check the status register bit 0 and performs a copy if it is
|
||||
* set (after first clearing it.)
|
||||
*
|
||||
* Here, bit 0 is set, an IRQ is triggered, and the code will clear bit 0 by
|
||||
* writing a 1 to bit 0 of DMA reg 0xD.
|
||||
*/
|
||||
|
||||
dma_regs[0x0C] |= 1; // this bit may indicate IRQ raised
|
||||
ppc_set_irq_line(1);
|
||||
|
||||
PROFILE_SECT_EXIT("dma");
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Interface */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* void dma_shutdown(void);
|
||||
*
|
||||
* Shuts down the DMA device emulation.
|
||||
*/
|
||||
|
||||
void dma_shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32));
|
||||
*
|
||||
* Initializes the DMA device emulation by setting the memory access handlers.
|
||||
*
|
||||
* Parameters:
|
||||
* read32 = Handler to use for 32-bit reads.
|
||||
* write32 = Handler to use for 32-bit writes.
|
||||
*/
|
||||
|
||||
void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32))
|
||||
{
|
||||
read_32 = read32;
|
||||
write_32 = write32;
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_reset(void);
|
||||
*
|
||||
* Resets the DMA device.
|
||||
*/
|
||||
|
||||
void dma_reset(void)
|
||||
{
|
||||
memset(dma_regs, 0, 0x20);
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the DMA device (for Step 2.0 or higher games only) to a
|
||||
* file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void dma_save_state(FILE *fp)
|
||||
{
|
||||
if (m3_config.step < 0x20)
|
||||
return;
|
||||
fwrite(dma_regs, sizeof(UINT8), 0x20, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the DMA device (for Step 2.0 or higher games only) from
|
||||
* a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void dma_load_state(FILE *fp)
|
||||
{
|
||||
if (m3_config.step < 0x20)
|
||||
return;
|
||||
fread(dma_regs, sizeof(UINT8), 0x20, fp);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Access */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* UINT8 dma_read_8(UINT32 a);
|
||||
*
|
||||
* Reads a byte from the DMA device.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT8 dma_read_8(UINT32 a)
|
||||
{
|
||||
// message(0, "%08X: Unknown DMA read8, %08X", PPC_PC, a);
|
||||
|
||||
return dma_regs[a & 0x1F];
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT32 dma_read_32(UINT32 a);
|
||||
*
|
||||
* Reads a word from the DMA device.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT32 dma_read_32(UINT32 a)
|
||||
{
|
||||
// message(0, "%08X: Unknown DMA read32, %08X", PPC_PC, a);
|
||||
|
||||
return BSWAP32(*(UINT32 *) &dma_regs[a & 0x1F]);
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_write_8(UINT32 a, UINT8 d);
|
||||
*
|
||||
* Writes a byte to the DMA device.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
* d = Data to write.
|
||||
*/
|
||||
|
||||
void dma_write_8(UINT32 a, UINT8 d)
|
||||
{
|
||||
dma_regs[a & 0x1F] = d;
|
||||
|
||||
switch (a & 0x1F)
|
||||
{
|
||||
case 0xD:
|
||||
if ((d & 1)) // clear status bit 0
|
||||
dma_regs[0xC] &= ~1;
|
||||
break;
|
||||
default:
|
||||
LOG("model3.log", "%08X: Unknown DMA write8, %08X = %02X\n", ppc_get_pc(), a, d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_write_16(UINT32 a, UINT16 d);
|
||||
*
|
||||
* Writes a half-word to the DMA device.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
* d = Data to write.
|
||||
*/
|
||||
|
||||
void dma_write_16(UINT32 a, UINT16 d)
|
||||
{
|
||||
switch (a & 0x1F)
|
||||
{
|
||||
case 0x14:
|
||||
message(0, "%08X = %04X", a, d);
|
||||
LOG("model3.log", "DMA %08X = %04X\n", a, d);
|
||||
break;
|
||||
default:
|
||||
error("unknown DMA write: %08X = %04X", a, d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void dma_write_32(UINT32 a, UINT32 d);
|
||||
*
|
||||
* Writes a word to the DMA device.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
* d = Data to write.
|
||||
*/
|
||||
|
||||
void dma_write_32(UINT32 a, UINT32 d)
|
||||
{
|
||||
d = BSWAP32(d); // this is a little endian device, only bswap here once
|
||||
|
||||
*(UINT32 *) &dma_regs[a & 0x1F] = d;
|
||||
|
||||
switch (a & 0x1F)
|
||||
{
|
||||
case 0x00: // DMA Source
|
||||
// message(0, "DMA SRC = %08X", d);
|
||||
return;
|
||||
case 0x04: // DMA Destination
|
||||
// message(0, "DMA DST = %08X", d);
|
||||
return;
|
||||
case 0x08: // DMA Length
|
||||
// message(0, "DMA LEN = %X", d * 4);
|
||||
do_dma();
|
||||
return;
|
||||
case 0x10: // DMA Command
|
||||
|
||||
/*
|
||||
* Virtual On 2 has been observed to write commands to reg 0x10 and
|
||||
* then expects particular values back from 0x14.
|
||||
*
|
||||
* Command 0x80000000 is a little strange. It is issued and twice and
|
||||
* each time, a bit of the result is expected to be different. This
|
||||
* is crudely simulated by flipping a bit.
|
||||
*
|
||||
* Virtua Striker 2 '99 does something similar, except that it writes
|
||||
* commands 0x80000000, 0x80000004, ... 0x80000020.
|
||||
*/
|
||||
|
||||
if (d & 0x20000000)
|
||||
*(UINT32 *) &dma_regs[0x14] = 0x178611db; //0x16C311DB; // PCI Vendor and Device ID
|
||||
else if ((d & 0x80000000))
|
||||
*(UINT32 *) &dma_regs[0x14] = r3d_read_32((d & 0xFF) | 0x84000000);
|
||||
#if 0
|
||||
else if (d == 0x80000000)
|
||||
{
|
||||
static UINT32 result = 0x02000000;
|
||||
result ^= 0x02000000;
|
||||
*(UINT32 *) &dma_regs[0x14] = result;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
message(0, "%08X: Unknown DMA command, %08X", ppc_get_pc(), d);
|
||||
|
||||
return;
|
||||
case 0x14:
|
||||
*(UINT32 *) &dma_regs[0x14] = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
|
||||
message(0, "%08X: Unknown DMA write32, %08X = %08X", ppc_get_pc(), a, d);
|
||||
}
|
||||
|
42
core/dma.h
42
core/dma.h
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* dma.h
|
||||
*
|
||||
* Step 2.0+ DMA device header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_DMA_H
|
||||
#define INCLUDED_DMA_H
|
||||
|
||||
extern void dma_init(UINT32 (*)(UINT32), void (*)(UINT32, UINT32));
|
||||
extern void dma_shutdown(void);
|
||||
extern void dma_reset(void);
|
||||
|
||||
extern void dma_save_state(FILE *);
|
||||
extern void dma_load_state(FILE *);
|
||||
|
||||
extern UINT8 dma_read_8(UINT32 a);
|
||||
extern UINT32 dma_read_32(UINT32 a);
|
||||
extern void dma_write_8(UINT32 a, UINT8 d);
|
||||
extern void dma_write_16(UINT32 a, UINT16 d);
|
||||
extern void dma_write_32(UINT32 a, UINT32 d);
|
||||
|
||||
#endif // INCLUDED_DMA_H
|
||||
|
71
core/dsb1.c
71
core/dsb1.c
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* dsb1.c
|
||||
*
|
||||
* DSB1 Digital Sound Board emulation.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
void dsb1_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void dsb1_reset(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void dsb1_shutdown(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* void dsb1_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the DSB1 (for games which have it) to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void dsb1_save_state(FILE *fp)
|
||||
{
|
||||
if (!(m3_config.flags & GAME_OWN_DSB1))
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* void dsb1_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the DSB1 (for games which have it) from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void dsb1_load_state(FILE *fp)
|
||||
{
|
||||
if (!(m3_config.flags & GAME_OWN_DSB1))
|
||||
return;
|
||||
}
|
||||
|
36
core/dsb1.h
36
core/dsb1.h
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* dsb1.h
|
||||
*
|
||||
* DSB1 Digital Sound Board header.
|
||||
*/
|
||||
|
||||
#ifndef _DSB1_H_
|
||||
#define _DSB1_H_
|
||||
|
||||
extern void dsb1_init(void);
|
||||
extern void dsb1_shutdown(void);
|
||||
extern void dsb1_reset(void);
|
||||
|
||||
extern void dsb1_save_state(FILE *);
|
||||
extern void dsb1_load_state(FILE *);
|
||||
|
||||
#endif /* _DSB1_H_ */
|
||||
|
391
core/eeprom.c
391
core/eeprom.c
|
@ -1,391 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* eeprom.c
|
||||
*
|
||||
* 93C46 EEPROM emulation courtesy of R. Belmont.
|
||||
*
|
||||
* NOTE: Save state code assumes enums will be the same across all compilers
|
||||
* and systems. The eeprom_store[] array is endian-dependent.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
eeprom.cpp - handles a serial eeprom with 64 16-bit addresses and 4-bit commands
|
||||
as seen in st-v, system 32, many konami boards, etc.
|
||||
|
||||
originally written: May 20, 2000 by R. Belmont for "sim"
|
||||
update: Jan 27, 2001 (RB): implemented "erase" opcode,
|
||||
made opcode fetch check for start bit
|
||||
like the real chip.
|
||||
Mar 26, 2001 (FF): added get_image to access the eeprom
|
||||
Jan 28, 2004 (Bart): Interface changes to work with Supermodel.
|
||||
Crudely simulated busy status by setting olatch to 0 in
|
||||
ES_DESELECT.
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "model3.h"
|
||||
|
||||
#define LOG_EEPROM 0 // log channel for EEPROM
|
||||
|
||||
static INT32 eeprom_state;
|
||||
|
||||
static UINT16 eeprom_store[64]; // 6 address bits times 16 bits per location
|
||||
static UINT8 opcode; // current opcode
|
||||
static UINT8 adr; // current address in eeprom_store
|
||||
static UINT8 curbit; // current bit # in read/write/addr fetch operation
|
||||
static UINT8 lastclk; // last clock
|
||||
static UINT8 dlatch; // input data latch
|
||||
static UINT8 olatch; // output data latch
|
||||
static UINT16 curio;
|
||||
|
||||
// states for the eeprom state machine
|
||||
enum
|
||||
{
|
||||
ES_DESELECT = 0,// chip select not asserted
|
||||
ES_ASSERT, // chip select asserted, waiting for opcode
|
||||
ES_OPCODE0, // got opcode bit 0
|
||||
ES_OPCODE1, // got opcode bit 1
|
||||
ES_OPCODE2, // got opcode bit 2
|
||||
ES_ADRFETCH, // fetching address
|
||||
ES_READBITS, // reading bits, 1 out every time clock goes high
|
||||
ES_WRITEBITS, // writing bits, 1 in every time clock goes high
|
||||
ES_WAITING // done with read/write, waiting for deselect to finalize
|
||||
};
|
||||
|
||||
/*
|
||||
* UINT8 eeprom_read_bit(void);
|
||||
*
|
||||
* Reads a data bit from the EEPROM.
|
||||
*
|
||||
* Returns:
|
||||
* Latched data bit.
|
||||
*/
|
||||
|
||||
UINT8 eeprom_read_bit(void)
|
||||
{
|
||||
return olatch;
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_set_ce(UINT8 ce);
|
||||
*
|
||||
* Passes the status of the chip enable.
|
||||
*
|
||||
* Parameters:
|
||||
* ce = Chip enable bit (must be 0 or 1.)
|
||||
*/
|
||||
|
||||
void eeprom_set_ce(UINT8 ce)
|
||||
{
|
||||
// chip enable
|
||||
if (ce)
|
||||
{
|
||||
// asserting CE - if deselected,
|
||||
// select. if selected already,
|
||||
// ignore
|
||||
if (eeprom_state == ES_DESELECT)
|
||||
{
|
||||
// printf("EEPROM: asserting chip enable\n");
|
||||
eeprom_state = ES_ASSERT;
|
||||
opcode = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// deasserting CE
|
||||
// printf("EEPROM: deasserting chip enable\n");
|
||||
eeprom_state = ES_DESELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_set_data(UINT8 data);
|
||||
*
|
||||
* Sets the data bit latch.
|
||||
*
|
||||
* Parameters:
|
||||
* data = Data bit (must be 0 or 1.)
|
||||
*/
|
||||
|
||||
void eeprom_set_data(UINT8 data)
|
||||
{
|
||||
dlatch = (data&0x01); // latch the data
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_set_clk(UINT8 clk);
|
||||
*
|
||||
* Sets the clock pin.
|
||||
*
|
||||
* Parameters:
|
||||
* clk = Clock (zero or non-zero.)
|
||||
*/
|
||||
|
||||
void eeprom_set_clk(UINT8 clk)
|
||||
{
|
||||
// things only happen on the rising edge of the clock
|
||||
if ((!lastclk) && (clk))
|
||||
{
|
||||
switch (eeprom_state)
|
||||
{
|
||||
case ES_DESELECT:
|
||||
olatch = 0;
|
||||
break;
|
||||
|
||||
case ES_ASSERT:
|
||||
case ES_OPCODE0:
|
||||
case ES_OPCODE1:
|
||||
case ES_OPCODE2:
|
||||
// first command bit must be a "1" in the real device
|
||||
if ((eeprom_state == ES_OPCODE0) && (dlatch == 0))
|
||||
{
|
||||
#if LOG_EEPROM
|
||||
LOG("model3.log", "EEPROM: waiting for start bit\n");
|
||||
#endif
|
||||
olatch = 1; // assert READY
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode <<= 1;
|
||||
opcode |= dlatch;
|
||||
#if LOG_EEPROM
|
||||
LOG("model3.log", "EEPROM: opcode fetch state, currently %x\n", opcode);
|
||||
#endif
|
||||
eeprom_state++;
|
||||
}
|
||||
|
||||
curbit = 0;
|
||||
adr = 0;
|
||||
break;
|
||||
|
||||
case ES_ADRFETCH: // fetch address
|
||||
adr <<= 1;
|
||||
adr |= dlatch;
|
||||
#if LOG_EEPROM
|
||||
LOG("model3.log", "EEPROM: address fetch state, cur addr = %x\n", adr);
|
||||
#endif
|
||||
curbit++;
|
||||
if (curbit == 6)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 4: // write enable - go back to accept a new opcode immediately
|
||||
opcode = 0;
|
||||
eeprom_state = ES_ASSERT;
|
||||
//printf("EEPROM: write enable\n");
|
||||
break;
|
||||
|
||||
case 5: // write
|
||||
eeprom_state = ES_WRITEBITS;
|
||||
olatch = 0; // indicate not ready yet
|
||||
curbit = 0;
|
||||
curio = 0;
|
||||
break;
|
||||
|
||||
case 6: // read
|
||||
eeprom_state = ES_READBITS;
|
||||
curbit = 0;
|
||||
curio = eeprom_store[adr];
|
||||
//printf("EEPROM: read %04x from address %d\n", curio, adr);
|
||||
break;
|
||||
|
||||
case 7: // erase location to ffff and assert READY
|
||||
eeprom_store[adr] = 0xffff;
|
||||
olatch = 1;
|
||||
eeprom_state = ES_WAITING;
|
||||
//printf("EEPROM: erase at address %d\n", adr);
|
||||
break;
|
||||
|
||||
default:
|
||||
#if LOG_EEPROM
|
||||
LOG("model3.log", "Unknown EEPROM opcode %d!\n", opcode);
|
||||
#endif
|
||||
eeprom_state = ES_WAITING;
|
||||
olatch = 1; // assert READY anyway
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ES_READBITS:
|
||||
olatch = ((curio & 0x8000)>>15);
|
||||
curio <<= 1;
|
||||
|
||||
curbit++;
|
||||
if (curbit == 16)
|
||||
{
|
||||
eeprom_state = ES_WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
case ES_WRITEBITS:
|
||||
curio <<= 1;
|
||||
curio |= dlatch;
|
||||
|
||||
curbit++;
|
||||
if (curbit == 16)
|
||||
{
|
||||
olatch = 1; // indicate success
|
||||
eeprom_store[adr] = curio;
|
||||
#if LOG_EEPROM
|
||||
LOG("model3.log", "EEPROM: Wrote %04x to address %d\n", curio, adr);
|
||||
#endif
|
||||
eeprom_state = ES_WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
case ES_WAITING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lastclk = clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_save_state(FILE *fp);
|
||||
*
|
||||
* Save the EEPROM state.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void eeprom_save_state(FILE *fp)
|
||||
{
|
||||
if (fp != NULL)
|
||||
{
|
||||
fwrite(&eeprom_state, sizeof(INT32), 1, fp);
|
||||
fwrite(eeprom_store, sizeof(UINT16), 64, fp);
|
||||
fwrite(&opcode, sizeof(UINT8), 1, fp);
|
||||
fwrite(&adr, sizeof(UINT8), 1, fp);
|
||||
fwrite(&curbit, sizeof(UINT8), 1, fp);
|
||||
fwrite(&lastclk, sizeof(UINT8), 1, fp);
|
||||
fwrite(&dlatch, sizeof(UINT8), 1, fp);
|
||||
fwrite(&olatch, sizeof(UINT8), 1, fp);
|
||||
fwrite(&curio, sizeof(UINT16), 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_load_state(FILE *fp);
|
||||
*
|
||||
* Load the EEPROM state.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void eeprom_load_state(FILE *fp)
|
||||
{
|
||||
if (fp != NULL)
|
||||
{
|
||||
fread(&eeprom_state, sizeof(INT32), 1, fp);
|
||||
fread(eeprom_store, sizeof(UINT16), 64, fp);
|
||||
fread(&opcode, sizeof(UINT8), 1, fp);
|
||||
fread(&adr, sizeof(UINT8), 1, fp);
|
||||
fread(&curbit, sizeof(UINT8), 1, fp);
|
||||
fread(&lastclk, sizeof(UINT8), 1, fp);
|
||||
fread(&dlatch, sizeof(UINT8), 1, fp);
|
||||
fread(&olatch, sizeof(UINT8), 1, fp);
|
||||
fread(&curio, sizeof(UINT16), 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* INT eeprom_load(CHAR *fname);
|
||||
*
|
||||
* Loads data from the file specified. If the file does not exist, the EEPROM
|
||||
* data is initialized with all 1's.
|
||||
*
|
||||
* Parameters:
|
||||
* fname = File name.
|
||||
*
|
||||
* Returns:
|
||||
* MODEL3_OKAY = Success.
|
||||
* MODEL3_ERROR = Error reading from the file.
|
||||
*/
|
||||
|
||||
INT eeprom_load(CHAR *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
INT error_code = MODEL3_ERROR;
|
||||
|
||||
message(0, "loading EEPROM from %s", fname);
|
||||
|
||||
if ((fp = fopen(fname, "rb")) != NULL)
|
||||
{
|
||||
error_code = fread(eeprom_store, sizeof(UINT16), 64, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (error_code == 64)
|
||||
return MODEL3_OKAY;
|
||||
}
|
||||
|
||||
memset(eeprom_store, 0xFF, sizeof(UINT16) * 64);
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* INT eeprom_save(CHAR *fname);
|
||||
*
|
||||
* Writes out the EEPROM data to the specified file.
|
||||
*
|
||||
* Parameters:
|
||||
* fname = File name to write.
|
||||
*
|
||||
* Returns:
|
||||
* MODEL3_OKAY = Success.
|
||||
* MODEL3_ERROR = Unable to open or write file.
|
||||
*/
|
||||
|
||||
INT eeprom_save(CHAR *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
INT i = MODEL3_ERROR;
|
||||
|
||||
message(0, "saving EEPROM to %s", fname);
|
||||
|
||||
if ((fp = fopen(fname, "wb")) != NULL)
|
||||
{
|
||||
i = fwrite(eeprom_store, sizeof(UINT16), 64, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (i == 64)
|
||||
return MODEL3_OKAY;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* void eeprom_reset(void);
|
||||
*
|
||||
* Resets the EEPROM emulation.
|
||||
*/
|
||||
|
||||
void eeprom_reset(void)
|
||||
{
|
||||
eeprom_state = ES_DESELECT;
|
||||
lastclk = 0;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* eeprom.h
|
||||
*
|
||||
* 93C46 EEPROM emulation header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_EEPROM_H
|
||||
#define INCLUDED_EEPROM_H
|
||||
|
||||
extern UINT8 eeprom_read_bit(void);
|
||||
extern void eeprom_set_clk(UINT8 clk);
|
||||
extern void eeprom_set_ce(UINT8 ce);
|
||||
extern void eeprom_set_data(UINT8 data);
|
||||
|
||||
extern void eeprom_save_state(FILE *);
|
||||
extern void eeprom_load_state(FILE *);
|
||||
|
||||
extern INT eeprom_load(CHAR *);
|
||||
extern INT eeprom_save(CHAR *);
|
||||
|
||||
extern void eeprom_reset(void);
|
||||
|
||||
#endif // INCLUDED_EEPROM_H
|
2396
core/model3.c
2396
core/model3.c
File diff suppressed because it is too large
Load diff
417
core/model3.h
417
core/model3.h
|
@ -1,417 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* model3.h
|
||||
*
|
||||
* Model 3 header. This serves as the primary header file for all modules to
|
||||
* include.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_MODEL3_H
|
||||
#define INCLUDED_MODEL3_H
|
||||
|
||||
/******************************************************************/
|
||||
/* Program Information */
|
||||
/******************************************************************/
|
||||
|
||||
#define VERSION "0.01" // program version
|
||||
#define VERSION_MAJOR 0x00 // major version number (BCD)
|
||||
#define VERSION_MINOR 0x01 // minor version number (BCD)
|
||||
|
||||
/******************************************************************/
|
||||
/* Includes */
|
||||
/******************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
//#include "zlib.h"
|
||||
|
||||
#include "osd.h" // provided by the port to define data types, etc.
|
||||
|
||||
#include "ppc_itp/ppc.h"
|
||||
|
||||
//#include "m68k/m68k.h"
|
||||
|
||||
#include "controls.h"
|
||||
#include "dma.h"
|
||||
#include "dsb1.h"
|
||||
#include "eeprom.h"
|
||||
#include "bridge.h"
|
||||
#include "r3d.h"
|
||||
#include "render.h"
|
||||
#include "rtc.h"
|
||||
#include "scsi.h"
|
||||
#include "scsp.h"
|
||||
#include "tilegen.h"
|
||||
#include "file.h"
|
||||
|
||||
#include "osd_common.h" // defines OSD interface (must be included last)
|
||||
|
||||
/******************************************************************/
|
||||
/* Helpful Macros */
|
||||
/******************************************************************/
|
||||
|
||||
#define MODEL3_OKAY 0 /* Everything went okay */
|
||||
#define MODEL3_ERROR -1 /* Some error happened */
|
||||
|
||||
#define MODEL3_SCREEN_WIDTH 496
|
||||
#define MODEL3_SCREEN_HEIGHT 384
|
||||
|
||||
#define SAFE_FREE(p) { if(p != NULL) free(p); p = NULL; }
|
||||
|
||||
#define PPC_PC ppc_get_reg(PPC_REG_PC)
|
||||
#define PPC_LR ppc_get_reg(PPC_REG_LR)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define BSWAP16(x) _byteswap_ushort(x)
|
||||
#define BSWAP32(x) _byteswap_ulong(x)
|
||||
|
||||
#else
|
||||
|
||||
static UINT16 BSWAP16(UINT16 d)
|
||||
{
|
||||
return(((d >> 8) & 0x00FF) |
|
||||
((d << 8) & 0xFF00));
|
||||
}
|
||||
|
||||
static UINT32 BSWAP32(UINT32 d)
|
||||
{
|
||||
return(((d >> 24) & 0x000000FF) |
|
||||
((d >> 8) & 0x0000FF00) |
|
||||
((d << 8) & 0x00FF0000) |
|
||||
((d << 24) & 0xFF000000));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
/* Configuration Structure */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Game Flags
|
||||
*
|
||||
* Identify various properties that the games can have.
|
||||
*/
|
||||
|
||||
#define GAME_OWN_STEERING_WHEEL (1 << 0) // analog steering wheel
|
||||
#define GAME_OWN_GUN (1 << 1) // light gun
|
||||
#define GAME_OWN_DSB1 (1 << 2) // DSB1 sound board
|
||||
|
||||
typedef enum
|
||||
{
|
||||
P1_BUTTON_1,
|
||||
P1_BUTTON_2,
|
||||
P1_BUTTON_3,
|
||||
P1_BUTTON_4,
|
||||
P1_BUTTON_5,
|
||||
P1_BUTTON_6,
|
||||
P1_BUTTON_7,
|
||||
P1_BUTTON_8,
|
||||
P2_BUTTON_1,
|
||||
P2_BUTTON_2,
|
||||
P2_BUTTON_3,
|
||||
P2_BUTTON_4,
|
||||
P2_BUTTON_5,
|
||||
P2_BUTTON_6,
|
||||
P2_BUTTON_7,
|
||||
P2_BUTTON_8,
|
||||
P1_JOYSTICK_UP,
|
||||
P1_JOYSTICK_DOWN,
|
||||
P1_JOYSTICK_LEFT,
|
||||
P1_JOYSTICK_RIGHT,
|
||||
P2_JOYSTICK_UP,
|
||||
P2_JOYSTICK_DOWN,
|
||||
P2_JOYSTICK_LEFT,
|
||||
P2_JOYSTICK_RIGHT,
|
||||
} GAME_BUTTON;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ANALOG_AXIS_1,
|
||||
ANALOG_AXIS_2,
|
||||
ANALOG_AXIS_3,
|
||||
ANALOG_AXIS_4,
|
||||
ANALOG_AXIS_5,
|
||||
ANALOG_AXIS_6,
|
||||
ANALOG_AXIS_7,
|
||||
ANALOG_AXIS_8,
|
||||
} GAME_ANALOG;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UINT8 control_set;
|
||||
UINT8 control_bit;
|
||||
GAME_BUTTON mapping;
|
||||
int enabled;
|
||||
} button[16];
|
||||
|
||||
struct
|
||||
{
|
||||
GAME_ANALOG mapping;
|
||||
int enabled;
|
||||
UINT8 center;
|
||||
} analog_axis[8];
|
||||
|
||||
} GAME_CONTROLS;
|
||||
|
||||
/*
|
||||
* CONFIG Structure
|
||||
*
|
||||
* Emulator configuration and game information.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* Emulator Configuration
|
||||
*
|
||||
* Determines the behavior of the emulator itself. These fields can be
|
||||
* loaded, saved, and modified. The user has control over these options.
|
||||
*/
|
||||
|
||||
BOOL log_enabled; // whether to log (no effect if _LOG_ not defined)
|
||||
BOOL fullscreen;
|
||||
BOOL triple_buffer;
|
||||
INT width;
|
||||
INT height;
|
||||
BOOL stretch;
|
||||
FLAGS layer_enable;
|
||||
CHAR rom_path[512];
|
||||
CHAR rom_list[512];
|
||||
CHAR backup_path[512];
|
||||
BOOL fps_limit;
|
||||
BOOL show_fps;
|
||||
|
||||
/*
|
||||
* Game Configuration
|
||||
*
|
||||
* Information on the game currently being emulated. The user has no
|
||||
* control over this stuff -- it's internal to the emulator only.
|
||||
*/
|
||||
|
||||
CHAR game_id[8+1]; // game ID string (max 8 chars + null terminator)
|
||||
CHAR game_name[128];
|
||||
INT step; // hardware step (0x15 = Step 1.5, etc.)
|
||||
INT bridge; // type of PCIBMC (1=MPC105, 2=MPC106)
|
||||
FLAGS flags; // game info flags
|
||||
BOOL has_lightgun;
|
||||
|
||||
// Game controls
|
||||
GAME_CONTROLS controls;
|
||||
|
||||
} CONFIG;
|
||||
|
||||
enum
|
||||
{
|
||||
ROMTYPE_NONE = 0,
|
||||
ROMTYPE_PROG0 = 1,
|
||||
ROMTYPE_PROG1,
|
||||
ROMTYPE_PROG2,
|
||||
ROMTYPE_PROG3,
|
||||
ROMTYPE_CROM00,
|
||||
ROMTYPE_CROM01,
|
||||
ROMTYPE_CROM02,
|
||||
ROMTYPE_CROM03,
|
||||
ROMTYPE_CROM10,
|
||||
ROMTYPE_CROM11,
|
||||
ROMTYPE_CROM12,
|
||||
ROMTYPE_CROM13,
|
||||
ROMTYPE_CROM20,
|
||||
ROMTYPE_CROM21,
|
||||
ROMTYPE_CROM22,
|
||||
ROMTYPE_CROM23,
|
||||
ROMTYPE_CROM30,
|
||||
ROMTYPE_CROM31,
|
||||
ROMTYPE_CROM32,
|
||||
ROMTYPE_CROM33,
|
||||
ROMTYPE_VROM00,
|
||||
ROMTYPE_VROM01,
|
||||
ROMTYPE_VROM02,
|
||||
ROMTYPE_VROM03,
|
||||
ROMTYPE_VROM04,
|
||||
ROMTYPE_VROM05,
|
||||
ROMTYPE_VROM06,
|
||||
ROMTYPE_VROM07,
|
||||
ROMTYPE_VROM10,
|
||||
ROMTYPE_VROM11,
|
||||
ROMTYPE_VROM12,
|
||||
ROMTYPE_VROM13,
|
||||
ROMTYPE_VROM14,
|
||||
ROMTYPE_VROM15,
|
||||
ROMTYPE_VROM16,
|
||||
ROMTYPE_VROM17,
|
||||
ROMTYPE_SPROG,
|
||||
ROMTYPE_SROM0,
|
||||
ROMTYPE_SROM1,
|
||||
ROMTYPE_SROM2,
|
||||
ROMTYPE_SROM3,
|
||||
ROMTYPE_DSBPROG,
|
||||
ROMTYPE_DSBROM0,
|
||||
ROMTYPE_DSBROM1,
|
||||
ROMTYPE_DSBROM2,
|
||||
ROMTYPE_DSBROM3,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
char name[20];
|
||||
int size;
|
||||
UINT32 crc32;
|
||||
int load;
|
||||
} ROMFILE;
|
||||
|
||||
typedef struct {
|
||||
UINT32 address;
|
||||
UINT32 data;
|
||||
INT size; // 8, 16, or 32
|
||||
} PATCH;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char game[20];
|
||||
char parent[20];
|
||||
char title[256];
|
||||
char manufacturer[32];
|
||||
int year;
|
||||
int step;
|
||||
int bridge;
|
||||
int cromsize;
|
||||
FLAGS flags;
|
||||
int num_patches;
|
||||
PATCH patch[64];
|
||||
|
||||
ROMFILE rom[64];
|
||||
|
||||
GAME_CONTROLS controls;
|
||||
|
||||
} ROMSET;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[60];
|
||||
UINT32 int_id;
|
||||
} STRING_ID;
|
||||
|
||||
static int get_string_id(const char *string, STRING_ID *idtable)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (strlen(idtable[i].id) > 0)
|
||||
{
|
||||
if (_stricmp(string, idtable[i].id) == 0)
|
||||
{
|
||||
return idtable[i].int_id;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* m3_config
|
||||
*
|
||||
* A global variable accessible by all parts of the emulator after emulation
|
||||
* begins successfully.
|
||||
*/
|
||||
|
||||
extern CONFIG m3_config;
|
||||
|
||||
extern void message(int, char * fmt, ...);
|
||||
extern void error(char * fmt, ...);
|
||||
|
||||
extern BOOL parse_config(const char *config_name);
|
||||
extern int parse_romlist(char *romlist_name, ROMSET *_romset);
|
||||
|
||||
/*
|
||||
* Profile
|
||||
*/
|
||||
|
||||
extern void profile_section_entry(CHAR * name);
|
||||
extern void profile_section_exit(CHAR * name);
|
||||
extern UINT64 profile_get_stat(CHAR * name);
|
||||
extern void profile_reset_sect(CHAR * name);
|
||||
extern void profile_cleanup(void);
|
||||
extern void profile_print(CHAR * string);
|
||||
|
||||
#ifdef _PROFILE_
|
||||
#define PROFILE_SECT_ENTRY(n) profile_section_entry(n);
|
||||
#define PROFILE_SECT_EXIT(n) profile_section_exit(n);
|
||||
#define PROFILE_SECT_RESET(n) profile_reset_sect(n);
|
||||
#else // !_PROFILE_
|
||||
#define PROFILE_SECT_ENTRY(n)
|
||||
#define PROFILE_SECT_EXIT(n)
|
||||
#define PROFILE_SECT_RESET(n)
|
||||
#endif // _PROFILE_
|
||||
|
||||
/******************************************************************/
|
||||
/* Functions */
|
||||
/******************************************************************/
|
||||
|
||||
#ifdef _LOG_
|
||||
#define LOG_INIT _log_init
|
||||
#define LOG _log
|
||||
#else // !_LOG_
|
||||
#define LOG_INIT
|
||||
#define LOG
|
||||
#endif // _LOG
|
||||
|
||||
extern void _log(char * path, char * fmt, ...);
|
||||
extern void _log_init(char * path);
|
||||
|
||||
extern BOOL model3_init(void);
|
||||
extern void model3_shutdown(void);
|
||||
|
||||
extern BOOL model3_load(void);
|
||||
|
||||
extern void model3_reset(void);
|
||||
extern void model3_run_frame(void);
|
||||
extern void model3_add_irq(UINT8);
|
||||
extern void model3_remove_irq(UINT8);
|
||||
|
||||
extern BOOL model3_save_state(CHAR *);
|
||||
extern BOOL model3_load_state(CHAR *);
|
||||
|
||||
extern void model3_load_eeprom(void);
|
||||
extern void model3_save_eeprom(void);
|
||||
extern void model3_load_bram(void);
|
||||
extern void model3_save_bram(void);
|
||||
|
||||
extern UINT8 m3_ppc_read_8(UINT32 a);
|
||||
extern UINT16 m3_ppc_read_16(UINT32 a);
|
||||
extern UINT32 m3_ppc_read_32(UINT32 a);
|
||||
extern UINT64 m3_ppc_read_64(UINT32 a);
|
||||
extern void m3_ppc_write_8(UINT32 a, UINT8 d);
|
||||
extern void m3_ppc_write_16(UINT32 a, UINT16 d);
|
||||
extern void m3_ppc_write_32(UINT32 a, UINT32 d);
|
||||
extern void m3_ppc_write_64(UINT32 a, UINT64 d);
|
||||
|
||||
extern void model3_dma_transfer(UINT32 src, UINT32 dst, int length, BOOL swap_words);
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#endif // INCLUDED_MODEL3_H
|
937
core/r3d.c
937
core/r3d.c
|
@ -1,937 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* r3d.c
|
||||
*
|
||||
* Real3D Model 3 graphics system emulation. The 3D hardware in Model 3 is
|
||||
* supposedly based on the Pro-1000.
|
||||
*
|
||||
* To-Do List:
|
||||
* -----------
|
||||
* - In VS2_98, in the attract mode, when the camera zooms in on the score
|
||||
* board for South Africa vs. Nigeria, the "Nigeria" text texture is
|
||||
* garbage.
|
||||
* - RAM texture uploading is too weird to be true.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RAM Size:
|
||||
* ---------
|
||||
*
|
||||
* It appears that there is 2MB total of "culling RAM." 1MB appears at
|
||||
* 0x8C000000 and the other at 0x8E000000. Step 1.0 and 1.5 appear to have
|
||||
* 1MB of polygon RAM, but Step 2.0 (and probably 2.1) clearly uses 2MB.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
extern UINT8 *ram;
|
||||
|
||||
/******************************************************************/
|
||||
/* Privates */
|
||||
/******************************************************************/
|
||||
|
||||
static UINT8 *culling_ram_8e; // culling RAM at 0x8E000000
|
||||
static UINT8 *culling_ram_8c; // culling RAM at 0x8C000000
|
||||
static UINT8 *polygon_ram; // polygon RAM at 0x98000000
|
||||
static UINT8 *texture_ram; // texture RAM
|
||||
static UINT8 *vrom;
|
||||
|
||||
static UINT8 texture_buffer_ram[1*1024*1024];
|
||||
|
||||
static UINT32 vrom_texture_address;
|
||||
static UINT32 vrom_texture_header;
|
||||
|
||||
static UINT32 texture_last_addr = 0;
|
||||
static UINT32 texture_header = 0;
|
||||
|
||||
/******************************************************************/
|
||||
/* Interface */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
|
||||
* UINT8 *polygon_ram_ptr, UINT8 *texture_ram, UINT8 *vrom_ptr);
|
||||
*
|
||||
* Initializes the Real3D graphics emulation.
|
||||
*
|
||||
* Parameters:
|
||||
* culling_ram_8e_ptr = Pointer to 0x8E000000 culling RAM.
|
||||
* culling_ram_8c_ptr = Pointer to 0x8C000000 culling RAM.
|
||||
* polygon_ram_ptr = Pointer to polygon RAM.
|
||||
* texture_ram = Pointer to texture RAM.
|
||||
* vrom_ptr = Pointer to VROM.
|
||||
*/
|
||||
|
||||
void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
|
||||
UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, UINT8 *vrom_ptr)
|
||||
{
|
||||
culling_ram_8e = culling_ram_8e_ptr;
|
||||
culling_ram_8c = culling_ram_8c_ptr;
|
||||
polygon_ram = polygon_ram_ptr;
|
||||
texture_ram = texture_ram_ptr;
|
||||
vrom = vrom_ptr;
|
||||
|
||||
LOG_INIT("texture.log");
|
||||
}
|
||||
|
||||
/*
|
||||
* void r3d_shutdown(void);
|
||||
*
|
||||
* Shuts down the Real3D emulation.
|
||||
*/
|
||||
|
||||
void r3d_shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* void r3d_reset(void);
|
||||
*
|
||||
* Resets the Real3D graphics hardware. RAM is cleared in order to prevent
|
||||
* the renderer from drawing garbage and possibly locking up as a result.
|
||||
*/
|
||||
|
||||
void r3d_reset(void)
|
||||
{
|
||||
memset(culling_ram_8e, 0, 1*1024*1024);
|
||||
memset(culling_ram_8c, 0, 4*1024*1024);
|
||||
memset(polygon_ram, 0, 2*1024*1024);
|
||||
memset(texture_ram, 0, 2048*2048*2);
|
||||
tap_reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* void r3d_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the Real3D graphics hardware to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void r3d_save_state(FILE *fp)
|
||||
{
|
||||
fwrite(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
|
||||
fwrite(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
|
||||
fwrite(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
|
||||
fwrite(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void r3d_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the Real3D graphics hardware from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void r3d_load_state(FILE *fp)
|
||||
{
|
||||
fread(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
|
||||
fread(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
|
||||
fread(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
|
||||
fread(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
|
||||
|
||||
osd_renderer_invalidate_textures(0, 0, 0, 0, 2048, 2048, texture_ram, 0);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Texture Memory Management */
|
||||
/******************************************************************/
|
||||
|
||||
static const INT decode[64] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9,12,13,
|
||||
2, 3, 6, 7,10,11,14,15,
|
||||
16,17,20,21,24,25,28,29,
|
||||
18,19,22,23,26,27,30,31,
|
||||
32,33,36,37,40,41,44,45,
|
||||
34,35,38,39,42,43,46,47,
|
||||
48,49,52,53,56,57,60,61,
|
||||
50,51,54,55,58,59,62,63
|
||||
};
|
||||
|
||||
/*
|
||||
* store_texture_tile():
|
||||
*
|
||||
* Writes a single 8x8 texture tile into the appropriate part of the texture
|
||||
* sheet.
|
||||
*/
|
||||
|
||||
static void store_texture_tile(UINT x, UINT y, UINT8 *src, UINT bpp, BOOL little_endian)
|
||||
{
|
||||
UINT xi, yi, pixel_offs;
|
||||
UINT16 rgb16;
|
||||
UINT8 gray8;
|
||||
|
||||
for (yi = 0; yi < 8; yi++)
|
||||
{
|
||||
for (xi = 0; xi < 8; xi++)
|
||||
{
|
||||
/*
|
||||
* Grab the pixel offset from the decode[] array and fetch the
|
||||
* pixel word
|
||||
*/
|
||||
|
||||
if (little_endian)
|
||||
{
|
||||
if (bpp == 2)
|
||||
{
|
||||
/*
|
||||
* XOR with 1 in little endian mode -- every word contains
|
||||
* 2 16-bit pixels, thus they are swapped
|
||||
*/
|
||||
|
||||
pixel_offs = decode[(yi * 8 + xi) ^ 1] * 2;
|
||||
rgb16 = *(UINT16 *) &src[pixel_offs];
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel_offs = decode[((yi ^ 1) * 8 + (xi ^ 1))];
|
||||
gray8 = src[pixel_offs];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bpp == 2)
|
||||
{
|
||||
pixel_offs = decode[yi * 8 + xi] * 2;
|
||||
rgb16 = (src[pixel_offs + 0] << 8) | src[pixel_offs + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel_offs = decode[yi * 8 + xi];
|
||||
gray8 = src[pixel_offs + 0];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store within the texture sheet
|
||||
*/
|
||||
|
||||
if (bpp == 2)
|
||||
*(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2] = rgb16;
|
||||
else
|
||||
texture_ram[(((y + yi) * 2048 + x) * 2) + xi] = gray8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* store_texture():
|
||||
*
|
||||
* Writes a texture into the texture sheet. The pixel words are not decoded,
|
||||
* but the 16-bit pixels are converted into a common endianness (little.)
|
||||
* 8-bit pixels are not expanded into 16-bits.
|
||||
*
|
||||
* bpp (bytes per pixel) must be 1 or 2.
|
||||
*/
|
||||
|
||||
static void store_texture(UINT x, UINT y, UINT w, UINT h, UINT8 *src, UINT bpp, BOOL little_endian)
|
||||
{
|
||||
UINT xi, yi;
|
||||
UINT bw;
|
||||
|
||||
if(bpp == 2)
|
||||
bw = 1;
|
||||
else
|
||||
bw = 2;
|
||||
|
||||
for (yi = 0; yi < h; yi += 8)
|
||||
{
|
||||
for (xi = 0; xi < w; xi += 8)
|
||||
{
|
||||
store_texture_tile(x + (xi / bw), y + yi, src, bpp, little_endian);
|
||||
src += 8 * 8 * bpp; // each texture tile is 8x8 and 16-bit color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* upload_texture():
|
||||
*
|
||||
* Uploads a texture to texture memory.
|
||||
*/
|
||||
|
||||
// Mipmap starting positions for each level
|
||||
static const int mipmap_xpos[11] =
|
||||
{ 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
|
||||
static const int mipmap_ypos[11] =
|
||||
{ 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023, 0 };
|
||||
|
||||
// Mipmap size dividers
|
||||
static const int mipmap_size[9] =
|
||||
{ 2, 4, 8, 16, 32, 64, 128, 256, 512 };
|
||||
|
||||
static void upload_texture(UINT32 header, UINT8 *src, BOOL little_endian)
|
||||
{
|
||||
UINT size_x, size_y, xpos, ypos, bit_depth, mip_ypos, page;
|
||||
int mipmap_num = 0;
|
||||
int mxpos, mypos, msize_x, msize_y;
|
||||
|
||||
PROFILE_SECT_ENTRY("real3d");
|
||||
|
||||
/*
|
||||
* Model 3 texture RAM appears as 2 2048x1024 textures. When textures are
|
||||
* uploaded, their size and position within a sheet is given. I treat the
|
||||
* texture sheet selection bit as an additional bit to the Y coordinate.
|
||||
*/
|
||||
|
||||
size_x = (header >> 14) & 7;
|
||||
size_y = (header >> 17) & 7;
|
||||
size_x = (32 << size_x); // width in pixels
|
||||
size_y = (32 << size_y); // height
|
||||
|
||||
ypos = (((header >> 7) & 0x1F) | ((header >> 15) & 0x20)) * 32;
|
||||
xpos = ((header >> 0) & 0x3F) * 32;
|
||||
|
||||
mip_ypos = ((header >> 7) & 0x1F) * 32;
|
||||
page = (header >> 15 & 0x20) ? 1 : 0;
|
||||
|
||||
if( header & 0x00800000 )
|
||||
bit_depth = 2; // 16-bit texture
|
||||
else
|
||||
bit_depth = 1; // 8-bit texture
|
||||
|
||||
LOG("texture.log", "%08X %d,%d\t%dx%d\n", header, xpos, ypos, size_x, size_y);
|
||||
|
||||
/*
|
||||
* Render the texture into the texture buffer
|
||||
*/
|
||||
|
||||
switch( (header >> 24) & 0xF )
|
||||
{
|
||||
case 0: // Texture with mipmaps
|
||||
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
|
||||
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
|
||||
|
||||
msize_x = size_x;
|
||||
msize_y = size_y;
|
||||
|
||||
// Store mipmaps
|
||||
while( msize_y > 8 && msize_x > 8 ) {
|
||||
|
||||
src += (msize_x * msize_y * bit_depth);
|
||||
msize_x /= 2;
|
||||
msize_y /= 2;
|
||||
|
||||
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
|
||||
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
|
||||
if(page)
|
||||
mypos += 1024;
|
||||
mipmap_num++;
|
||||
|
||||
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
|
||||
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // Texture without mipmaps
|
||||
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
|
||||
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
|
||||
break;
|
||||
|
||||
case 2: // Only mipmaps
|
||||
msize_x = size_x;
|
||||
msize_y = size_y;
|
||||
while( msize_y > 8 && msize_x > 8 ) {
|
||||
|
||||
msize_x /= 2;
|
||||
msize_y /= 2;
|
||||
|
||||
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
|
||||
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
|
||||
if(page)
|
||||
mypos += 1024;
|
||||
mipmap_num++;
|
||||
|
||||
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
|
||||
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
|
||||
|
||||
src += (msize_x * msize_y * bit_depth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove any existing textures that may have been overwritten
|
||||
*/
|
||||
|
||||
//osd_renderer_invalidate_textures(xpos, ypos, size_x, size_y);
|
||||
|
||||
PROFILE_SECT_EXIT("real3d");
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Access */
|
||||
/******************************************************************/
|
||||
|
||||
static BOOL trigger = 0;
|
||||
static UINT64 trigger_time;
|
||||
|
||||
/*
|
||||
* UINT32 r3d_read_32(UINT32 a);
|
||||
*
|
||||
* Reads a 32-bit word from the Real3D regions.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
*
|
||||
* Returns:
|
||||
* Data read.
|
||||
*/
|
||||
|
||||
UINT32 r3d_read_32(UINT32 a)
|
||||
{
|
||||
static UINT32 _84000000 = 0;
|
||||
|
||||
// message(0, "%08X (%08X): Real3D read32 to %08X", PPC_PC, PPC_LR, a);
|
||||
|
||||
switch (a)
|
||||
{
|
||||
/*
|
||||
* In Lost World, routine at 0x1174E0 reads all the 0x840000XX status
|
||||
* registers and at 0x117A30, bit 0x02000000 is checked for.
|
||||
*/
|
||||
|
||||
case 0x84000000:
|
||||
return (_84000000 ^= 0xFFFFFFFF);
|
||||
case 0x84000004: // unknown
|
||||
case 0x84000008:
|
||||
case 0x8400000C:
|
||||
case 0x84000010:
|
||||
case 0x84000014:
|
||||
case 0x84000018:
|
||||
case 0x8400001C:
|
||||
case 0x84000020:
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
error("Unknown R3D read: %08X: %08X\n", ppc_get_pc(), a);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* void r3d_write_32(UINT32 a, UINT32 d);
|
||||
*
|
||||
* Writes a 32-bit word to the Real3D regions.
|
||||
*
|
||||
* Parameters:
|
||||
* a = Address.
|
||||
* d = Data to write.
|
||||
*/
|
||||
|
||||
UINT32 _9C000000, _9C000004, _9C000008;
|
||||
static int texture_start_pos = 8;
|
||||
static int texture_ram_ptr = 0;
|
||||
|
||||
void r3d_write_32(UINT32 a, UINT32 d)
|
||||
{
|
||||
static UINT32 last_addr;
|
||||
|
||||
if (a >= 0x8E000000 && a <= 0x8E0FFFFF) // culling RAM
|
||||
{
|
||||
*(UINT32 *) &culling_ram_8e[a & 0xFFFFF] = BSWAP32(d);
|
||||
return;
|
||||
}
|
||||
else if (a >= 0x8C000000 && a <= 0x8C3FFFFF) // culling RAM
|
||||
{
|
||||
*(UINT32 *) &culling_ram_8c[a & 0x3FFFFF] = BSWAP32(d);
|
||||
return;
|
||||
}
|
||||
else if (a >= 0x98000000 && a <= 0x981FFFFF) // polygon RAM
|
||||
{
|
||||
// if(a >= 0x98001000 && a < 0x98002000)
|
||||
// message(1, "color table: %08X = %08X", a, BSWAP32(d));
|
||||
|
||||
*(UINT32 *) &polygon_ram[a & 0x1FFFFF] = BSWAP32(d);
|
||||
return;
|
||||
}
|
||||
else if (a >= 0x94000000 && a <= 0x940FFFFF) // texture buffer
|
||||
{
|
||||
d = BSWAP32(d);
|
||||
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
|
||||
|
||||
texture_ram_ptr += 4;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0x88000000: // trigger?
|
||||
|
||||
//message(0, "%08X (%08X): 88000000 = %08X", PPC_PC, PPC_LR, BSWAP32(d));
|
||||
|
||||
if( texture_ram_ptr > 0 ) {
|
||||
int i=0;
|
||||
while( i < texture_ram_ptr ) {
|
||||
UINT32 length = (*(UINT32*)&texture_buffer_ram[i+0] / 2) + 2;
|
||||
UINT32 header = *(UINT32*)&texture_buffer_ram[i+4];
|
||||
upload_texture( header, &texture_buffer_ram[i+8], 1 );
|
||||
i += length;
|
||||
};
|
||||
}
|
||||
texture_ram_ptr = 0;
|
||||
|
||||
return;
|
||||
case 0x90000000: // VROM texture address
|
||||
vrom_texture_address = BSWAP32(d);
|
||||
LOG("model3.log", "VROM1 ADDR = %08X\n", BSWAP32(d));
|
||||
//message(0, "VROM texture address = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
|
||||
return;
|
||||
case 0x90000004:
|
||||
vrom_texture_header = BSWAP32(d);
|
||||
LOG("model3.log", "VROM1 HEAD = %08X\n", BSWAP32(d));
|
||||
//message(0, "VROM texture header = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
|
||||
return;
|
||||
case 0x90000008:
|
||||
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
|
||||
LOG("model3.log", "VROM1 SIZE = %08X\n", BSWAP32(d));
|
||||
//message(0, "VROM texture length = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
|
||||
return;
|
||||
case 0x9000000C: // ? Virtual On 2: These are almost certainly for VROM textures as well (I was too lazy to check :P)
|
||||
vrom_texture_address = BSWAP32(d);
|
||||
LOG("model3.log", "VROM2 ADDR = %08X\n", BSWAP32(d));
|
||||
//message(0, "90000000C = %08X", BSWAP32(d));
|
||||
return;
|
||||
case 0x90000010: // ?
|
||||
vrom_texture_header = BSWAP32(d);
|
||||
LOG("model3.log", "VROM2 HEAD = %08X\n", BSWAP32(d));
|
||||
//message(0, "900000010 = %08X", BSWAP32(d));
|
||||
return;
|
||||
case 0x90000014: // ?
|
||||
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
|
||||
LOG("model3.log", "VROM2 SIZE = %08X\n", BSWAP32(d));
|
||||
//message(0, "900000014 = %08X", BSWAP32(d));
|
||||
return;
|
||||
case 0x9C000000: // ?
|
||||
//message(0, "9C000000 = %08X", BSWAP32(d));
|
||||
LOG("model3.log", "%08X = %08X\n", a, d);
|
||||
_9C000000 = BSWAP32(d);
|
||||
return;
|
||||
case 0x9C000004: // ?
|
||||
//message(0, "9C000004 = %08X", BSWAP32(d));
|
||||
LOG("model3.log", "%08X = %08X\n", a, d);
|
||||
_9C000004 = BSWAP32(d);
|
||||
return;
|
||||
case 0x9C000008: // ?
|
||||
//message(0, "9C000008 = %08X", BSWAP32(d));
|
||||
LOG("model3.log", "%08X = %08X\n", a, d);
|
||||
_9C000008 = BSWAP32(d);
|
||||
return;
|
||||
}
|
||||
|
||||
error("Unknown R3D write: %08X: %08X = %08X\n", ppc_get_pc(), a, d);
|
||||
}
|
||||
|
||||
void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
|
||||
{
|
||||
int i;
|
||||
|
||||
dst &= 0xffffff;
|
||||
|
||||
if (swap_words)
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = BSWAP32(*src++);
|
||||
*(UINT32 *)&culling_ram_8c[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = (*src++);
|
||||
*(UINT32 *)&culling_ram_8c[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
|
||||
{
|
||||
int i;
|
||||
|
||||
dst &= 0xffffff;
|
||||
|
||||
if (swap_words)
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = BSWAP32(*src++);
|
||||
*(UINT32 *)&culling_ram_8e[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = (*src++);
|
||||
*(UINT32 *)&culling_ram_8e[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
|
||||
{
|
||||
int i;
|
||||
|
||||
dst &= 0xffffff;
|
||||
|
||||
if (swap_words)
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = BSWAP32(*src++);
|
||||
*(UINT32 *) &polygon_ram[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = (*src++);
|
||||
*(UINT32 *) &polygon_ram[dst] = d;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
|
||||
{
|
||||
int i;
|
||||
|
||||
dst &= 0xffffff;
|
||||
|
||||
if (swap_words)
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = BSWAP32(*src++);
|
||||
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
|
||||
texture_ram_ptr += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < length; i+=4)
|
||||
{
|
||||
UINT32 d = (*src++);
|
||||
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
|
||||
texture_ram_ptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Real3D TAP Port */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* State (corresponding to fsm[][] Y) and Instruction Names
|
||||
*/
|
||||
|
||||
static char *state_name[] = { "Test-Logic/Reset", "Run-Test/Idle", "Select-DR-Scan",
|
||||
"Capture-DR", "Shift-DR", "Exit1-DR", "Pause-DR",
|
||||
"Exit2-DR", "Update-DR", "Select-IR-Scan",
|
||||
"Capture-IR", "Shift-IR", "Exit1-IR", "Pause-IR",
|
||||
"Exit2-IR", "Update-IR"
|
||||
};
|
||||
|
||||
/*
|
||||
* TAP Finite State Machine
|
||||
*
|
||||
* Y are states and X are outgoing paths. Constructed from information on page
|
||||
* 167 of the 3D-RAM manual.
|
||||
*/
|
||||
|
||||
#define NEXT(new_state) fsm[state][new_state]
|
||||
|
||||
static INT state; // current state
|
||||
static INT fsm[][2] = {
|
||||
{ 1, 0 }, // 0 Test-Logic/Reset
|
||||
{ 1, 2 }, // 1 Run-Test/Idle
|
||||
{ 3, 9 }, // 2 Select-DR-Scan
|
||||
{ 4, 5 }, // 3 Capture-DR
|
||||
{ 4, 5 }, // 4 Shift-DR
|
||||
{ 6, 8 }, // 5 Exit1-DR
|
||||
{ 6, 7 }, // 6 Pause-DR
|
||||
{ 4, 8 }, // 7 Exit2-DR
|
||||
{ 1, 2 }, // 8 Update-DR
|
||||
{ 10, 0 }, // 9 Select-IR-Scan
|
||||
{ 11, 12 }, // 10 Capture-IR
|
||||
{ 11, 12 }, // 11 Shift-IR
|
||||
{ 13, 15 }, // 12 Exit1-IR
|
||||
{ 13, 14 }, // 13 Pause-IR
|
||||
{ 11, 15 }, // 14 Exit2-IR
|
||||
{ 1, 2 } // 15 Update-IR
|
||||
};
|
||||
|
||||
/*
|
||||
* TAP Registers
|
||||
*/
|
||||
|
||||
static UINT64 current_instruction; // latched IR (not always equal to IR)
|
||||
static UINT64 ir; // instruction register (46 bits)
|
||||
|
||||
static UINT8 id_data[32]; // ASIC ID code data buffer
|
||||
static INT id_size; // size of ID data in bits
|
||||
static INT ptr; // current bit ptr for data
|
||||
|
||||
static BOOL tdo; // bit shifted out to TDO
|
||||
|
||||
/*
|
||||
* insert_bit():
|
||||
*
|
||||
* Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be
|
||||
* the MSB of the first byte in the buffer.
|
||||
*/
|
||||
|
||||
static void insert_bit(UINT8 *buf, INT bit_num, INT bit)
|
||||
{
|
||||
INT bit_in_byte;
|
||||
|
||||
bit_in_byte = 7 - (bit_num & 7);
|
||||
|
||||
buf[bit_num / 8] &= ~(1 << bit_in_byte);
|
||||
buf[bit_num / 8] |= (bit << bit_in_byte);
|
||||
}
|
||||
|
||||
/*
|
||||
* insert_id():
|
||||
*
|
||||
* Inserts a 32-bit ID code into the ID bit field.
|
||||
*/
|
||||
|
||||
static void insert_id(UINT32 id, INT start_bit)
|
||||
{
|
||||
INT i;
|
||||
|
||||
for (i = 31; i >= 0; i--)
|
||||
insert_bit(id_data, start_bit++, (id >> i) & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* shift():
|
||||
*
|
||||
* Shifts the data buffer right (towards LSB at byte 0) by 1 bit. The size of
|
||||
* the number of bits must be specified. The bit shifted out of the LSB is
|
||||
* returned.
|
||||
*/
|
||||
|
||||
static BOOL shift(UINT8 *data, INT num_bits)
|
||||
{
|
||||
INT i;
|
||||
BOOL shift_out, shift_in;
|
||||
|
||||
/*
|
||||
* This loop takes care of all the fully-filled bytes
|
||||
*/
|
||||
|
||||
shift_in = 0;
|
||||
for (i = 0; i < num_bits / 8; i++)
|
||||
{
|
||||
shift_out = data[i] & 1;
|
||||
data[i] >>= 1;
|
||||
data[i] |= (shift_in << 7);
|
||||
shift_in = shift_out; // carry over to next element's MSB
|
||||
}
|
||||
|
||||
/*
|
||||
* Take care of the last partial byte (if there is one)
|
||||
*/
|
||||
|
||||
if ((num_bits & 7) != 0)
|
||||
{
|
||||
shift_out = (data[i] >> (8 - (num_bits & 7))) & 1;
|
||||
data[i] >>= 1;
|
||||
data[i] |= (shift_in << 7);
|
||||
}
|
||||
|
||||
return shift_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* BOOL tap_read(void);
|
||||
*
|
||||
* Reads TDO.
|
||||
*
|
||||
* Returns:
|
||||
* TDO.
|
||||
*/
|
||||
|
||||
BOOL tap_read(void)
|
||||
{
|
||||
return tdo;
|
||||
}
|
||||
|
||||
/*
|
||||
* void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst);
|
||||
*
|
||||
* Writes to the TAP. State changes only occur on the rising edge of the clock
|
||||
* (tck = 1.)
|
||||
*
|
||||
* Parameters:
|
||||
* tck = Clock.
|
||||
* tms = Test mode select.
|
||||
* tdi = Serial data input. Must be 0 or 1 only!
|
||||
* trst = Reset.
|
||||
*/
|
||||
|
||||
void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst)
|
||||
{
|
||||
if (!tck)
|
||||
return;
|
||||
|
||||
state = NEXT(tms);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 3: // Capture-DR
|
||||
|
||||
/*
|
||||
* Read ASIC IDs.
|
||||
*
|
||||
* The ID Sequence is:
|
||||
* - Jupiter
|
||||
* - Mercury
|
||||
* - Venus
|
||||
* - Earth
|
||||
* - Mars
|
||||
* - Mars (again)
|
||||
*
|
||||
* Note that different Model 3 steps have different chip
|
||||
* revisions, hence the different IDs returned below.
|
||||
*
|
||||
* On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve
|
||||
* the ID codes but Step 2.0 is a little weirder. It seems to use this
|
||||
* and either the state of the TAP after reset or other instructions
|
||||
* to read the IDs as well. This can be emulated in one of 2 ways:
|
||||
* Ignore the instruction and always load up the data or load the
|
||||
* data on TAP reset and when the instruction is issued.
|
||||
*/
|
||||
|
||||
if (m3_config.step == 0x10)
|
||||
{
|
||||
insert_id(0x116C7057, 1 + 0 * 32);
|
||||
insert_id(0x216C3057, 1 + 1 * 32);
|
||||
insert_id(0x116C4057, 1 + 2 * 32);
|
||||
insert_id(0x216C5057, 1 + 3 * 32);
|
||||
insert_id(0x116C6057, 1 + 4 * 32 + 1);
|
||||
insert_id(0x116C6057, 1 + 5 * 32 + 1);
|
||||
}
|
||||
else if (m3_config.step == 0x15)
|
||||
{
|
||||
insert_id(0x316C7057, 1 + 0 * 32);
|
||||
insert_id(0x316C3057, 1 + 1 * 32);
|
||||
insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057
|
||||
insert_id(0x316C5057, 1 + 3 * 32);
|
||||
insert_id(0x216C6057, 1 + 4 * 32 + 1);
|
||||
insert_id(0x216C6057, 1 + 5 * 32 + 1);
|
||||
}
|
||||
else if (m3_config.step >= 0x20)
|
||||
{
|
||||
insert_id(0x416C7057, 1 + 0 * 32);
|
||||
insert_id(0x416C3057, 1 + 1 * 32);
|
||||
insert_id(0x316C4057, 1 + 2 * 32);
|
||||
insert_id(0x416C5057, 1 + 3 * 32);
|
||||
insert_id(0x316C6057, 1 + 4 * 32 + 1);
|
||||
insert_id(0x316C6057, 1 + 5 * 32 + 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4: // Shift-DR
|
||||
|
||||
tdo = shift(id_data, id_size);
|
||||
break;
|
||||
|
||||
case 10: // Capture-IR
|
||||
|
||||
/*
|
||||
* Load lower 2 bits with 01 as per IEEE 1149.1-1990
|
||||
*/
|
||||
|
||||
ir = 1;
|
||||
break;
|
||||
|
||||
case 11: // Shift-IR
|
||||
|
||||
/*
|
||||
* Shift IR towards output and load in new data from TDI
|
||||
*/
|
||||
|
||||
tdo = ir & 1; // shift LSB to output
|
||||
ir >>= 1;
|
||||
ir |= ((UINT64) tdi << 45);
|
||||
break;
|
||||
|
||||
case 15: // Update-IR
|
||||
|
||||
/*
|
||||
* Latch IR (technically, this should occur on the falling edge of
|
||||
* TCK)
|
||||
*/
|
||||
|
||||
ir &= 0x3fffffffffff;
|
||||
current_instruction = ir;
|
||||
|
||||
#if 0
|
||||
{
|
||||
UINT8 *i = (UINT8 *) &ir;
|
||||
LOG("tap.log", "current instruction set: %02X%02X%02X%02X%02X%02X\n", i[5], i[4], i[3], i[2], i[1], i[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (state == 4)
|
||||
LOG("tap.log", "state: Shift-DR %d\n", tdi);
|
||||
else if (state == 11)
|
||||
LOG("tap.log", "state: Shift-IR %d\n", tdi);
|
||||
else
|
||||
LOG("tap.log", "state: %s\n", state_name[state]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void tap_reset(void);
|
||||
*
|
||||
* Resets the TAP (simulating a power up or SCAN_RST signal.)
|
||||
*/
|
||||
|
||||
void tap_reset(void)
|
||||
{
|
||||
id_size = 197; // 197 bits
|
||||
|
||||
state = 0; // test-logic/reset
|
||||
}
|
49
core/r3d.h
49
core/r3d.h
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* r3d.h
|
||||
*
|
||||
* Real3D Model 3 graphics system header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_R3D_H
|
||||
#define INCLUDED_R3D_H
|
||||
|
||||
extern void r3d_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *);
|
||||
extern void r3d_shutdown(void);
|
||||
extern void r3d_reset(void);
|
||||
|
||||
extern void r3d_save_state(FILE *);
|
||||
extern void r3d_load_state(FILE *);
|
||||
|
||||
extern UINT32 r3d_read_32(UINT32 a);
|
||||
extern void r3d_write_32(UINT32 a, UINT32 d);
|
||||
|
||||
extern void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
|
||||
extern void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
|
||||
extern void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
|
||||
extern void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words);
|
||||
|
||||
|
||||
extern void tap_reset(void);
|
||||
extern BOOL tap_read(void);
|
||||
extern void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst);
|
||||
|
||||
#endif // INCLUDED_R3D_H
|
||||
|
855
core/render.c
855
core/render.c
|
@ -1,855 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* render.c
|
||||
*
|
||||
* Rendering engine. Responsible for both Real3D graphics emulation and
|
||||
* for drawing the tile layers with correct priorities.
|
||||
*
|
||||
* NOTES:
|
||||
* ------
|
||||
*
|
||||
* - The "hardware coordinate system" is the default Model 3 coordinate system
|
||||
* before any matrices are applied. In it, +X is to the right, +Y is down,
|
||||
* and +Z is further into the screen.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
extern BOOL render_scene(void);
|
||||
|
||||
#define LOG_MODEL_ADDR 0 // logs model addresses to models.log
|
||||
|
||||
/******************************************************************/
|
||||
/* Useful Macros */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Single-Precision Floating Point
|
||||
*/
|
||||
|
||||
#define GET_FLOAT(ptr) (*((float *) ptr))
|
||||
|
||||
/*
|
||||
* Trigonometry
|
||||
*/
|
||||
|
||||
#define PI 3.14159265358979323846264338327
|
||||
#define CONVERT_TO_DEGREES(a) (((a) * 180.0) / PI)
|
||||
|
||||
/******************************************************************/
|
||||
/* Private Data */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* Memory Regions
|
||||
*
|
||||
* These will be passed to us before rendering begins.
|
||||
*/
|
||||
|
||||
static UINT8 *culling_ram_8e; // pointer to Real3D culling RAM
|
||||
static UINT8 *culling_ram_8c; // pointer to Real3D culling RAM
|
||||
static UINT8 *polygon_ram; // pointer to Real3D polygon RAM
|
||||
static UINT8 *texture_ram; // pointer to Real3D texture RAM
|
||||
static UINT8 *vrom; // pointer to VROM
|
||||
|
||||
/*
|
||||
* Matrix Base
|
||||
*/
|
||||
|
||||
static float *matrix_base; // current scene's matrix table
|
||||
static float *lod_base; // current scene's LOD table
|
||||
|
||||
/*
|
||||
* Matrix Conversion Tables
|
||||
*
|
||||
* These tables map Model 3 matrix indices to column-major form.
|
||||
*/
|
||||
|
||||
static INT normal_matrix[4*4] = // normal matrices
|
||||
{
|
||||
3*4+0, 3*4+1, 3*4+2,
|
||||
0*4+0, 1*4+0, 2*4+0,
|
||||
0*4+1, 1*4+1, 2*4+1,
|
||||
0*4+2, 1*4+2, 2*4+2
|
||||
};
|
||||
static INT coord_matrix[4*4] = // coordinate system matrix
|
||||
{
|
||||
3*4+2, 3*4+0, 3*4+1,
|
||||
0*4+2, 1*4+2, 2*4+2,
|
||||
0*4+0, 1*4+0, 2*4+0,
|
||||
0*4+1, 1*4+1, 2*4+1
|
||||
};
|
||||
|
||||
/******************************************************************/
|
||||
/* Function Prototypes */
|
||||
/******************************************************************/
|
||||
|
||||
static void draw_block(UINT32 *);
|
||||
|
||||
/******************************************************************/
|
||||
/* TEMPORARY Model Tracking Code */
|
||||
/* */
|
||||
/* This code builds a list of VROM model addresses as they are */
|
||||
/* referenced. */
|
||||
/******************************************************************/
|
||||
|
||||
#if LOG_MODEL_ADDR
|
||||
|
||||
static struct model_addr
|
||||
{
|
||||
UINT32 addr; // model address in VROM
|
||||
INT num_polys; // number of polygons in model
|
||||
struct model_addr *next; // next in list
|
||||
} *model_addr_list = NULL;
|
||||
|
||||
static INT count_polys(UINT32 *mdl)
|
||||
{
|
||||
UINT32 link_data, mask;
|
||||
INT num_polys = 0, num_verts, i, stop;
|
||||
|
||||
do
|
||||
{
|
||||
stop = BSWAP32(mdl[1]) & 4; // get stop bit
|
||||
link_data = BSWAP32(mdl[0]); // link data
|
||||
|
||||
/*
|
||||
* Count how many vertices the polygon has by subtracting the number
|
||||
* of vertices used from the previous polygon from 4 (quad) or 3 (tri)
|
||||
*/
|
||||
|
||||
num_verts = (link_data & 0x40) ? 4 : 3;
|
||||
mask = 8;
|
||||
for (i = 0; i < 4 && num_verts; i++)
|
||||
{
|
||||
if ((link_data & mask))
|
||||
--num_verts;
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance to next polygon
|
||||
*/
|
||||
|
||||
mdl += 7 + num_verts * 4;
|
||||
++num_polys; // increment count
|
||||
} while (!stop);
|
||||
|
||||
return num_polys;
|
||||
}
|
||||
|
||||
static void record_model(UINT32 addr)
|
||||
{
|
||||
struct model_addr *l;
|
||||
|
||||
/*
|
||||
* Search for this entry -- if already in the list, exit
|
||||
for (l = model_addr_list; l != NULL; l = l->next)
|
||||
{
|
||||
if (addr == l->addr)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add new entry
|
||||
*/
|
||||
|
||||
l = malloc(sizeof(struct model_addr));
|
||||
if (l == NULL)
|
||||
error("out of memory in record_model()");
|
||||
l->addr = addr;
|
||||
l->num_polys = count_polys((UINT32 *) &vrom[addr * 4]);
|
||||
l->next = model_addr_list;
|
||||
model_addr_list = l;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
/* Real3D Address Translation */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* translate_scene_graph_address():
|
||||
*
|
||||
* Returns a pointer to scene graph (culling RAM) memory given a scene graph
|
||||
* address (only lower 24 bits are relevant.)
|
||||
*/
|
||||
|
||||
static UINT32 *translate_scene_graph_address(UINT32 addr)
|
||||
{
|
||||
addr &= 0x00FFFFFF; // only lower 24 bits matter
|
||||
if ((addr & 0x00800000)) // 8E culling RAM
|
||||
{
|
||||
if (addr >= 0x00840000)
|
||||
error("translate_scene_graph_address(): addr = %08X", addr);
|
||||
return (UINT32 *) &culling_ram_8e[(addr & 0x0003FFFF) * 4];
|
||||
}
|
||||
else // 8C culling RAM
|
||||
{
|
||||
//if (addr >= 0x00100000)
|
||||
// error("translate_scene_graph_address(): addr = %08X", addr);
|
||||
return (UINT32 *) &culling_ram_8c[(addr & 0x000FFFFF) * 4];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* draw_model():
|
||||
*
|
||||
* Translates the model address and draws the model (accounting for
|
||||
* endianness.)
|
||||
*/
|
||||
|
||||
static void draw_model(UINT32 addr)
|
||||
{
|
||||
addr &= 0x00FFFFFF; // only lower 24 bits matter
|
||||
if (addr > 0x00100000) // VROM
|
||||
{
|
||||
#if LOG_MODEL_ADDR
|
||||
record_model(addr); // TEMP: this tracks model addresses in VROM
|
||||
#endif
|
||||
osd_renderer_draw_model((UINT32 *) &vrom[(addr & 0x00FFFFFF) * 4], addr, 0);
|
||||
}
|
||||
else // polygon RAM (may actually be 4MB)
|
||||
{
|
||||
osd_renderer_draw_model((UINT32 *) &polygon_ram[(addr & 0x000FFFFF) * 4], addr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Matrices */
|
||||
/* */
|
||||
/* Model 3 matrices are 4x3 in size (they lack the translational */
|
||||
/* component.) They are layed out like this: */
|
||||
/* */
|
||||
/* 03 04 05 00 */
|
||||
/* 06 07 08 01 */
|
||||
/* 09 10 11 02 */
|
||||
/* */
|
||||
/* Matrix #0 is for coordinate system selection, it is layed out */
|
||||
/* as: */
|
||||
/* */
|
||||
/* 06 07 08 01 */
|
||||
/* 09 10 11 02 */
|
||||
/* 03 04 05 00 */
|
||||
/* */
|
||||
/* By default, the Model 3 appears to have a form of left-handed */
|
||||
/* coordinate system where positive Z means further away from the */
|
||||
/* camera and the positive Y axis points downward along the */
|
||||
/* screen. */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* get_matrix():
|
||||
*
|
||||
* Reads a Model 3 matrix and converts it to column-major 4x4 form using the
|
||||
* supplied conversion table.
|
||||
*/
|
||||
|
||||
static void get_matrix(MATRIX dest, INT convert[3*4], UINT num)
|
||||
{
|
||||
INT m = num * 12, i;
|
||||
|
||||
for (i = 0; i < 3*4; i++) // fetch Model 3 4x3 matrix
|
||||
dest[convert[i]] = matrix_base[m + i];
|
||||
dest[0*4+3] = 0.0; // fill in translation component to make 4x4
|
||||
dest[1*4+3] = 0.0;
|
||||
dest[2*4+3] = 0.0;
|
||||
dest[3*4+3] = 1.0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
/* Scene Graph Traversal */
|
||||
/******************************************************************/
|
||||
|
||||
int list_depth = 0;
|
||||
|
||||
/*
|
||||
* draw_list():
|
||||
*
|
||||
* Processes a list backwards. Each list element references a block.
|
||||
*/
|
||||
|
||||
static void draw_list(UINT32 *list)
|
||||
{
|
||||
UINT32 *list_ptr;
|
||||
UINT32 addr;
|
||||
|
||||
list_ptr = list;
|
||||
|
||||
if (list_depth > 2)
|
||||
return;
|
||||
|
||||
list_depth++;
|
||||
|
||||
/*
|
||||
* Go to end of list
|
||||
*/
|
||||
|
||||
while (1)
|
||||
{
|
||||
addr = *list_ptr;
|
||||
if ((addr & 0x02000000)) // last pointer in list
|
||||
{
|
||||
//--list_ptr;
|
||||
break;
|
||||
}
|
||||
if (addr == 0 || addr == 0x800800) // safeguard in case memory hasn't been set up
|
||||
{
|
||||
--list_ptr;
|
||||
break;
|
||||
}
|
||||
++list_ptr;
|
||||
}
|
||||
|
||||
while (list_ptr >= list)
|
||||
{
|
||||
addr = *list_ptr;
|
||||
if ((addr & 0x00FFFFFF) != 0x00FFFFFF)
|
||||
draw_block(translate_scene_graph_address(addr));
|
||||
--list_ptr; // next element
|
||||
}
|
||||
|
||||
list_depth--;
|
||||
}
|
||||
|
||||
/*
|
||||
* draw_pointer_list():
|
||||
*
|
||||
* Draws a 4-element pointer list for model LOD selection.
|
||||
*/
|
||||
|
||||
static void draw_pointer_list(UINT lod_num, UINT32* list)
|
||||
{
|
||||
float *lod_control = (float *)((UINT32)lod_base + lod_num * 8);
|
||||
|
||||
/*
|
||||
* Perform the actual LOD calculation, select the LOD model
|
||||
* to draw -- and perform additional LOD blending.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
printf( "LOD control = %f, %f\n"
|
||||
" %f, %f\n"
|
||||
" %f, %f\n"
|
||||
" %f, %f\n",
|
||||
lod_control[0], lod_control[1],
|
||||
lod_control[2], lod_control[3],
|
||||
lod_control[4], lod_control[5],
|
||||
lod_control[6], lod_control[7]
|
||||
);
|
||||
#endif
|
||||
|
||||
if(1)
|
||||
draw_model( list[0] );
|
||||
else if(0)
|
||||
draw_model( list[1] );
|
||||
else if(0)
|
||||
draw_model( list[2] );
|
||||
else
|
||||
draw_model( list[3] );
|
||||
}
|
||||
|
||||
/*
|
||||
* draw_block():
|
||||
*
|
||||
* Traverses a 10- (or 8-) word block (culling node.) The blocks have this
|
||||
* format:
|
||||
*
|
||||
* 0: ID code (upper 22 bits) and control bits
|
||||
* 1: Scaling? Not present in Step 1.0
|
||||
* 2: Flags? Not present in Step 1.0
|
||||
* 3: Lower 12 bits are matrix select. Upper bits contain flags.
|
||||
* 4: X translation (floating point)
|
||||
* 5: Y translation
|
||||
* 6: Z translation
|
||||
* 7: Pointer to model data, list, or pointer list
|
||||
* 8: Pointer to next block
|
||||
* 9: Pair of 16-bit values, related to rendering order
|
||||
*
|
||||
* Lower 16 bits of word 2 control "texture offset": -P-X XXXX X--Y YYYY, same
|
||||
* as in polygon headers. The purpose of this is unknown.
|
||||
*/
|
||||
|
||||
static void draw_block(UINT32 *block)
|
||||
{
|
||||
MATRIX m;
|
||||
UINT32 addr;
|
||||
INT offset;
|
||||
INT txoffs_x, txoffs_y, txoffs_page;
|
||||
|
||||
if (m3_config.step == 0x10) // Step 1.0 blocks are only 8 words
|
||||
offset = 2;
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
addr = block[7 - offset];
|
||||
|
||||
txoffs_x = ((block[2] >> 7) & 0x3F) * 32;
|
||||
txoffs_y = (block[2] & 0x1F) * 32;
|
||||
txoffs_page = !!(block[2] & 0x4000);
|
||||
|
||||
/*
|
||||
* Apply matrix and translation
|
||||
*/
|
||||
|
||||
get_matrix(m, normal_matrix, block[3 - offset] & 0xFFF);
|
||||
osd_renderer_push_matrix();
|
||||
|
||||
if ((block[0] & 0x10)) // this bit appears to control translation
|
||||
{
|
||||
osd_renderer_translate_matrix(GET_FLOAT(&block[4 - offset]), GET_FLOAT(&block[5 - offset]), GET_FLOAT(&block[6 - offset]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((block[3 - offset] & 0xFFF) != 0)
|
||||
osd_renderer_multiply_matrix(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit 0x08 of word 0 indicates a pointer list
|
||||
*/
|
||||
|
||||
if ((block[0] & 0x08))
|
||||
draw_pointer_list((block[3 - offset] >> 12) & 127, translate_scene_graph_address(addr));
|
||||
else
|
||||
{
|
||||
if (addr != 0x0FFFFFFF && addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid?
|
||||
{
|
||||
switch ((addr >> 24) & 0xFF) // decide what address points to
|
||||
{
|
||||
case 0x00: // block
|
||||
draw_block(translate_scene_graph_address(addr));
|
||||
break;
|
||||
case 0x01: // model
|
||||
case 0x03: // model (Scud Race, model in VROM)
|
||||
draw_model(addr);
|
||||
break;
|
||||
case 0x04: // list
|
||||
draw_list(translate_scene_graph_address(addr));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osd_renderer_pop_matrix();
|
||||
|
||||
/*
|
||||
* NOTE: This second pointer needs to be investigated further.
|
||||
*/
|
||||
|
||||
addr = block[8 - offset];
|
||||
if (addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid?
|
||||
draw_block(translate_scene_graph_address(addr));
|
||||
}
|
||||
|
||||
/*
|
||||
* get_viewport_data():
|
||||
*
|
||||
* Sets up a VIEWPORT structure. Is passed a pointer to the main node.
|
||||
*/
|
||||
|
||||
static void get_viewport_data(VIEWPORT *vp, UINT32 *node)
|
||||
{
|
||||
vp->x = (node[0x1A] & 0xFFFF) >> 4; // position is in 12.4 format
|
||||
vp->y = (node[0x1A] >> 16) >> 4;
|
||||
vp->width = (node[0x14] & 0xFFFF) >> 2; // size is in 14.2 format
|
||||
vp->height = (node[0x14] >> 16) >> 2;
|
||||
|
||||
vp->left = asin(GET_FLOAT(&node[0x0C]));
|
||||
vp->right = asin(GET_FLOAT(&node[0x10]));
|
||||
vp->up = asin(GET_FLOAT(&node[0x0E]));
|
||||
vp->down = asin(GET_FLOAT(&node[0x12]));
|
||||
|
||||
vp->left = CONVERT_TO_DEGREES(vp->left);
|
||||
vp->right = CONVERT_TO_DEGREES(vp->right);
|
||||
vp->up = CONVERT_TO_DEGREES(vp->up);
|
||||
vp->down = CONVERT_TO_DEGREES(vp->down);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_light_data():
|
||||
*
|
||||
* Sets up a LIGHT structure based on ambient sun light. The sun vector
|
||||
* indicates the direction of the parallel sun light. It is specified in the
|
||||
* hardware coordinate system and must be applied before any matrices.
|
||||
*/
|
||||
|
||||
static void get_light_data(LIGHT* l, UINT32* node)
|
||||
{
|
||||
memset( l, 0, sizeof(LIGHT) );
|
||||
l->u = GET_FLOAT(&node[5]); // it seems X needs to be inverted
|
||||
l->v = GET_FLOAT(&node[6]);
|
||||
l->w = GET_FLOAT(&node[4]);
|
||||
|
||||
l->diffuse_intensity = GET_FLOAT(&node[7]);
|
||||
l->ambient_intensity = (UINT8)((node[0x24] >> 8) & 0xFF) / 256.0f;
|
||||
|
||||
LOG("model3.log", "sun light = (%f,%f,%f),%f,(%02X=%f)\n", l->u, l->v, l->w, l->diffuse_intensity, ((node[0x24] >> 8) & 0xFF), l->ambient_intensity);
|
||||
|
||||
l->color = 0xFFFFFFFF;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* draw_viewport():
|
||||
*
|
||||
* Traverses the main (scene descriptor) nodes and draws the ones with the
|
||||
* given viewport priority.
|
||||
*/
|
||||
|
||||
static void draw_viewport(UINT pri, UINT32 addr)
|
||||
{
|
||||
MATRIX m;
|
||||
VIEWPORT vp;
|
||||
LIGHT sun;
|
||||
UINT32 *node;
|
||||
UINT32 next_addr, ptr;
|
||||
|
||||
node = translate_scene_graph_address(addr);
|
||||
|
||||
/*
|
||||
* Recurse until the last node has been reached
|
||||
*/
|
||||
|
||||
next_addr = node[1];
|
||||
if (next_addr == 0) // culling RAM probably hasn't been set up yet...
|
||||
return;
|
||||
if (next_addr != 0x01000000)
|
||||
draw_viewport(pri, next_addr);
|
||||
|
||||
/*
|
||||
* Draw this node if the priority matches
|
||||
*/
|
||||
|
||||
if (pri == ((node[0] >> 3) & 3))
|
||||
{
|
||||
/*
|
||||
* Set up viewport and matrix table base
|
||||
*/
|
||||
|
||||
get_viewport_data(&vp, node);
|
||||
osd_renderer_set_viewport(&vp);
|
||||
matrix_base = (float *) translate_scene_graph_address(node[0x16]);
|
||||
lod_base = (float *) translate_scene_graph_address(node[0x17]);
|
||||
|
||||
/*
|
||||
* Lighting -- seems to work nice if applied before coordinate system
|
||||
* selection but I haven't done a thorough check.
|
||||
*/
|
||||
|
||||
get_light_data(&sun, node);
|
||||
sun.type = LIGHT_PARALLEL;
|
||||
osd_renderer_set_light( 0, &sun );
|
||||
|
||||
/*
|
||||
* Set coordinate system (matrix 0)
|
||||
*/
|
||||
|
||||
get_matrix(m, coord_matrix, 0);
|
||||
osd_renderer_set_coordinate_system(m);
|
||||
|
||||
/*
|
||||
* Process a block or list. So far, no other possibilities have been
|
||||
* seen here...
|
||||
*/
|
||||
|
||||
ptr = node[2];
|
||||
|
||||
switch ((ptr >> 24) & 0xFF)
|
||||
{
|
||||
case 0x00: // block
|
||||
draw_block(translate_scene_graph_address(node[2]));
|
||||
break;
|
||||
//case 0x04: // list
|
||||
// draw_list(translate_scene_graph_address(node[2]));
|
||||
// break;
|
||||
default: // unknown
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
/* Frame Update */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* do_3d():
|
||||
*
|
||||
* Draw the complete Real3D frame.
|
||||
*/
|
||||
|
||||
static void do_3d(void)
|
||||
{
|
||||
INT i;
|
||||
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
osd_renderer_clear(0, 1); // clear Z-buffer
|
||||
osd_renderer_begin_3d_scene();
|
||||
draw_viewport(i, 0x00800000);
|
||||
osd_renderer_end_3d_scene();
|
||||
|
||||
LOG("model3.log", "GOT HERE\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void set_color_offset(UINT32 reg);
|
||||
*
|
||||
* Sets color offset to the value specified by reg, and updates the
|
||||
* renderer status.
|
||||
*/
|
||||
|
||||
static void set_color_offset(UINT32 reg)
|
||||
{
|
||||
FLOAT32 r, g, b;
|
||||
|
||||
/*
|
||||
* Color offset is specified as a triplet of signed 8-bit values, one
|
||||
* for each color component. 0 is the default value, it doesn't modify
|
||||
* the output color. It's equal to disabling the color offset (though
|
||||
* some bit in the tilegen ports could be used for this).
|
||||
* 0x80 (-128) is the minimum value, and corresponds to complete black.
|
||||
* 0x7F (+127) is the maximum value, and corresponds to complete white.
|
||||
*/
|
||||
|
||||
r = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 8) & 0xFF))) / 128.0f;
|
||||
g = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 16) & 0xFF))) / 128.0f;
|
||||
b = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 24) & 0xFF))) / 128.0f;
|
||||
|
||||
// osd_renderer_set_color_offset(r != 0.0f && g != 0.0f && b != 0.0f, r, g, b);
|
||||
}
|
||||
|
||||
/*
|
||||
* void render_frame(void);
|
||||
*
|
||||
* Draws the entire frame (all 3D and 2D graphics) and blits it.
|
||||
*/
|
||||
|
||||
void render_frame(void)
|
||||
{
|
||||
UINT32 renderer_features;
|
||||
int i, j;
|
||||
UINT32 color_offset;
|
||||
LOG("model3.log", "RENDER START\n");
|
||||
|
||||
tilegen_update();
|
||||
|
||||
renderer_features = osd_renderer_get_features();
|
||||
|
||||
if (renderer_features & RENDERER_FEATURE_PRIORITY)
|
||||
{
|
||||
// this is codepath for new-style renderers that support priorities
|
||||
{
|
||||
UINT32 *priority = tilegen_get_priority_buffer();
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
{
|
||||
int pitch;
|
||||
UINT8 *buffer;
|
||||
osd_renderer_get_priority_buffer(i, &buffer, &pitch);
|
||||
|
||||
for (j=0; j < 512; j++)
|
||||
{
|
||||
if (tilegen_is_priority_enabled())
|
||||
{
|
||||
buffer[j*pitch] = (priority[j] >> ((3-i) * 8)) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < 2) buffer[j*pitch] = 0xff;
|
||||
else buffer[j*pitch] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
osd_renderer_free_priority_buffer(i);
|
||||
}
|
||||
}
|
||||
|
||||
osd_renderer_clear(1, 1); // clear both the frame and Z-buffer
|
||||
|
||||
// set_color_offset(tilegen_read_32(0x44));
|
||||
|
||||
/*if (tilegen_is_layer_enabled(3))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(3);
|
||||
color_offset = tilegen_get_layer_color_offset(3);
|
||||
osd_renderer_draw_layer(3, color_offset, scroll & 0xffff, scroll >> 16);
|
||||
}
|
||||
if (tilegen_is_layer_enabled(2))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(2);
|
||||
color_offset = tilegen_get_layer_color_offset(2);
|
||||
osd_renderer_draw_layer(2, color_offset, scroll & 0xffff, scroll >> 16);
|
||||
}*/
|
||||
|
||||
for (i=3; i >= 0; i--)
|
||||
{
|
||||
if (tilegen_is_layer_enabled(i))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(i);
|
||||
color_offset = tilegen_get_layer_color_offset(i);
|
||||
osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
do_3d();
|
||||
|
||||
for (i=3; i >= 0; i--)
|
||||
{
|
||||
if (tilegen_is_layer_enabled(i))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(i);
|
||||
color_offset = tilegen_get_layer_color_offset(i);
|
||||
osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this codepath is for the old-style renderers
|
||||
osd_renderer_clear(1, 1); // clear both the frame and Z-buffer
|
||||
|
||||
if (tilegen_is_layer_enabled(3))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(3);
|
||||
color_offset = tilegen_get_layer_color_offset(3);
|
||||
osd_renderer_draw_layer(3, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
|
||||
}
|
||||
if (tilegen_is_layer_enabled(2))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(2);
|
||||
color_offset = tilegen_get_layer_color_offset(2);
|
||||
osd_renderer_draw_layer(2, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
|
||||
}
|
||||
|
||||
do_3d();
|
||||
|
||||
if (tilegen_is_layer_enabled(1))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(1);
|
||||
color_offset = tilegen_get_layer_color_offset(1);
|
||||
osd_renderer_draw_layer(1, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
|
||||
}
|
||||
if (tilegen_is_layer_enabled(0))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(0);
|
||||
color_offset = tilegen_get_layer_color_offset(0);
|
||||
osd_renderer_draw_layer(0, color_offset, scroll & 0xffff, scroll >> 16, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/*{
|
||||
double time = (double)(counter_end - counter_start) / (double)counter_frequency;
|
||||
printf("Rendering time: %f ms\n", time*1000.0);
|
||||
}*/
|
||||
|
||||
// set_color_offset(tilegen_read_32(0x40));
|
||||
|
||||
// osd_renderer_draw_layer(1);
|
||||
|
||||
/*if (tilegen_is_layer_enabled(1))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(1);
|
||||
color_offset = tilegen_get_layer_color_offset(1);
|
||||
osd_renderer_draw_layer(1, color_offset, scroll & 0xffff, scroll >> 16);
|
||||
}
|
||||
if (tilegen_is_layer_enabled(0))
|
||||
{
|
||||
UINT32 scroll = tilegen_get_layer_scroll_pos(0);
|
||||
color_offset = tilegen_get_layer_color_offset(0);
|
||||
osd_renderer_draw_layer(0, color_offset, scroll & 0xffff, scroll >> 16);
|
||||
}*/
|
||||
|
||||
LOG("model3.log", "RENDER END\n");
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
/* Initialization and Shutdown */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
|
||||
* UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr,
|
||||
* UINT8 *vrom_ptr);
|
||||
*
|
||||
* Initializes the renderer by receiving the Real3D memory regions. Passes
|
||||
* the memory to the OSD renderer.
|
||||
*
|
||||
* Parameters:
|
||||
* culling_ram_8e_ptr = Pointer to Real3D culling RAM at 0x8E000000.
|
||||
* culling_ram_8c_ptr = Pointer to Real3D culling RAM at 0x8C000000.
|
||||
* polygon_ram_ptr = Pointer to Real3D polygon RAM.
|
||||
* texture_ram_ptr = Pointer to Real3D texture RAM.
|
||||
* vrom_ptr = Pointer to VROM.
|
||||
*/
|
||||
|
||||
void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
|
||||
UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr,
|
||||
UINT8 *vrom_ptr)
|
||||
{
|
||||
culling_ram_8e = culling_ram_8e_ptr;
|
||||
culling_ram_8c = culling_ram_8c_ptr;
|
||||
polygon_ram = polygon_ram_ptr;
|
||||
texture_ram = texture_ram_ptr;
|
||||
vrom = vrom_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* void render_shutdown(void);
|
||||
*
|
||||
* Shuts down the rendering engine.
|
||||
*/
|
||||
|
||||
void render_shutdown(void)
|
||||
{
|
||||
#if LOG_MODEL_ADDR
|
||||
// TEMP code to print out model list
|
||||
|
||||
FILE *fp;
|
||||
struct model_addr *l, *next;
|
||||
|
||||
fp = fopen("models.log", "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("failed to write models.log\n");
|
||||
return;
|
||||
}
|
||||
|
||||
l = model_addr_list;
|
||||
while (l != NULL)
|
||||
{
|
||||
fprintf(fp, "addr = %08X\tnum_polys = %d\n", l->addr, l->num_polys);
|
||||
next = l->next;
|
||||
free(l);
|
||||
l = next;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#endif
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* render.h
|
||||
*
|
||||
* Rendering engine header. OSD renderers will want to include this because
|
||||
* some important data structures are defined here.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_RENDER_H
|
||||
#define INCLUDED_RENDER_H
|
||||
|
||||
/******************************************************************/
|
||||
/* Data Structures */
|
||||
/******************************************************************/
|
||||
|
||||
/*
|
||||
* MATRIX
|
||||
*
|
||||
* A 4x4 matrix stored in column-major (OpenGL) format.
|
||||
*/
|
||||
|
||||
typedef float MATRIX [4*4];
|
||||
|
||||
/*
|
||||
* VIEWPORT
|
||||
*
|
||||
* Viewport and projection data. The field-of-view angles are in degrees. The
|
||||
* coordinates and size of the viewport are truncated from Model 3's fixed-
|
||||
* point formats to integers.
|
||||
*
|
||||
* The viewport coordinate system maps directly to the Model 3's physical
|
||||
* resolution and its origin is at the bottom-left corner of the screen.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT x, y, width, height; // viewport position and size.
|
||||
double up, down, left, right; // FOV angles from center
|
||||
} VIEWPORT;
|
||||
|
||||
/*
|
||||
* LIGHT
|
||||
*/
|
||||
|
||||
enum {
|
||||
LIGHT_PARALLEL,
|
||||
LIGHT_POSITIONAL,
|
||||
LIGHT_SPOT
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT type;
|
||||
float u,v,w; // Direction vector
|
||||
float x,y,z; // Position for point light
|
||||
float diffuse_intensity;
|
||||
float ambient_intensity;
|
||||
UINT32 color;
|
||||
} LIGHT;
|
||||
|
||||
/******************************************************************/
|
||||
/* Functions */
|
||||
/******************************************************************/
|
||||
|
||||
extern void render_frame(void);
|
||||
extern void render_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *);
|
||||
extern void render_shutdown(void);
|
||||
|
||||
#endif // INCLUDED_RENDER_H
|
604
core/romparse.c
604
core/romparse.c
|
@ -1,604 +0,0 @@
|
|||
#include "model3.h"
|
||||
#include "expat.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ELEMENT_NONE = 1,
|
||||
ELEMENT_GAMELIST,
|
||||
ELEMENT_GAME,
|
||||
ELEMENT_DESCRIPTION,
|
||||
ELEMENT_YEAR,
|
||||
ELEMENT_MANUFACTURER,
|
||||
ELEMENT_STEP,
|
||||
ELEMENT_CROMSIZE,
|
||||
ELEMENT_ROM,
|
||||
ELEMENT_PATCH,
|
||||
ELEMENT_BRIDGE,
|
||||
ELEMENT_INPUT,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ATTR_ROM_TYPE = 1,
|
||||
ATTR_ROM_NAME,
|
||||
ATTR_ROM_SIZE,
|
||||
ATTR_ROM_CRC,
|
||||
ATTR_ROM_SHA1,
|
||||
ATTR_GAME_NAME,
|
||||
ATTR_GAME_PARENT,
|
||||
ATTR_PATCH_SIZE,
|
||||
ATTR_PATCH_ADDRESS,
|
||||
ATTR_PATCH_DATA,
|
||||
ATTR_INPUT_TYPE,
|
||||
ATTR_INPUT_CENTER,
|
||||
ATTR_INPUT_MAPPING,
|
||||
};
|
||||
|
||||
static STRING_ID element_id[] =
|
||||
{
|
||||
{ "gamelist", ELEMENT_GAMELIST },
|
||||
{ "game", ELEMENT_GAME },
|
||||
{ "description", ELEMENT_DESCRIPTION },
|
||||
{ "year", ELEMENT_YEAR },
|
||||
{ "manufacturer", ELEMENT_MANUFACTURER },
|
||||
{ "step", ELEMENT_STEP },
|
||||
{ "cromsize", ELEMENT_CROMSIZE },
|
||||
{ "rom", ELEMENT_ROM },
|
||||
{ "patch", ELEMENT_PATCH },
|
||||
{ "bridge", ELEMENT_BRIDGE },
|
||||
{ "input", ELEMENT_INPUT },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID rom_attr_id[] =
|
||||
{
|
||||
{ "type", ATTR_ROM_TYPE },
|
||||
{ "name", ATTR_ROM_NAME },
|
||||
{ "size", ATTR_ROM_SIZE },
|
||||
{ "crc", ATTR_ROM_CRC },
|
||||
{ "sha1", ATTR_ROM_SHA1 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID game_attr_id[] =
|
||||
{
|
||||
{ "name", ATTR_GAME_NAME },
|
||||
{ "parent", ATTR_GAME_PARENT },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID patch_attr_id[] =
|
||||
{
|
||||
{ "size", ATTR_PATCH_SIZE },
|
||||
{ "address", ATTR_PATCH_ADDRESS },
|
||||
{ "data", ATTR_PATCH_DATA },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID input_attr_id[] =
|
||||
{
|
||||
{ "type", ATTR_INPUT_TYPE },
|
||||
{ "center", ATTR_INPUT_CENTER },
|
||||
{ "mapping", ATTR_INPUT_MAPPING },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID step_id[] =
|
||||
{
|
||||
{ "1.0", 0x10 },
|
||||
{ "1.5", 0x15 },
|
||||
{ "2.0", 0x20 },
|
||||
{ "2.1", 0x21 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID rom_id[] =
|
||||
{
|
||||
{ "prog0", ROMTYPE_PROG0 },
|
||||
{ "prog1", ROMTYPE_PROG1 },
|
||||
{ "prog2", ROMTYPE_PROG2 },
|
||||
{ "prog3", ROMTYPE_PROG3 },
|
||||
{ "crom00", ROMTYPE_CROM00 },
|
||||
{ "crom01", ROMTYPE_CROM01 },
|
||||
{ "crom02", ROMTYPE_CROM02 },
|
||||
{ "crom03", ROMTYPE_CROM03 },
|
||||
{ "crom10", ROMTYPE_CROM10 },
|
||||
{ "crom11", ROMTYPE_CROM11 },
|
||||
{ "crom12", ROMTYPE_CROM12 },
|
||||
{ "crom13", ROMTYPE_CROM13 },
|
||||
{ "crom20", ROMTYPE_CROM20 },
|
||||
{ "crom21", ROMTYPE_CROM21 },
|
||||
{ "crom22", ROMTYPE_CROM22 },
|
||||
{ "crom23", ROMTYPE_CROM23 },
|
||||
{ "crom30", ROMTYPE_CROM30 },
|
||||
{ "crom31", ROMTYPE_CROM31 },
|
||||
{ "crom32", ROMTYPE_CROM32 },
|
||||
{ "crom33", ROMTYPE_CROM33 },
|
||||
{ "vrom00", ROMTYPE_VROM00 },
|
||||
{ "vrom01", ROMTYPE_VROM01 },
|
||||
{ "vrom02", ROMTYPE_VROM02 },
|
||||
{ "vrom03", ROMTYPE_VROM03 },
|
||||
{ "vrom04", ROMTYPE_VROM04 },
|
||||
{ "vrom05", ROMTYPE_VROM05 },
|
||||
{ "vrom06", ROMTYPE_VROM06 },
|
||||
{ "vrom07", ROMTYPE_VROM07 },
|
||||
{ "vrom10", ROMTYPE_VROM10 },
|
||||
{ "vrom11", ROMTYPE_VROM11 },
|
||||
{ "vrom12", ROMTYPE_VROM12 },
|
||||
{ "vrom13", ROMTYPE_VROM13 },
|
||||
{ "vrom14", ROMTYPE_VROM14 },
|
||||
{ "vrom15", ROMTYPE_VROM15 },
|
||||
{ "vrom16", ROMTYPE_VROM16 },
|
||||
{ "vrom17", ROMTYPE_VROM17 },
|
||||
{ "sprog", ROMTYPE_SPROG },
|
||||
{ "srom0", ROMTYPE_SROM0 },
|
||||
{ "srom1", ROMTYPE_SROM1 },
|
||||
{ "srom2", ROMTYPE_SROM2 },
|
||||
{ "srom3", ROMTYPE_SROM3 },
|
||||
{ "dsbprog", ROMTYPE_DSBPROG },
|
||||
{ "dsbrom0", ROMTYPE_DSBROM0 },
|
||||
{ "dsbrom1", ROMTYPE_DSBROM1 },
|
||||
{ "dsbrom2", ROMTYPE_DSBROM2 },
|
||||
{ "dsbrom3", ROMTYPE_DSBROM3 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
#define INPUT_TYPE_BUTTON 0x10000
|
||||
#define INPUT_TYPE_ANALOG 0x20000
|
||||
|
||||
static STRING_ID input_id[] =
|
||||
{
|
||||
{ "button01", INPUT_TYPE_BUTTON | 0 },
|
||||
{ "button02", INPUT_TYPE_BUTTON | 1 },
|
||||
{ "button03", INPUT_TYPE_BUTTON | 2 },
|
||||
{ "button04", INPUT_TYPE_BUTTON | 3 },
|
||||
{ "button05", INPUT_TYPE_BUTTON | 4 },
|
||||
{ "button06", INPUT_TYPE_BUTTON | 5 },
|
||||
{ "button07", INPUT_TYPE_BUTTON | 6 },
|
||||
{ "button08", INPUT_TYPE_BUTTON | 7 },
|
||||
{ "button11", INPUT_TYPE_BUTTON | 8 },
|
||||
{ "button12", INPUT_TYPE_BUTTON | 9 },
|
||||
{ "button13", INPUT_TYPE_BUTTON | 10 },
|
||||
{ "button14", INPUT_TYPE_BUTTON | 11 },
|
||||
{ "button15", INPUT_TYPE_BUTTON | 12 },
|
||||
{ "button16", INPUT_TYPE_BUTTON | 13 },
|
||||
{ "button17", INPUT_TYPE_BUTTON | 14 },
|
||||
{ "button18", INPUT_TYPE_BUTTON | 15 },
|
||||
{ "analog1", INPUT_TYPE_ANALOG | 0 },
|
||||
{ "analog2", INPUT_TYPE_ANALOG | 1 },
|
||||
{ "analog3", INPUT_TYPE_ANALOG | 2 },
|
||||
{ "analog4", INPUT_TYPE_ANALOG | 3 },
|
||||
{ "analog5", INPUT_TYPE_ANALOG | 4 },
|
||||
{ "analog6", INPUT_TYPE_ANALOG | 5 },
|
||||
{ "analog7", INPUT_TYPE_ANALOG | 6 },
|
||||
{ "analog8", INPUT_TYPE_ANALOG | 7 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
static STRING_ID input_mapping_id[] =
|
||||
{
|
||||
{ "p1_button_1", P1_BUTTON_1 },
|
||||
{ "p1_button_2", P1_BUTTON_2 },
|
||||
{ "p1_button_3", P1_BUTTON_3 },
|
||||
{ "p1_button_4", P1_BUTTON_4 },
|
||||
{ "p1_button_5", P1_BUTTON_5 },
|
||||
{ "p1_button_6", P1_BUTTON_6 },
|
||||
{ "p1_button_7", P1_BUTTON_7 },
|
||||
{ "p1_button_8", P1_BUTTON_8 },
|
||||
{ "p2_button_1", P2_BUTTON_1 },
|
||||
{ "p2_button_2", P2_BUTTON_2 },
|
||||
{ "p2_button_3", P2_BUTTON_3 },
|
||||
{ "p2_button_4", P2_BUTTON_4 },
|
||||
{ "p2_button_5", P2_BUTTON_5 },
|
||||
{ "p2_button_6", P2_BUTTON_6 },
|
||||
{ "p2_button_7", P2_BUTTON_7 },
|
||||
{ "p2_button_8", P2_BUTTON_8 },
|
||||
{ "analog_axis_1", ANALOG_AXIS_1 },
|
||||
{ "analog_axis_2", ANALOG_AXIS_2 },
|
||||
{ "analog_axis_3", ANALOG_AXIS_3 },
|
||||
{ "analog_axis_4", ANALOG_AXIS_4 },
|
||||
{ "analog_axis_5", ANALOG_AXIS_5 },
|
||||
{ "analog_axis_6", ANALOG_AXIS_6 },
|
||||
{ "analog_axis_7", ANALOG_AXIS_7 },
|
||||
{ "analog_axis_8", ANALOG_AXIS_8 },
|
||||
{ "p1_joystick_up", P1_JOYSTICK_UP },
|
||||
{ "p1_joystick_down", P1_JOYSTICK_DOWN },
|
||||
{ "p1_joystick_left", P1_JOYSTICK_LEFT },
|
||||
{ "p1_joystick_right", P1_JOYSTICK_RIGHT },
|
||||
{ "p2_joystick_up", P2_JOYSTICK_UP },
|
||||
{ "p2_joystick_down", P2_JOYSTICK_DOWN },
|
||||
{ "p2_joystick_left", P2_JOYSTICK_LEFT },
|
||||
{ "p2_joystick_right", P2_JOYSTICK_RIGHT },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
static UINT8 *romlist;
|
||||
|
||||
static ROMSET *romset;
|
||||
|
||||
static int current_attr;
|
||||
static int current_element;
|
||||
|
||||
static int current_rom;
|
||||
static int current_romset;
|
||||
static int current_patch;
|
||||
static int current_input;
|
||||
|
||||
|
||||
|
||||
static void XMLCALL element_start(void *data, const char *el, const char **attr)
|
||||
{
|
||||
int element = get_string_id(el, element_id);
|
||||
|
||||
if (element < 0)
|
||||
{
|
||||
message(0, "Unknown element %s while parsing XML file\n", el);
|
||||
}
|
||||
else
|
||||
{
|
||||
current_element = element;
|
||||
|
||||
switch (element)
|
||||
{
|
||||
case ELEMENT_ROM:
|
||||
{
|
||||
int i=0;
|
||||
|
||||
// handle ROM types
|
||||
while (attr[i] != NULL)
|
||||
{
|
||||
int id = get_string_id(attr[i], rom_attr_id);
|
||||
|
||||
if (id >= 0)
|
||||
{
|
||||
current_attr = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not a type
|
||||
switch (current_attr)
|
||||
{
|
||||
case ATTR_ROM_TYPE:
|
||||
{
|
||||
int romtype = get_string_id(attr[i], rom_id);
|
||||
romset[current_romset].rom[current_rom].type = romtype;
|
||||
break;
|
||||
}
|
||||
case ATTR_ROM_NAME:
|
||||
{
|
||||
strcpy(romset[current_romset].rom[current_rom].name, attr[i]);
|
||||
break;
|
||||
}
|
||||
case ATTR_ROM_SIZE:
|
||||
{
|
||||
int romsize;
|
||||
sscanf(attr[i], "%d", &romsize);
|
||||
romset[current_romset].rom[current_rom].size = romsize;
|
||||
break;
|
||||
}
|
||||
case ATTR_ROM_CRC:
|
||||
{
|
||||
UINT32 romcrc;
|
||||
sscanf(attr[i], "%X", &romcrc);
|
||||
romset[current_romset].rom[current_rom].crc32 = romcrc;
|
||||
break;
|
||||
}
|
||||
case ATTR_ROM_SHA1:
|
||||
{
|
||||
// not handled
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case ELEMENT_GAME:
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (attr[i] != NULL)
|
||||
{
|
||||
int id = get_string_id(attr[i], game_attr_id);
|
||||
|
||||
if (id >= 0)
|
||||
{
|
||||
current_attr = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (current_attr)
|
||||
{
|
||||
case ATTR_GAME_NAME:
|
||||
{
|
||||
strcpy(romset[current_romset].game, attr[i]);
|
||||
break;
|
||||
}
|
||||
case ATTR_GAME_PARENT:
|
||||
{
|
||||
strcpy(romset[current_romset].parent, attr[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case ELEMENT_PATCH:
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (attr[i] != NULL)
|
||||
{
|
||||
int id = get_string_id(attr[i], patch_attr_id);
|
||||
|
||||
if (id >= 0)
|
||||
{
|
||||
current_attr = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (current_attr)
|
||||
{
|
||||
case ATTR_PATCH_SIZE:
|
||||
{
|
||||
int patch_size;
|
||||
sscanf(attr[i], "%d", &patch_size);
|
||||
romset[current_romset].patch[current_patch].size = patch_size;
|
||||
break;
|
||||
}
|
||||
case ATTR_PATCH_ADDRESS:
|
||||
{
|
||||
UINT32 address;
|
||||
sscanf(attr[i], "%X", &address);
|
||||
romset[current_romset].patch[current_patch].address = address;
|
||||
break;
|
||||
}
|
||||
case ATTR_PATCH_DATA:
|
||||
{
|
||||
UINT32 data;
|
||||
sscanf(attr[i], "%X", &data);
|
||||
romset[current_romset].patch[current_patch].data = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case ELEMENT_INPUT:
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (attr[i] != NULL)
|
||||
{
|
||||
int id = get_string_id(attr[i], input_attr_id);
|
||||
|
||||
if (id >= 0)
|
||||
{
|
||||
current_attr = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (current_attr)
|
||||
{
|
||||
case ATTR_INPUT_TYPE:
|
||||
{
|
||||
current_input = get_string_id(attr[i], input_id);
|
||||
|
||||
if (current_input & INPUT_TYPE_BUTTON)
|
||||
{
|
||||
int button = current_input & 0xffff;
|
||||
int set = (button / 8) & 1;
|
||||
int bit = 1 << (button % 8);
|
||||
romset[current_romset].controls.button[button].enabled = 1;
|
||||
romset[current_romset].controls.button[button].control_set = set;
|
||||
romset[current_romset].controls.button[button].control_bit = bit;
|
||||
}
|
||||
else if (current_input & INPUT_TYPE_ANALOG)
|
||||
{
|
||||
int axis = current_input & 0xffff;
|
||||
romset[current_romset].controls.analog_axis[axis].enabled = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_INPUT_CENTER:
|
||||
{
|
||||
if (current_input & INPUT_TYPE_ANALOG)
|
||||
{
|
||||
int axis = current_input & 0xffff;
|
||||
int center;
|
||||
sscanf(attr[i], "%d", ¢er);
|
||||
romset[current_romset].controls.analog_axis[axis].center = center;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_INPUT_MAPPING:
|
||||
{
|
||||
int mapping = get_string_id(attr[i], input_mapping_id);
|
||||
if (current_input & INPUT_TYPE_BUTTON)
|
||||
{
|
||||
int button = current_input & 0xffff;
|
||||
romset[current_romset].controls.button[button].mapping = mapping;
|
||||
}
|
||||
else if (current_input & INPUT_TYPE_ANALOG)
|
||||
{
|
||||
int axis = current_input & 0xffff;
|
||||
romset[current_romset].controls.analog_axis[axis].mapping = mapping;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL element_end(void *data, const char *el)
|
||||
{
|
||||
int element = get_string_id(el, element_id);
|
||||
|
||||
if (element < 0)
|
||||
{
|
||||
message(0, "Unknown element %s while parsing XML\n", el);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (element)
|
||||
{
|
||||
case ELEMENT_ROM:
|
||||
{
|
||||
current_rom++;
|
||||
current_element = ELEMENT_GAMELIST;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_GAME:
|
||||
{
|
||||
romset[current_romset].num_patches = current_patch;
|
||||
current_romset++;
|
||||
current_rom = 0;
|
||||
current_patch = 0;
|
||||
current_element = ELEMENT_GAMELIST;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_DESCRIPTION:
|
||||
case ELEMENT_YEAR:
|
||||
case ELEMENT_MANUFACTURER:
|
||||
case ELEMENT_STEP:
|
||||
case ELEMENT_BRIDGE:
|
||||
case ELEMENT_CROMSIZE:
|
||||
{
|
||||
current_element = ELEMENT_GAMELIST;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_PATCH:
|
||||
{
|
||||
current_patch++;
|
||||
current_element = ELEMENT_GAMELIST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL character_data(void *data, const char *s, int len)
|
||||
{
|
||||
char temp[2000];
|
||||
memcpy(temp, s, len);
|
||||
temp[len] = 0;
|
||||
|
||||
switch (current_element)
|
||||
{
|
||||
case ELEMENT_DESCRIPTION:
|
||||
{
|
||||
strcpy(romset[current_romset].title, temp);
|
||||
break;
|
||||
}
|
||||
case ELEMENT_YEAR:
|
||||
{
|
||||
int year;
|
||||
sscanf(temp, "%d", &year);
|
||||
romset[current_romset].year = year;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_MANUFACTURER:
|
||||
{
|
||||
strcpy(romset[current_romset].manufacturer, temp);
|
||||
break;
|
||||
}
|
||||
case ELEMENT_STEP:
|
||||
{
|
||||
int step = get_string_id(temp, step_id);
|
||||
|
||||
if (step >= 0)
|
||||
{
|
||||
romset[current_romset].step = step;
|
||||
}
|
||||
else
|
||||
{
|
||||
message(0, "Invalid step %s while parsing XML file\n", temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ELEMENT_BRIDGE:
|
||||
{
|
||||
if (_stricmp(temp, "mpc106") == 0)
|
||||
{
|
||||
romset[current_romset].bridge = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
message(0, "Unknown bridge %s while parsing XML file\n", temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ELEMENT_CROMSIZE:
|
||||
{
|
||||
if (_stricmp(temp, "64M") == 0)
|
||||
{
|
||||
romset[current_romset].cromsize = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
message(0, "Unknown cromsize %s while parsing XML file\n", temp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parse_romlist(char *romlist_name, ROMSET *_romset)
|
||||
{
|
||||
XML_Parser parser;
|
||||
|
||||
int length;
|
||||
FILE *file;
|
||||
|
||||
file = open_file(FILE_READ|FILE_BINARY, "%s", romlist_name);
|
||||
if (file == NULL)
|
||||
{
|
||||
message(0, "Couldn't open %s", romlist_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = (int)get_open_file_size(file);
|
||||
|
||||
romlist = (UINT8*)malloc(length);
|
||||
|
||||
if (!read_from_file(file, romlist, length))
|
||||
{
|
||||
message(0, "I/O error while reading %s", romlist_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close_file(file);
|
||||
|
||||
romset = _romset;
|
||||
|
||||
// parse the XML file
|
||||
parser = XML_ParserCreate(NULL);
|
||||
|
||||
XML_SetElementHandler(parser, element_start, element_end);
|
||||
XML_SetCharacterDataHandler(parser, character_data);
|
||||
|
||||
if (XML_Parse(parser, romlist, length, 1) != XML_STATUS_OK)
|
||||
{
|
||||
message(0, "Error while parsing the XML file %s", romlist_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return current_romset;
|
||||
}
|
179
core/rtc.c
179
core/rtc.c
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* rtc.c
|
||||
*
|
||||
* Real-Time Clock (72421) emulation.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
#include <time.h>
|
||||
|
||||
static UINT8 rtc_step = 0;
|
||||
static UINT8 rtc_reg[0x10]; /* 4-bit wide */
|
||||
|
||||
/******************************************************************/
|
||||
/* Interface */
|
||||
/******************************************************************/
|
||||
|
||||
void rtc_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void rtc_shutdown(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void rtc_reset(void)
|
||||
{
|
||||
rtc_step = 0;
|
||||
|
||||
memset(rtc_reg, 0, 0x10);
|
||||
}
|
||||
|
||||
void rtc_step_frame(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* void rtc_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the real-time clock to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void rtc_save_state(FILE *fp)
|
||||
{
|
||||
// do nothing yet because this file isn't complete or used, it appears
|
||||
}
|
||||
|
||||
/*
|
||||
* void rtc_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the real-time clock from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void rtc_load_state(FILE *fp)
|
||||
{
|
||||
// do nothing yet because this file isn't complete or used, it appears
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Access */
|
||||
/******************************************************************/
|
||||
|
||||
static UINT8 get_register(int reg)
|
||||
{
|
||||
time_t current_time;
|
||||
struct tm* tms;
|
||||
|
||||
time( ¤t_time );
|
||||
tms = localtime( ¤t_time );
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case 0: // 1-second digit
|
||||
return (tms->tm_sec % 10) & 0xF;
|
||||
break;
|
||||
case 1: // 10-seconds digit
|
||||
return (tms->tm_sec / 10) & 0x7;
|
||||
break;
|
||||
case 2: // 1-minute digit
|
||||
return (tms->tm_min % 10) & 0xF;
|
||||
break;
|
||||
case 3: // 10-minute digit
|
||||
return (tms->tm_min / 10) & 0x7;
|
||||
break;
|
||||
case 4: // 1-hour digit
|
||||
return (tms->tm_hour % 10) & 0xF;
|
||||
break;
|
||||
case 5: // 10-hours digit
|
||||
return (tms->tm_hour / 10) & 0x7;
|
||||
break;
|
||||
case 6: // 1-day digit (days in month)
|
||||
return (tms->tm_mday % 10) & 0xF;
|
||||
break;
|
||||
case 7: // 10-days digit
|
||||
return (tms->tm_mday / 10) & 0x3;
|
||||
break;
|
||||
case 8: // 1-month digit
|
||||
return ((tms->tm_mon + 1) % 10) & 0xF;
|
||||
break;
|
||||
case 9: // 10-months digit
|
||||
return ((tms->tm_mon + 1) / 10) & 0x1;
|
||||
break;
|
||||
case 10: // 1-year digit
|
||||
return (tms->tm_year % 10) & 0xF;
|
||||
break;
|
||||
case 11: // 10-years digit
|
||||
return ((tms->tm_year % 100) / 10) & 0xF;
|
||||
break;
|
||||
case 12: // day of the week
|
||||
return tms->tm_wday & 0x7;
|
||||
break;
|
||||
case 13:
|
||||
return 0;
|
||||
break;
|
||||
case 14:
|
||||
return 0;
|
||||
break;
|
||||
case 15:
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
error("ERROR: invalid RTC access reg%X\n", reg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 rtc_read_8(UINT32 a)
|
||||
{
|
||||
int address = (a >> 2) & 0xF;
|
||||
|
||||
//message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC));
|
||||
|
||||
return get_register( address );
|
||||
}
|
||||
|
||||
UINT32 rtc_read_32(UINT32 a)
|
||||
{
|
||||
int address = (a >> 2) & 0xF;
|
||||
|
||||
//message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC));
|
||||
|
||||
return get_register( address) << 24 | 0x30000; // Bits 0x30000 set to get battery voltage check to pass
|
||||
}
|
||||
|
||||
void rtc_write(UINT32 a, UINT8 d)
|
||||
{
|
||||
a = (a >> 2) & 0xF;
|
||||
//message(0, "RTC: write %08X = %X", a, d);
|
||||
|
||||
a &= 0xF;
|
||||
|
||||
rtc_reg[a] = d;
|
||||
}
|
41
core/rtc.h
41
core/rtc.h
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* rtc.h
|
||||
*
|
||||
* Real-Time Clock (72421) header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_RTC_H
|
||||
#define INCLUDED_RTC_H
|
||||
|
||||
extern void rtc_init(void);
|
||||
extern void rtc_shutdown(void);
|
||||
extern void rtc_reset(void);
|
||||
extern void rtc_step_frame(void);
|
||||
|
||||
extern void rtc_save_state(FILE *);
|
||||
extern void rtc_load_state(FILE *);
|
||||
|
||||
extern UINT8 rtc_read_8(UINT32 a);
|
||||
extern UINT32 rtc_read_32(UINT32 a);
|
||||
extern void rtc_write(UINT32 a, UINT8 d);
|
||||
|
||||
#endif // INCLUDED_RTC_H
|
||||
|
367
core/scsi.c
367
core/scsi.c
|
@ -1,367 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* scsi.c
|
||||
*
|
||||
* NCR 53C810 SCSI controller emulation.
|
||||
*
|
||||
* Multi-byte data written is assumed to be little endian and is therefore
|
||||
* reversed because the PowerPC operates in big endian mode in the Model 3.
|
||||
*
|
||||
* NOTE: scsi_run() is often called with an argument of 100. This is
|
||||
* actually incorrect. It should run until an interrupt condition. A count of
|
||||
* 100 is used as a runaway counter to prevent lock-ups.
|
||||
*/
|
||||
|
||||
#include "model3.h"
|
||||
|
||||
/*
|
||||
* Read/Write Handlers
|
||||
*
|
||||
* These are used as an interface to the rest of the system.
|
||||
*/
|
||||
|
||||
static UINT8 (*read_8)(UINT32);
|
||||
static UINT16 (*read_16)(UINT32);
|
||||
static UINT32 (*read_32)(UINT32);
|
||||
static void (*write_8)(UINT32, UINT8);
|
||||
static void (*write_16)(UINT32, UINT16);
|
||||
static void (*write_32)(UINT32, UINT32);
|
||||
|
||||
/*
|
||||
* 53C810 Context
|
||||
*
|
||||
* Offsets within the register array correspond to register addresses but the
|
||||
* endianness in which they are stored is little endian. Macros are provided
|
||||
* to access them.
|
||||
*/
|
||||
|
||||
#define REG8(r) scsi_regs[r]
|
||||
#define REG16(r) *((UINT16 *) &scsi_regs[r])
|
||||
#define REG32(r) *((UINT32 *) &scsi_regs[r])
|
||||
|
||||
static UINT8 scsi_regs[0x60];
|
||||
static BOOL scripts_exec; // true if SCRIPTS code should be executed
|
||||
|
||||
/*
|
||||
* SCRIPTS Emulation
|
||||
*/
|
||||
|
||||
#include "scsiop.h"
|
||||
|
||||
/*
|
||||
* UINT8 scsi_read_8(UINT32 addr);
|
||||
*
|
||||
* Reads from the SCSI register space.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Register address (only lower 8 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Returns data from the register read.
|
||||
*/
|
||||
|
||||
UINT8 scsi_read_8(UINT32 addr)
|
||||
{
|
||||
UINT8 reg;
|
||||
|
||||
addr &= 0xFF;
|
||||
//if (addr > 0x5F)
|
||||
// error("%08X: SCSI invalid read from %02X", ppc_get_reg(PPC_REG_PC), addr);
|
||||
|
||||
reg = REG8(addr);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x14:
|
||||
REG8(addr) &= 0xFE; // clear DIP
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*
|
||||
* UINT32 scsi_read_32(UINT32 addr);
|
||||
*
|
||||
* Reads from the SCSI register space.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Register address (only lower 8 bits matter.)
|
||||
*
|
||||
* Returns:
|
||||
* Returns data from the register read.
|
||||
*/
|
||||
|
||||
UINT32 scsi_read_32(UINT32 addr)
|
||||
{
|
||||
UINT32 reg;
|
||||
|
||||
// error("SCSI 32-bit read from %08X", addr);
|
||||
|
||||
addr &= 0xFF;
|
||||
if (addr > 0x5F)
|
||||
error("%08X: SCSI invalid read from %02X", ppc_get_pc(), addr);
|
||||
|
||||
reg = REG32(addr);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x14:
|
||||
error("%08X: SCSI 32-bit read from reg %02X -- don't know what to do", ppc_get_pc(), addr);
|
||||
break;
|
||||
default:
|
||||
// NOTE: some registers might have to be handled to clear certain
|
||||
// bits
|
||||
break;
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void scsi_write_8(UINT32 addr, UINT8 data);
|
||||
*
|
||||
* Writes a byte to the SCSI register space.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Register address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void scsi_write_8(UINT32 addr, UINT8 data)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
if (addr > 0x5F)
|
||||
error("%08X: SCSI invalid write8 to %02X", ppc_get_pc(), addr);
|
||||
|
||||
//message(0, "%08X: SCSI %02X = %02X", ppc_get_pc(), addr, data);
|
||||
|
||||
REG8(addr) = data;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3B: // DCNTL: DMA Control
|
||||
|
||||
/*
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* +------+------+------+------+------+------+------+------+
|
||||
* | CLSE | PFF | PFEN | SSM | IRQM | STD | IRQD | COM |
|
||||
* +------+------+------+------+------+------+------+------+
|
||||
*
|
||||
* CLSE Cache Line Size Enable
|
||||
*
|
||||
* PFF Prefetch Flush
|
||||
*
|
||||
* PFEN Prefetch Enable
|
||||
*
|
||||
* SSM Single Step Mode
|
||||
*
|
||||
* Setting this bit causes the SCSI to stop after executing
|
||||
* each SCRIPTS instruction and generate a single step
|
||||
* interrupt. To restart the SCSI after the interrupt has
|
||||
* been generated, read ISTAT and DSTAT to recognize and
|
||||
* clear the interrupt, then set STD bit in this register
|
||||
* to resume execution.
|
||||
*
|
||||
* IRQM IRQ Mode
|
||||
*
|
||||
* STD Start DMA Operation
|
||||
*
|
||||
* The SCSI fetches an instruction and executes it when this
|
||||
* bit is set. It is required when the SCSI is in one of the
|
||||
* following modes:
|
||||
*
|
||||
* - Manual start mode: Bit 0 in the DMODE register is
|
||||
* set.
|
||||
* - Single step mode: Bit 4 in the DCNTL register is
|
||||
* set.
|
||||
*
|
||||
* When in manual mode, setting this bit starts instruction
|
||||
* execution -- it remains set until an interrupt occurs. In
|
||||
* single step mode, it restarts execution after an
|
||||
* interrupt.
|
||||
*
|
||||
* IRQD IRQ Disable
|
||||
*
|
||||
* COM LSI53C700 Family Compatibility
|
||||
*/
|
||||
|
||||
/*
|
||||
* Single-stepping is checked for in scsi_run() (the number of
|
||||
* instructions to execute will be reduced to 1 there.)
|
||||
*/
|
||||
|
||||
if ((REG8(0x38) & 0x01) || // MAN=1, start SCRIPTS on STD=1
|
||||
(REG8(0x3B) & 0x10)) // single step, resume execution
|
||||
{
|
||||
scripts_exec = data & 0x04;
|
||||
scsi_run(500);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_write_16(UINT32 addr, UINT16 data);
|
||||
*
|
||||
* Writes a word to the SCSI register space.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Register address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void scsi_write_16(UINT32 addr, UINT16 data)
|
||||
{
|
||||
data = BSWAP16(data);
|
||||
//message(0, "%08X: SCSI %02X = %04X", ppc_get_pc(), addr, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_write_32(UINT32 addr, UINT32 data);
|
||||
*
|
||||
* Writes a byte to the SCSI register space.
|
||||
*
|
||||
* Parameters:
|
||||
* addr = Register address (only lower 8 bits matter.)
|
||||
* data = Data to write.
|
||||
*/
|
||||
|
||||
void scsi_write_32(UINT32 addr, UINT32 data)
|
||||
{
|
||||
if ((addr & 0xff) > 0x5C)
|
||||
error("%08X: SCSI invalid write32 to %08X", ppc_get_pc(), addr);
|
||||
addr &= 0xff;
|
||||
|
||||
data = BSWAP32(data);
|
||||
REG32(addr) = data;
|
||||
|
||||
// message(0, "%08X: SCSI %02X = %08X", ppc_get_reg(PPC_REG_PC), addr, data);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x2C: // DSP: DMA SCRIPTS Pointer
|
||||
if ((REG8(0x38) & 0x01) == 0) // MAN=0, start SCRIPTS automatically
|
||||
scripts_exec = 1;
|
||||
scsi_run(500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_save_state(FILE *fp);
|
||||
*
|
||||
* Saves the state of the SCSI controller to a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to save to.
|
||||
*/
|
||||
|
||||
void scsi_save_state(FILE *fp)
|
||||
{
|
||||
fwrite(scsi_regs, sizeof(UINT8), 0x60, fp);
|
||||
fwrite(&scripts_exec, sizeof(BOOL), 1, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_load_state(FILE *fp);
|
||||
*
|
||||
* Loads the state of the SCSI controller from a file.
|
||||
*
|
||||
* Parameters:
|
||||
* fp = File to load from.
|
||||
*/
|
||||
|
||||
void scsi_load_state(FILE *fp)
|
||||
{
|
||||
fread(scsi_regs, sizeof(UINT8), 0x60, fp);
|
||||
fread(&scripts_exec, sizeof(BOOL), 1, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_reset(void);
|
||||
*
|
||||
* Initializes the SCSI controller to its power-on state. All bits which are
|
||||
* marked as undefined by the manual are simply set to 0 here.
|
||||
*/
|
||||
|
||||
void scsi_reset(void)
|
||||
{
|
||||
memset(scsi_regs, 0, sizeof(scsi_regs));
|
||||
scripts_exec = 0;
|
||||
|
||||
REG8(0x00) = 0xc0;
|
||||
REG8(0x0C) = 0x80;
|
||||
REG8(0x0F) = 0x02;
|
||||
REG8(0x18) = 0xff;
|
||||
REG8(0x19) = 0xf0;
|
||||
REG8(0x1A) = 0x01;
|
||||
REG8(0x46) = 0x60;
|
||||
REG8(0x47) = 0x0f;
|
||||
REG8(0x4C) = 0x03;
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32),
|
||||
* UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8),
|
||||
* void (*write16)(UINT32, UINT16),
|
||||
* void (*write32)(UINT32, UINT32));
|
||||
*
|
||||
* Initializes the SCSI controller emulation by building the SCRIPTS opcode
|
||||
* table and setting the memory access handlers.
|
||||
*
|
||||
* Parameters:
|
||||
* read8 = Handler to use for 8-bit reads.
|
||||
* read16 = Handler to use for 16-bit reads.
|
||||
* read32 = Handler to use for 32-bit reads.
|
||||
* write8 = Handler to use for 8-bit writes.
|
||||
* write16 = Handler to use for 16-bit writes.
|
||||
* write32 = Handler to use for 32-bit writes.
|
||||
*/
|
||||
|
||||
void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32),
|
||||
UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8),
|
||||
void (*write16)(UINT32, UINT16),
|
||||
void (*write32)(UINT32, UINT32))
|
||||
{
|
||||
read_8 = read8;
|
||||
read_16 = read16;
|
||||
read_32 = read32;
|
||||
write_8 = write8;
|
||||
write_16 = write16;
|
||||
write_32 = write32;
|
||||
|
||||
build_opcode_table();
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_shutdown(void);
|
||||
*
|
||||
* Shuts down the SCSI emulation (actually does nothing.)
|
||||
*/
|
||||
|
||||
void scsi_shutdown(void)
|
||||
{
|
||||
}
|
51
core/scsi.h
51
core/scsi.h
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* scsi.h
|
||||
*
|
||||
* NCR 53C810 SCSI controller header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SCSI_H
|
||||
#define INCLUDED_SCSI_H
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
extern UINT8 scsi_read_8(UINT32);
|
||||
extern UINT32 scsi_read_32(UINT32);
|
||||
|
||||
extern void scsi_write_8(UINT32, UINT8);
|
||||
extern void scsi_write_16(UINT32, UINT16);
|
||||
extern void scsi_write_32(UINT32, UINT32);
|
||||
|
||||
extern void scsi_save_state(FILE *);
|
||||
extern void scsi_load_state(FILE *);
|
||||
|
||||
extern void scsi_run(INT);
|
||||
extern void scsi_reset(void);
|
||||
|
||||
extern void scsi_init(UINT8 (*)(UINT32), UINT16 (*)(UINT32),
|
||||
UINT32 (*)(UINT32), void (*)(UINT32, UINT8),
|
||||
void (*)(UINT32, UINT16),
|
||||
void (*)(UINT32, UINT32));
|
||||
extern void scsi_shutdown(void);
|
||||
|
||||
#endif // INCLUDED_SCSI_H
|
221
core/scsiop.h
221
core/scsiop.h
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* scsiop.h
|
||||
*
|
||||
* NCR 53C810 SCSI controller SCRIPTS emulation. This file is intended to be
|
||||
* included by scsi.c only.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SCSIOP_H
|
||||
#define INCLUDED_SCSIOP_H
|
||||
|
||||
/*
|
||||
* Macros
|
||||
*/
|
||||
|
||||
#define INSTRUCTION(name) static BOOL name()
|
||||
|
||||
#define FETCH(dest) do { dest = read_32(REG32(0x2c)); REG32(0x2c) += 4; dest = BSWAP32(dest); } while (0);
|
||||
|
||||
#define DBC (REG32(0x24) & 0xffffff)
|
||||
#define DSPS (REG32(0x30))
|
||||
#define TEMP (REG32(0x1c))
|
||||
|
||||
|
||||
/*
|
||||
* Opcode Table
|
||||
*
|
||||
* Use the upper 8 bits of a SCRIPTS instruction as an index into this table.
|
||||
*/
|
||||
|
||||
static BOOL (*op_table[256])();
|
||||
|
||||
|
||||
/*
|
||||
* Move Memory
|
||||
*/
|
||||
|
||||
#ifdef _PROFILE_
|
||||
extern UINT is_dma;
|
||||
#endif
|
||||
|
||||
INSTRUCTION(move_memory)
|
||||
{
|
||||
UINT32 source = DSPS, dest;
|
||||
INT num_bytes = DBC;
|
||||
|
||||
PROFILE_SECT_ENTRY("scsi");
|
||||
|
||||
#ifdef _PROFILE_
|
||||
is_dma = 1;
|
||||
#endif
|
||||
|
||||
FETCH(TEMP);
|
||||
dest = TEMP;
|
||||
|
||||
// message(0, "%08X (%08X): SCSI move memory: %08X->%08X, %X", ppc_get_reg(PPC_REG_PC), ppc_get_reg(PPC_REG_LR), source, dest, num_bytes);
|
||||
|
||||
/*
|
||||
* Perform a 32-bit copy if possible and if necessary, finish off with a
|
||||
* byte-for-byte copy
|
||||
*/
|
||||
|
||||
/*for (i = 0; i < num_bytes / 4; i++)
|
||||
{
|
||||
write_32(dest, read_32(source));
|
||||
dest += 4;
|
||||
source += 4;
|
||||
}*/
|
||||
|
||||
model3_dma_transfer(source, dest, num_bytes, FALSE);
|
||||
|
||||
if (num_bytes & 3)
|
||||
{
|
||||
error("unaligned SCSI op !!!\n");
|
||||
num_bytes &= 3;
|
||||
while (num_bytes--)
|
||||
write_8(dest++, read_8(source++));
|
||||
}
|
||||
|
||||
source += num_bytes;
|
||||
dest += num_bytes;
|
||||
|
||||
#ifdef _PROFILE_
|
||||
is_dma = 0;
|
||||
#endif
|
||||
|
||||
REG32(0x24) &= 0xff000000; // update DBC (is any of this necessary???)
|
||||
DSPS = source;
|
||||
TEMP = dest;
|
||||
|
||||
PROFILE_SECT_EXIT("scsi");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* INT and INTFLY
|
||||
*/
|
||||
|
||||
INSTRUCTION(int_and_intfly)
|
||||
{
|
||||
if ((DBC & 0x100000)) // INTFLY -- not yet emulated!
|
||||
return 1;
|
||||
|
||||
if (((REG32(0x24) >> 21) & 1) || ((REG32(0x24) >> 18) & 1) || ((REG32(0x24) >> 17) & 1))
|
||||
return 1; // conditional tests not yet emulated
|
||||
|
||||
REG8(0x14) |= 0x01; // DIP=1
|
||||
scripts_exec = 0; // halt execution
|
||||
|
||||
/*
|
||||
* NOTE: I haven't seen any games rely on this, so if you observe SCSI
|
||||
* problems, remove this to see if it helps.
|
||||
*/
|
||||
|
||||
REG8(0x14) |= 0x01; // DIP=1
|
||||
REG8(0x0c) |= 0x04; // SIR=1
|
||||
//model3_add_irq(0x60);
|
||||
ppc_set_irq_line(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalid Instruction
|
||||
*/
|
||||
|
||||
INSTRUCTION(invalid)
|
||||
{
|
||||
// message(0, "INVALID SCSI INSTRUCTION @ %08X", REG32(0x2c));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* void scsi_run(INT num);
|
||||
*
|
||||
* Runs SCSI SCRIPTS instructions until the code halts or the requested number
|
||||
* of instructions is executed.
|
||||
*
|
||||
* Parameters:
|
||||
* num = Number of instructions to execute.
|
||||
*/
|
||||
|
||||
void scsi_run(INT num)
|
||||
{
|
||||
LOG("model3.log", "SCSI exec %08X\n", REG32(0x2c));
|
||||
if (!scripts_exec)
|
||||
return;
|
||||
|
||||
if ((REG8(0x3B) & 0x10)) // single step mode
|
||||
num = 1;
|
||||
|
||||
while (num-- && scripts_exec)
|
||||
{
|
||||
UINT32 save_addr = REG32(0x2c); // for debugging
|
||||
|
||||
FETCH(REG32(0x24)); // first double word into DCMD and DBC
|
||||
FETCH(DSPS); // second double word into DSPS
|
||||
|
||||
if ((*op_table[REG32(0x24) >> 24])())
|
||||
error("SCSI: invalid instruction @ %08X", save_addr);
|
||||
}
|
||||
|
||||
scripts_exec = 0;
|
||||
|
||||
if ((REG8(0x3B) & 0x10)) // single step mode, trigger interrupt
|
||||
{
|
||||
REG8(0x0c) |= 0x08; // SSI=1
|
||||
REG8(0x14) |= 0x01; // DIP=1
|
||||
ppc_set_irq_line(1); // what about Model 3 IRQ status?
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* insert():
|
||||
*
|
||||
* Inserts an instruction into the appropriate elements of the opcode table
|
||||
* under the control of a mask.
|
||||
*/
|
||||
|
||||
static void insert(UINT8 match, UINT8 mask, BOOL (*handler)())
|
||||
{
|
||||
UINT32 i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if ((i & mask) == match)
|
||||
op_table[i] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build_opcode_table():
|
||||
*
|
||||
* Installs instruction handlers.
|
||||
*/
|
||||
|
||||
static void build_opcode_table(void)
|
||||
{
|
||||
insert(0, 0, &invalid);
|
||||
insert(0xc0, 0xfe, &move_memory);
|
||||
insert(0x98, 0xf8, &int_and_intfly);
|
||||
}
|
||||
|
||||
#endif // INCLUDED_SCSIOP_H
|
2494
core/scsp.c
2494
core/scsp.c
File diff suppressed because it is too large
Load diff
29
core/scsp.h
29
core/scsp.h
|
@ -1,29 +0,0 @@
|
|||
|
||||
#ifndef _SCSP_H_
|
||||
#define _SCSP_H_
|
||||
|
||||
extern void scsp_shutdown(void);
|
||||
extern void scsp_init(UINT8 *scsp_ram, void *sint_hand, void *mint_hand);
|
||||
extern void scsp_reset(void);
|
||||
|
||||
extern void scsp_update(INT32 *bufL, INT32 *bufR, UINT32 len);
|
||||
extern void scsp_update_timer(UINT32 len);
|
||||
|
||||
extern UINT32 scsp_read_8(UINT32 a);
|
||||
extern UINT32 scsp_read_16(UINT32 a);
|
||||
extern UINT32 scsp_read_32(UINT32 a);
|
||||
|
||||
extern void scsp_write_8(UINT32 a, UINT32 d);
|
||||
extern void scsp_write_16(UINT32 a, UINT32 d);
|
||||
extern void scsp_write_32(UINT32 a, UINT32 d);
|
||||
|
||||
extern void scsp_midi_in_send(UINT8 data);
|
||||
extern void scsp_midi_out_send(UINT8 data);
|
||||
extern UINT8 scsp_midi_in_read(void);
|
||||
extern UINT8 scsp_midi_out_read(void);
|
||||
|
||||
extern char * scsp_debug_slist_on(void);
|
||||
extern char * scsp_debug_ilist(INT s_m, char * out);
|
||||
|
||||
#endif /* _SCSP_H_ */
|
||||
|
1072
core/tilegen.c
1072
core/tilegen.c
File diff suppressed because it is too large
Load diff
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Sega Model 3 Emulator
|
||||
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License Version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program (license.txt); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* tilegen.h
|
||||
*
|
||||
* Tilemap generator header.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_TILEGEN_H
|
||||
#define INCLUDED_TILEGEN_H
|
||||
|
||||
extern void tilegen_update(void);
|
||||
|
||||
extern UINT16 tilegen_vram_read_16(UINT32 addr);
|
||||
extern UINT32 tilegen_vram_read_32(UINT32);
|
||||
extern void tilegen_vram_write_32(UINT32, UINT32);
|
||||
|
||||
extern UINT16 tilegen_read_16(UINT32);
|
||||
extern UINT32 tilegen_read_32(UINT32);
|
||||
extern void tilegen_write_32(UINT32, UINT32);
|
||||
|
||||
extern BOOL tilegen_is_layer_enabled(int);
|
||||
extern UINT32 tilegen_get_layer_color_offset(int layer);
|
||||
extern UINT32* tilegen_get_priority_buffer(void);
|
||||
|
||||
extern void tilegen_save_state(FILE *);
|
||||
extern void tilegen_load_state(FILE *);
|
||||
|
||||
extern void tilegen_reset(void);
|
||||
extern void tilegen_init(UINT8 *);
|
||||
extern void tilegen_shutdown(void);
|
||||
|
||||
#endif // INCLUDED_TILEGEN_H
|
||||
|
Loading…
Reference in a new issue