Original Supermodel code moved to tags/Original.

This commit is contained in:
Bart Trzynadlowski 2011-04-24 00:55:39 +00:00
parent 74d1cec9b8
commit 187c62d3b1
26 changed files with 0 additions and 11675 deletions

View file

@ -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 *) &regs[addr])
#define WORD(addr) *((UINT16 *) &regs[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(&reg_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(&reg_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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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", &center);
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;
}

View file

@ -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( &current_time );
tms = localtime( &current_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;
}

View file

@ -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

View file

@ -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)
{
}

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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_ */

File diff suppressed because it is too large Load diff

View file

@ -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