Encryption device emulation (thanks to MAME), fixed warnings in Model3.cpp, added a string formatter helper, and updated Win32 GCC Makefile.

This commit is contained in:
Bart Trzynadlowski 2016-04-02 21:50:40 +00:00
parent c0f679479a
commit 6e5c301de8
7 changed files with 4254 additions and 3116 deletions

View file

@ -57,7 +57,8 @@ BOOST_INCLUDEPATH = /mingw64/boost_1_55_0
# #
ifeq ($(strip $(BITS)),64) ifeq ($(strip $(BITS)),64)
SDL_LIBPATH = /mingw64/lib64 SDL_LIBPATH = /mingw64/lib64
SDL_INCLUDEPATH = /mingw64/x86_64-w64-mingw32/include/SDL #SDL_INCLUDEPATH = /mingw64/x86_64-w64-mingw32/include/SDL
SDL_INCLUDEPATH = /mingw64/SDL-1.2.15/include
else else
SDL_LIBPATH = /mingw/lib SDL_LIBPATH = /mingw/lib
SDL_INCLUDEPATH = /mingw/include/SDL SDL_INCLUDEPATH = /mingw/include/SDL
@ -68,6 +69,7 @@ endif
# #
ifeq ($(strip $(BITS)),64) ifeq ($(strip $(BITS)),64)
WINSDK_LIBPATH = /Program\ Files/Microsoft\ SDKs/Windows/v7.0/Lib/x64 WINSDK_LIBPATH = /Program\ Files/Microsoft\ SDKs/Windows/v7.0/Lib/x64
#WINSDK_LIBPATH = /Program\ Files\ (x86)/Windows\ Kits/10/Lib/10.0.10586.0/um/x64
else else
WINSDK_LIBPATH = /Program\ Files/Microsoft\ SDKs/Windows/v7.0/Lib WINSDK_LIBPATH = /Program\ Files/Microsoft\ SDKs/Windows/v7.0/Lib
endif endif
@ -98,7 +100,7 @@ LD = g++
COMPILER_FLAGS = -I$(SDL_INCLUDEPATH) -ISrc/ -ISrc/OSD/ -ISrc/OSD/SDL/ -ISrc/OSD/Windows/ -c -Wall -DSUPERMODEL_WIN32 -DGLEW_STATIC -O3 COMPILER_FLAGS = -I$(SDL_INCLUDEPATH) -ISrc/ -ISrc/OSD/ -ISrc/OSD/SDL/ -ISrc/OSD/Windows/ -c -Wall -DSUPERMODEL_WIN32 -DGLEW_STATIC -O3
CFLAGS = $(COMPILER_FLAGS) CFLAGS = $(COMPILER_FLAGS)
CPPFLAGS = $(COMPILER_FLAGS) -I$(BOOST_INCLUDEPATH) -std=c++11 CPPFLAGS = $(COMPILER_FLAGS) -I$(BOOST_INCLUDEPATH) -std=c++11
LFLAGS = -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lz -l:$(WINSDK_LIBPATH)/WbemUuid.lib -s LFLAGS = -o $(OUTFILE) $(OBJ) -L$(SDL_LIBPATH) -lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32 -ldinput8 -ldxguid -lole32 -loleaut32 -lwbemuuid -lz -s #-l:$(WINSDK_LIBPATH)/WbemUuid.lib -s
# #
# Build options... # Build options...
@ -131,7 +133,9 @@ OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/Config.o $(OBJ_DIR)/I
$(OBJ_DIR)/Outputs.o $(OBJ_DIR)/WinOutputs.o \ $(OBJ_DIR)/Outputs.o $(OBJ_DIR)/WinOutputs.o \
$(OBJ_DIR)/amp_audio.o $(OBJ_DIR)/amp_dump.o $(OBJ_DIR)/amp_getbits.o $(OBJ_DIR)/amp_getdata.o $(OBJ_DIR)/amp_huffman.o \ $(OBJ_DIR)/amp_audio.o $(OBJ_DIR)/amp_dump.o $(OBJ_DIR)/amp_getbits.o $(OBJ_DIR)/amp_getdata.o $(OBJ_DIR)/amp_huffman.o \
$(OBJ_DIR)/amp_layer2.o $(OBJ_DIR)/amp_layer3.o $(OBJ_DIR)/amp_misc2.o $(OBJ_DIR)/amp_position.o $(OBJ_DIR)/amp_transform.o \ $(OBJ_DIR)/amp_layer2.o $(OBJ_DIR)/amp_layer3.o $(OBJ_DIR)/amp_misc2.o $(OBJ_DIR)/amp_position.o $(OBJ_DIR)/amp_transform.o \
$(OBJ_DIR)/amp_util.o $(OBJ_DIR)/amp_util.o \
$(OBJ_DIR)/Crypto.o \
$(OBJ_DIR)/Format.o
# If built-in debugger enabled, include all debugging classes # If built-in debugger enabled, include all debugging classes
@ -250,6 +254,9 @@ $(OBJ_DIR)/%.o: Src/OSD/Windows/%.cpp
$(OBJ_DIR)/%.o: Src/Pkgs/%.c $(OBJ_DIR)/%.o: Src/Pkgs/%.c
$(CC) $< $(CFLAGS) -o $(OBJ_DIR)/$(*F).o $(CC) $< $(CFLAGS) -o $(OBJ_DIR)/$(*F).o
$(OBJ_DIR)/%.o: Src/Util/%.cpp Src/Util/%.h
$(CC) $< $(CPPFLAGS) -o $(OBJ_DIR)/$(*F).o
# #
# AMP MPEG decoder library # AMP MPEG decoder library
# #

1031
Src/Model3/Crypto.cpp Normal file

File diff suppressed because it is too large Load diff

123
Src/Model3/Crypto.h Normal file
View file

@ -0,0 +1,123 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011-2016 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel 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 Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* Crypto.h
*
* Header file for security board encryption device. This code was taken from
* MAME (http://mamedev.org).
*/
// license:BSD-3-Clause
// copyright-holders:David Haywood
#pragma once
#ifndef __SEGA315_5881_CRYPT__
#define __SEGA315_5881_CRYPT__
#include <cstdint>
#include <memory>
#include <functional>
class CBlockFile;
class CCrypto
{
public:
// construction/destruction
CCrypto();
void SaveState(CBlockFile *SaveState);
void LoadState(CBlockFile *SaveState);
void Init(uint32_t encryptionKey, std::function<uint16_t(uint32_t)> ReadRAMCallback);
void Reset();
uint16_t Decrypt(uint8_t **base);
void SetAddressLow(uint16_t data);
void SetAddressHigh(uint16_t data);
void SetSubKey(uint16_t data);
std::function<uint16_t(uint32_t)> m_read;
/*
static void set_read_cb(device_t &device,sega_m2_read_delegate readcb)
{
sega_315_5881_crypt_device &dev = downcast<sega_315_5881_crypt_device &>(device);
dev.m_read = readcb;
}
*/
private:
uint32_t key;
std::unique_ptr<uint8_t[]> buffer;
std::unique_ptr<uint8_t[]> line_buffer;
std::unique_ptr<uint8_t[]> line_buffer_prev;
uint32_t prot_cur_address;
uint16_t subkey, dec_hist;
uint32_t dec_header;
bool enc_ready;
int buffer_pos, line_buffer_pos, line_buffer_size, buffer_bit, buffer_bit2;
uint8_t buffer2[2];
uint16_t buffer2a;
int block_size;
int block_pos;
int block_numlines;
int done_compression;
struct sbox {
uint8_t table[64];
int inputs[6]; // positions of the inputs bits, -1 means no input except from key
int outputs[2]; // positions of the output bits
};
static const sbox fn1_sboxes[4][4];
static const sbox fn2_sboxes[4][4];
static const int FN1GK = 38;
static const int FN2GK = 32;
static const int fn1_game_key_scheduling[FN1GK][2];
static const int fn2_game_key_scheduling[FN2GK][2];
static const int fn1_sequence_key_scheduling[20][2];
static const int fn2_sequence_key_scheduling[16];
static const int fn2_middle_result_scheduling[16];
static const uint8_t trees[9][2][32];
int feistel_function(int input, const struct sbox *sboxes, uint32_t subkeys);
uint16_t block_decrypt(uint32_t game_key, uint16_t sequence_key, uint16_t counter, uint16_t data);
uint16_t get_decrypted_16();
int get_compressed_bit();
void enc_start();
void enc_fill();
void line_fill();
};
#endif

View file

@ -1,7 +1,7 @@
/** /**
** Supermodel ** Supermodel
** A Sega Model 3 Arcade Emulator. ** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson ** Copyright 2011-2016 Bart Trzynadlowski, Nik Henson
** **
** This file is part of Supermodel. ** This file is part of Supermodel.
** **
@ -27,8 +27,9 @@
* To-Do List * To-Do List
* ---------- * ----------
* - Save state format has changed slightly. No longer need dmaUnknownRegister * - Save state format has changed slightly. No longer need dmaUnknownRegister
* in Real3D.cpp. PowerPC timing variables have changed. Before 0.3a * in Real3D.cpp and security board-related variable was added to Model 3
* release, important to change format version #. * state. PowerPC timing variables have changed. Before 0.3a release,
* important to change format version #.
* - ROM sets should probably be handled with a class that manages ROM * - ROM sets should probably be handled with a class that manages ROM
* loading, the game list, as well as ROM patching * loading, the game list, as well as ROM patching
* - Wrap up CPU emulation inside a class. * - Wrap up CPU emulation inside a class.
@ -184,6 +185,16 @@
* G32 --- * G32 ---
* G31 Right Turbo * G31 Right Turbo
* G30 Right Shot Trigger * G30 Right Shot Trigger
*
* Misc. Notes
* -----------
*
* daytona2:
* - Base address of program in CROM: 0x600000
* - 0x10019E is the location in RAM which contains link type.
* - Region menu can be accessed by entering test mode, holding start, and
* pressing: green, green, blue, yellow, red, yellow, blue
* (VR4,4,2,3,1,3,2).
*/ */
#include <new> #include <new>
@ -191,6 +202,10 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "Supermodel.h" #include "Supermodel.h"
#include "Util/Format.h"
#include <functional>
#include <set>
#include <sstream>
/****************************************************************************** /******************************************************************************
Model 3 Inputs Model 3 Inputs
@ -636,130 +651,30 @@ void CModel3::WriteInputs(unsigned reg, UINT8 data)
seems to help avoid this. seems to help avoid this.
******************************************************************************/ ******************************************************************************/
static const UINT16 spikeoutSecurity[] = uint16_t CModel3::ReadSecurityRAM(uint32_t addr)
{ {
0x0000, if (addr < 0x8000)
0x4f4d, 0x4544, 0x2d4c, 0x2033, 0x7953, 0x7473, 0x6d65, 0x5020, return (*(uint32_t *) &securityRAM[addr * 4]) >> 16;
0x6f72, 0x7267, 0x6d61, 0x4320, 0x706f, 0x7279, 0x6769, 0x7468, return 0;
0x2820, 0x2943, 0x3120, 0x3939, 0x2035, 0x4553, 0x4147, 0x4520, }
0x746e, 0x7265, 0x7270, 0x7369, 0x7365, 0x4c2c, 0x4454, 0x202e,
0x6c41, 0x206c, 0x6972, 0x6867, 0x2074, 0x6572, 0x6573, 0x7672,
0x6465, 0x202e, 0x2020, 0x0020
};
static const UINT16 vs298Security[] =
{
0x0000, // dummy read
0x4A20, 0x5041, 0x4E41, 0x4920, 0x4154, 0x594C, 0x4220, 0x4152, 0x4953, 0x204C,
0x5241, 0x4547, 0x544E, 0x4E49, 0x2041, 0x4547, 0x4D52, 0x4E41, 0x2059, 0x4E45,
0x4C47, 0x4E41, 0x2044, 0x454E, 0x4854, 0x5245, 0x414C, 0x444E, 0x2053, 0x5246,
0x4E41, 0x4543, 0x4320, 0x4C4F, 0x4D4F, 0x4942, 0x2041, 0x4150, 0x4152, 0x5547,
0x5941, 0x4220, 0x4C55, 0x4147, 0x4952, 0x2041, 0x5053, 0x4941, 0x204E, 0x5243,
0x414F, 0x4954, 0x2041, 0x4542, 0x474C, 0x5549, 0x204D, 0x494E, 0x4547, 0x4952,
0x2041, 0x4153, 0x4455, 0x2049, 0x4F4B, 0x4552, 0x2041, 0x4544, 0x4D4E, 0x5241,
0x204B, 0x4F52, 0x414D, 0x494E, 0x2041, 0x4353, 0x544F, 0x414C, 0x444E, 0x5520,
0x4153, 0x5320, 0x554F, 0x4854, 0x4641, 0x4952, 0x4143, 0x4D20, 0x5845, 0x4349,
0x204F, 0x5559, 0x4F47, 0x4C53, 0x5641, 0x4149, 0x4620, 0x5F43, 0x4553, 0x4147
};
static const UINT16 ecaSecurity[] =
{
0x0000,
0x2d2f, 0x202d, 0x4d45, 0x5245, 0x4547, 0x434e, 0x2059, 0x4143,
0x4c4c, 0x4120, 0x424d, 0x4c55, 0x4e41, 0x4543, 0x2d20, 0x0a2d,
0x6f43, 0x7970, 0x6952, 0x6867, 0x2074, 0x4553, 0x4147, 0x4520,
0x746e, 0x7265, 0x7270, 0x7369, 0x7365, 0x202c, 0x744c, 0x2e64,
0x530a, 0x666f, 0x7774, 0x7261, 0x2065, 0x2652, 0x2044, 0x6544,
0x7470, 0x202e, 0x3123, 0x660a, 0x726f, 0x7420, 0x7365, 0x0a74,
};
static const UINT16 oceanhunSecurity[57] =
{
0x0000, // dummy read
0x3d3d, 0x203d, 0x434f, 0x4145, 0x204e, 0x5548, 0x544e, 0x5245,
0x3d20, 0x3d3d, 0x430a, 0x706f, 0x5279, 0x6769, 0x7468, 0x5320,
0x4745, 0x2041, 0x6e45, 0x6574, 0x7072, 0x6972, 0x6573, 0x2c73,
0x4c20, 0x6474, 0x0a2e, 0x6d41, 0x7375, 0x6d65, 0x6e65, 0x2074,
0x2652, 0x2044, 0x6544, 0x7470, 0x202e, 0x3123, 0x4b0a, 0x7a61,
0x6e75, 0x7261, 0x2069, 0x7354, 0x6b75, 0x6d61, 0x746f, 0x206f,
0x6553, 0x7463, 0x6f69, 0x206e, 0x614d, 0x616e, 0x6567, 0x0a72
};
static const UINT16 swtrilgySecurity[57] =
{
0xffff,
0x3d3d, 0x3d3d, 0x203d, 0x5453, 0x5241, 0x5720, 0x5241, 0x2053,
0x3d3d, 0x3d3d, 0x0a3d, 0x6f43, 0x7970, 0x6952, 0x6867, 0x2074,
0x4553, 0x4147, 0x4520, 0x746e, 0x7265, 0x7270, 0x7369, 0x7365,
0x202c, 0x744c, 0x2e64, 0x410a, 0x756d, 0x6573, 0x656d, 0x746e,
0x5220, 0x4426, 0x4420, 0x7065, 0x2e74, 0x2320, 0x3231, 0x4b0a,
0x7461, 0x7573, 0x6179, 0x7573, 0x4120, 0x646e, 0x206f, 0x2026,
0x614b, 0x6f79, 0x6f6b, 0x5920, 0x6d61, 0x6d61, 0x746f, 0x0a6f
};
static const UINT16 fvipers2Security[65] =
{
0x2a2a,
0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x202a, 0x5b5b,
0x4620, 0x6769, 0x7468, 0x6e69, 0x2067, 0x6956, 0x6570, 0x7372,
0x3220, 0x5d20, 0x205d, 0x6e69, 0x3c20, 0x4d3c, 0x444f, 0x4c45,
0x332d, 0x3e3e, 0x4320, 0x706f, 0x7279, 0x6769, 0x7468, 0x2820,
0x2943, 0x3931, 0x3839, 0x5320, 0x4745, 0x2041, 0x6e45, 0x6574,
0x7072, 0x6972, 0x6573, 0x2c73, 0x544c, 0x2e44, 0x2020, 0x4120,
0x6c6c, 0x7220, 0x6769, 0x7468, 0x7220, 0x7365, 0x7265, 0x6576,
0x2e64, 0x2a20, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a
};
UINT32 CModel3::ReadSecurity(unsigned reg) UINT32 CModel3::ReadSecurity(unsigned reg)
{ {
UINT32 data;
switch (reg) switch (reg)
{ {
case 0x00: // Status case 0x00: // Status
return 0; return 0;
case 0x1C: // Data case 0x1C: // Data
if (!strcmp(Game->id, "spikeout") || !strcmp(Game->id, "spikeofe")) if (m_securityFirstRead)
{ {
data = (spikeoutSecurity[securityPtr++] << 16); m_securityFirstRead = false;
securityPtr %= (sizeof(spikeoutSecurity)/sizeof(UINT16)); return 0xFFFF0000;
} }
else if (!strcmp(Game->id, "vs298") ||
!strcmp(Game->id, "vs2v991") || !strcmp(Game->id, "vs299") ||
!strcmp(Game->id, "vs299a") || !strcmp(Game->id, "vs299b"))
{
data = (vs298Security[securityPtr++] << 16);
securityPtr %= (sizeof(vs298Security)/sizeof(UINT16));
}
else if (!strcmp(Game->id, "eca") || !strcmp(Game->id, "ecax"))
{
data = (ecaSecurity[securityPtr++] << 16);
securityPtr %= (sizeof(ecaSecurity)/sizeof(UINT16));
}
else if (!strcmp(Game->id, "oceanhun"))
{
data = (oceanhunSecurity[securityPtr++] << 16);
securityPtr %= (sizeof(oceanhunSecurity)/sizeof(UINT16));
}
else if (!strcmp(Game->id, "swtrilgy") || !strcmp(Game->id, "swtrilgya"))
{
data = (swtrilgySecurity[securityPtr++] << 16);
securityPtr %= (sizeof(swtrilgySecurity)/sizeof(UINT16));
}
else if (!strcmp(Game->id, "fvipers2"))
{
data = (fvipers2Security[securityPtr++] << 16);
securityPtr %= (sizeof(fvipers2Security)/sizeof(UINT16));
}
else if (!strcmp(Game->id, "von2"))
data = 0xFFFFFFFF;
else else
{ {
data = 0xFFFFFFFF; uint8_t *base_ptr;
DebugLog("Security read: reg=%X, PC=%08X, LR=%08X\n", reg, ppc_get_pc(), ppc_get_lr()); return m_cryptoDevice.Decrypt(&base_ptr) << 16;
} }
return data;
default: default:
DebugLog("Security read: reg=%X\n", reg); DebugLog("Security read: reg=%X\n", reg);
break; break;
@ -770,7 +685,25 @@ UINT32 CModel3::ReadSecurity(unsigned reg)
void CModel3::WriteSecurity(unsigned reg, UINT32 data) void CModel3::WriteSecurity(unsigned reg, UINT32 data)
{ {
switch (reg)
{
case 0x10:
case 0x14:
m_cryptoDevice.SetAddressLow(0);
m_cryptoDevice.SetAddressHigh(0);
m_securityFirstRead = true;
break;
case 0x18:
{
uint16_t subKey = data >> 16;
subKey = ((subKey & 0xFF00) >> 8) | ((subKey & 0x00FF) << 8);
m_cryptoDevice.SetSubKey(subKey);
break;
}
default:
DebugLog("Security write: reg=%X, data=%08X (PC=%08X, LR=%08X)\n", reg, data, ppc_get_pc(), ppc_get_lr()); DebugLog("Security write: reg=%X, data=%08X (PC=%08X, LR=%08X)\n", reg, data, ppc_get_pc(), ppc_get_lr());
break;
}
} }
@ -831,7 +764,6 @@ void CModel3::SetCROMBank(unsigned idx)
idx = (~idx) & 0xF; idx = (~idx) & 0xF;
cromBank = &crom[0x800000 + (idx*0x800000)]; cromBank = &crom[0x800000 + (idx*0x800000)];
DebugLog("CROM bank setting: %d (%02X), PC=%08X, LR=%08X\n", idx, cromBankReg, ppc_get_pc(), ppc_get_lr()); DebugLog("CROM bank setting: %d (%02X), PC=%08X, LR=%08X\n", idx, cromBankReg, ppc_get_pc(), ppc_get_lr());
//printf("CROM bank setting: %d (%02X), PC=%08X, LR=%08X\n", idx, cromBankReg, ppc_get_pc(), ppc_get_lr());
} }
UINT8 CModel3::ReadSystemRegister(unsigned reg) UINT8 CModel3::ReadSystemRegister(unsigned reg)
@ -965,7 +897,7 @@ UINT8 CModel3::Read8(UINT32 addr)
// 53C810 SCSI // 53C810 SCSI
case 0xC0: // only on Step 1.0 case 0xC0: // only on Step 1.0
if (Game->step != 0x10) // check for Step 1.0 if (Game->step != 0x10)
break; break;
case 0xF9: case 0xF9:
case 0xC1: case 0xC1:
@ -1499,6 +1431,7 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
// Security board RAM // Security board RAM
case 0x18: case 0x18:
case 0x19:
*(UINT32 *) &securityRAM[(addr&0x1FFFF)] = data; *(UINT32 *) &securityRAM[(addr&0x1FFFF)] = data;
break; break;
@ -1903,7 +1836,6 @@ void CModel3::Write64(UINT32 addr, UINT64 data)
Write32(addr+4, (UINT32) data); Write32(addr+4, (UINT32) data);
} }
#endif #endif
@ -1926,6 +1858,8 @@ void CModel3::SaveState(CBlockFile *SaveState)
SaveState->Write(backupRAM, 0x20000); SaveState->Write(backupRAM, 0x20000);
SaveState->Write(securityRAM, 0x20000); SaveState->Write(securityRAM, 0x20000);
SaveState->Write(&midiCtrlPort, sizeof(midiCtrlPort)); SaveState->Write(&midiCtrlPort, sizeof(midiCtrlPort));
int32_t securityFirstRead = m_securityFirstRead;
SaveState->Write(&securityFirstRead, sizeof(securityFirstRead));
// All devices... // All devices...
ppc_save_state(SaveState); ppc_save_state(SaveState);
@ -1937,6 +1871,7 @@ void CModel3::SaveState(CBlockFile *SaveState)
GPU.SaveState(SaveState); GPU.SaveState(SaveState);
SoundBoard.SaveState(SaveState); // also saves DSB state SoundBoard.SaveState(SaveState); // also saves DSB state
DriveBoard.SaveState(SaveState); DriveBoard.SaveState(SaveState);
m_cryptoDevice.SaveState(SaveState);
} }
void CModel3::LoadState(CBlockFile *SaveState) void CModel3::LoadState(CBlockFile *SaveState)
@ -1960,6 +1895,9 @@ void CModel3::LoadState(CBlockFile *SaveState)
SaveState->Read(backupRAM, 0x20000); SaveState->Read(backupRAM, 0x20000);
SaveState->Read(securityRAM, 0x20000); SaveState->Read(securityRAM, 0x20000);
SaveState->Read(&midiCtrlPort, sizeof(midiCtrlPort)); SaveState->Read(&midiCtrlPort, sizeof(midiCtrlPort));
int32_t securityFirstRead;
SaveState->Write(&securityFirstRead, sizeof(securityFirstRead));
m_securityFirstRead = securityFirstRead;
// All devices... // All devices...
GPU.LoadState(SaveState); GPU.LoadState(SaveState);
@ -1971,6 +1909,7 @@ void CModel3::LoadState(CBlockFile *SaveState)
ppc_load_state(SaveState); ppc_load_state(SaveState);
SoundBoard.LoadState(SaveState); SoundBoard.LoadState(SaveState);
DriveBoard.LoadState(SaveState); DriveBoard.LoadState(SaveState);
m_cryptoDevice.LoadState(SaveState);
} }
void CModel3::SaveNVRAM(CBlockFile *NVRAM) void CModel3::SaveNVRAM(CBlockFile *NVRAM)
@ -2015,9 +1954,9 @@ void CModel3::RunFrame(void)
goto ThreadError; goto ThreadError;
// Wake threads for PPC main board (if multi-threading GPU), sound board (if sync'd) and drive board (if attached) so they can process a frame // Wake threads for PPC main board (if multi-threading GPU), sound board (if sync'd) and drive board (if attached) so they can process a frame
if (g_Config.gpuMultiThreaded && !ppcBrdThreadSync->Post() || if ((g_Config.gpuMultiThreaded && !ppcBrdThreadSync->Post()) ||
syncSndBrdThread && !sndBrdThreadSync->Post() || (syncSndBrdThread && !sndBrdThreadSync->Post()) ||
DriveBoard.IsAttached() && !drvBrdThreadSync->Post()) (DriveBoard.IsAttached() && !drvBrdThreadSync->Post()))
goto ThreadError; goto ThreadError;
// If not multi-threading GPU, then run PPC main board for a frame and sync GPUs now in this thread // If not multi-threading GPU, then run PPC main board for a frame and sync GPUs now in this thread
@ -2035,9 +1974,9 @@ void CModel3::RunFrame(void)
goto ThreadError; goto ThreadError;
// Wait for PPC main board, sound board and drive board threads to finish their work (if they are running and haven't finished already) // Wait for PPC main board, sound board and drive board threads to finish their work (if they are running and haven't finished already)
while (g_Config.gpuMultiThreaded && !ppcBrdThreadDone || while ((g_Config.gpuMultiThreaded && !ppcBrdThreadDone) ||
syncSndBrdThread && !sndBrdThreadDone || (syncSndBrdThread && !sndBrdThreadDone) ||
DriveBoard.IsAttached() && !drvBrdThreadDone) (DriveBoard.IsAttached() && !drvBrdThreadDone))
{ {
if (!notifySync->Wait(notifyLock)) if (!notifySync->Wait(notifyLock))
goto ThreadError; goto ThreadError;
@ -2199,20 +2138,15 @@ void CModel3::RenderFrame(void)
bool CModel3::RunSoundBoardFrame(void) bool CModel3::RunSoundBoardFrame(void)
{ {
UINT32 start = CThread::GetTicks(); UINT32 start = CThread::GetTicks();
bool bufferFull = SoundBoard.RunFrame(); bool bufferFull = SoundBoard.RunFrame();
timings.sndTicks = CThread::GetTicks() - start; timings.sndTicks = CThread::GetTicks() - start;
return bufferFull; return bufferFull;
} }
void CModel3::RunDriveBoardFrame(void) void CModel3::RunDriveBoardFrame(void)
{ {
UINT32 start = CThread::GetTicks(); UINT32 start = CThread::GetTicks();
DriveBoard.RunFrame(); DriveBoard.RunFrame();
timings.drvTicks = CThread::GetTicks() - start; timings.drvTicks = CThread::GetTicks() - start;
} }
@ -2816,6 +2750,7 @@ void CModel3::Reset(void)
// Reset security device // Reset security device
securityPtr = 0; securityPtr = 0;
m_securityFirstRead = true;
// Reset inputs // Reset inputs
inputBank = 0; inputBank = 0;
@ -2841,6 +2776,8 @@ void CModel3::Reset(void)
if (DriveBoard.IsAttached()) if (DriveBoard.IsAttached())
DriveBoard.Reset(); DriveBoard.Reset();
m_cryptoDevice.Reset();
gpusReady = false; gpusReady = false;
timings.ppcTicks = 0; timings.ppcTicks = 0;
@ -2875,8 +2812,7 @@ void CModel3::Patch(void)
{ {
*(UINT32 *) &crom[0x7374f4] = 0x38840004; // an actual bug in the game code *(UINT32 *) &crom[0x7374f4] = 0x38840004; // an actual bug in the game code
} }
else if (!strcmp(Game->id, "vs215") || else if (!strcmp(Game->id, "vs215") || !strcmp(Game->id, "vs215o") || !strcmp(Game->id, "vs29815"))
!strcmp(Game->id, "vs215o") || !strcmp(Game->id, "vs29815"))
{ {
// VS215 is a modification of VS2 that runs on Step 1.5 hardware. I // VS215 is a modification of VS2 that runs on Step 1.5 hardware. I
// suspect the code here is trying to detect the system type but am too // suspect the code here is trying to detect the system type but am too
@ -2898,23 +2834,6 @@ void CModel3::Patch(void)
*(UINT32 *) &crom[0x7C0C8] = 0x60000000; *(UINT32 *) &crom[0x7C0C8] = 0x60000000;
*(UINT32 *) &crom[0x7C0CC] = 0x60000000; *(UINT32 *) &crom[0x7C0CC] = 0x60000000;
} }
else if (!strcmp(Game->id, "daytona2"))
{
// Base address of program in CROM: 0x600000
// 0x10019E is the location in RAM which contains link type.
// Region menu can be accessed by entering test mode, holding start,
// and pressing: green, green, blue, yellow, red, yellow, blue (VR4,4,2,3,1,3,2)
*(UINT32 *) &crom[0x68468c] = 0x60000000; // protection device
*(UINT32 *) &crom[0x6063c4] = 0x60000000; // needed to allow levels to load
*(UINT32 *) &crom[0x616434] = 0x60000000; // prevents PPC from executing invalid code (MMU?)
*(UINT32 *) &crom[0x69f4e4] = 0x60000000; // ""
}
else if (!strcmp(Game->id, "dayto2pe"))
{
//*(UINT32 *) &crom[0x606784] = 0x60000000;
*(UINT32 *) &crom[0x69A3FC] = 0x60000000; // MAME says: jump to encrypted code
*(UINT32 *) &crom[0x618B28] = 0x60000000; // MAME says: jump to encrypted code
}
else if (!strcmp(Game->id, "harley")) else if (!strcmp(Game->id, "harley"))
{ {
*(UINT32 *) &crom[0x50E8D4] = 0x60000000; *(UINT32 *) &crom[0x50E8D4] = 0x60000000;
@ -2941,35 +2860,29 @@ void CModel3::Patch(void)
else if (!strcmp(Game->id, "eca") || !strcmp(Game->id, "ecax")) else if (!strcmp(Game->id, "eca") || !strcmp(Game->id, "ecax"))
{ {
*(UINT32 *) &crom[0x535580] = 0x60000000; *(UINT32 *) &crom[0x535580] = 0x60000000;
*(UINT32 *) &crom[0x5023B4] = 0x60000000; //*(UINT32 *) &crom[0x5023B4] = 0x60000000;
*(UINT32 *) &crom[0x5023D4] = 0x60000000; //*(UINT32 *) &crom[0x5023D4] = 0x60000000;
} }
} }
// Reverses all aligned 16-bit words, thereby switching their endianness (assumes buffer size is divisible by 2) // Reverses all aligned 16-bit words, thereby switching their endianness (assumes buffer size is divisible by 2)
static void Reverse16(UINT8 *buf, unsigned size) static void Reverse16(uint8_t *buf, size_t size)
{ {
unsigned i; for (size_t i = 0; i < size; i += 2)
UINT8 tmp;
for (i = 0; i < size; i += 2)
{ {
tmp = buf[i+0]; uint8_t tmp = buf[i+0];
buf[i+0] = buf[i+1]; buf[i+0] = buf[i+1];
buf[i+1] = tmp; buf[i+1] = tmp;
} }
} }
// Reverses all aligned 32-bit words, thereby switching their endianness (assumes buffer size is divisible by 4) // Reverses all aligned 32-bit words, thereby switching their endianness (assumes buffer size is divisible by 4)
static void Reverse32(UINT8 *buf, unsigned size) static void Reverse32(uint8_t *buf, size_t size)
{ {
unsigned i; for (size_t i = 0; i < size; i += 4)
UINT8 tmp1, tmp2;
for (i = 0; i < size; i += 4)
{ {
tmp1 = buf[i+0]; uint8_t tmp1 = buf[i+0];
tmp2 = buf[i+1]; uint8_t tmp2 = buf[i+1];
buf[i+0] = buf[i+3]; buf[i+0] = buf[i+3];
buf[i+1] = buf[i+2]; buf[i+1] = buf[i+2];
buf[i+2] = tmp2; buf[i+2] = tmp2;
@ -2977,63 +2890,6 @@ static void Reverse32(UINT8 *buf, unsigned size)
} }
} }
// Reads in CROMs directly (for debugging purposes only)
static void ReadCROMDirectly(UINT8 *crom, char *fileName[4], unsigned combinedSize)
{
FILE *fp[4] = { NULL, NULL, NULL, NULL };
// Open all files
for (int i = 0; i < 4; i++)
{
fp[i] = fopen(fileName[i],"rb");
if (NULL == fp[i])
{
ErrorLog("Unable to open file for reading: %s.", fileName[i]);
goto ReadCleanup;
}
}
// Read and interleave 2 bytes at a time
for (unsigned i = 0; i < combinedSize; i += 8)
{
fread(&crom[i+0], 1, 2, fp[0]);
fread(&crom[i+2], 1, 2, fp[1]);
fread(&crom[i+4], 1, 2, fp[2]);
fread(&crom[i+6], 1, 2, fp[3]);
}
Reverse16(crom, combinedSize); // byte reverse ROMs
// Reverse 32 bit words for Supermodel
Reverse32(crom, combinedSize);
ReadCleanup:
for (int i = 0; i < 4; i++)
{
if (fp[i] != NULL)
fclose(fp[i]);
}
}
// Dumps a memory region to a file for debugging purposes
static void Dump(const char *file, UINT8 *buf, unsigned size, bool reverse32, bool reverse16)
{
FILE *fp;
fp = fopen(file, "wb");
if (NULL != fp)
{
if (reverse32)
Reverse32(buf, size);
else if (reverse16)
Reverse16(buf, size);
fwrite(buf, sizeof(UINT8), size, fp);
fclose(fp);
printf("dumped %s\n", file);
}
else
printf("unable to dump %s\n", file);
}
// Offsets of memory regions within Model 3's pool // Offsets of memory regions within Model 3's pool
#define OFFSET_RAM 0 // 8 MB #define OFFSET_RAM 0 // 8 MB
#define OFFSET_CROM 0x800000 // 8 MB (fixed CROM) #define OFFSET_CROM 0x800000 // 8 MB (fixed CROM)
@ -3181,29 +3037,27 @@ bool CModel3::LoadROMSet(const struct GameInfo *GameList, const char *zipFile)
else else
DriveBoard.Init(NULL); // disable DriveBoard.Init(NULL); // disable
// Security board encryption device
m_cryptoDevice.Init(Game->encryptionKey, std::bind(&CModel3::ReadSecurityRAM, this, std::placeholders::_1));
// Apply ROM patches // Apply ROM patches
Patch(); Patch();
// Print game information // Print game information
std::set<std::string> extraHw;
if (Game->mpegBoard)
extraHw.insert(Util::Format() << "Digital Sound Board (Type " << Game->mpegBoard << ")");
if (Game->driveBoard)
extraHw.insert("Drive Board");
if (Game->encryptionKey)
extraHw.insert("Security Board");
printf(" Title: %s\n", Game->title); printf(" Title: %s\n", Game->title);
printf(" ROM Set: %s\n", Game->id); printf(" ROM Set: %s\n", Game->id);
printf(" Developer: %s\n", Game->mfgName); printf(" Developer: %s\n", Game->mfgName);
printf(" Year: %d\n", Game->year); printf(" Year: %d\n", Game->year);
printf(" Step: %d.%d\n", (Game->step>>4)&0xF, Game->step&0xF); printf(" Step: %d.%d\n", (Game->step>>4)&0xF, Game->step&0xF);
if (Game->mpegBoard) printf(" Extra Hardware: %s\n", Util::Format(", ").Join(extraHw).str().c_str());
{
printf(" Extra Hardware: Digital Sound Board (Type %d)", Game->mpegBoard);
if (Game->driveBoard)
printf(", Drive Board");
printf("\n"); printf("\n");
}
else if (Game->driveBoard)
printf(" Extra Hardware: Drive Board\n");
printf("\n");
// Load patched CROM directly (for testing out ROM patches)
//char *fileName[4] = { "epr-20599a.patched.20","epr-20598a.patched.19","epr-20597a.patched.18","epr-20596a.patched.17" };
//ReadCROMDirectly(crom, fileName, 0x800000);
return OKAY; return OKAY;
} }
@ -3259,7 +3113,7 @@ bool CModel3::Init(void)
driveROM = &memoryPool[OFFSET_DRIVEROM]; driveROM = &memoryPool[OFFSET_DRIVEROM];
SetCROMBank(0xFF); SetCROMBank(0xFF);
// Initialize other devices (PowerPC and DSB initialized after ROMs loaded) // Initialize other devices (PowerPC, DSB, and security board initialized after ROMs loaded)
IRQ.Init(); IRQ.Init();
PCIBridge.Init(); PCIBridge.Init();
PCIBus.Init(); PCIBus.Init();
@ -3339,17 +3193,37 @@ CModel3::CModel3(void)
DebugLog("Built Model 3\n"); DebugLog("Built Model 3\n");
} }
/*
// Dumps a memory region to a file for debugging purposes
static void Dump(const char *file, uint8_t *buf, size_t size, bool reverse32, bool reverse16)
{
FILE *fp = fopen(file, "wb");
if (NULL != fp)
{
if (reverse32)
Reverse32(buf, size);
else if (reverse16)
Reverse16(buf, size);
fwrite(buf, sizeof(UINT8), size, fp);
fclose(fp);
printf("dumped %s\n", file);
}
else
printf("unable to dump %s\n", file);
}
*/
CModel3::~CModel3(void) CModel3::~CModel3(void)
{ {
/*
// Debug: dump some files // Debug: dump some files
#if 0
//Dump("ram", ram, 0x800000, true, false); //Dump("ram", ram, 0x800000, true, false);
//Dump("vrom", vrom, 0x4000000, true, false); //Dump("vrom", vrom, 0x4000000, true, false);
Dump("crom", crom, 0x800000, true, false); Dump("crom", crom, 0x800000, true, false);
//Dump("bankedCrom", &crom[0x800000], 0x7000000, true, false); //Dump("bankedCrom", &crom[0x800000], 0x7000000, true, false);
//Dump("soundROM", soundROM, 0x80000, false, true); //Dump("soundROM", soundROM, 0x80000, false, true);
//Dump("sampleROM", sampleROM, 0x800000, false, true); //Dump("sampleROM", sampleROM, 0x800000, false, true);
#endif */
// Stop all threads // Stop all threads
StopThreads(); StopThreads();

View file

@ -28,6 +28,7 @@
#ifndef INCLUDED_MODEL3_H #ifndef INCLUDED_MODEL3_H
#define INCLUDED_MODEL3_H #define INCLUDED_MODEL3_H
#include "Model3/Crypto.h"
/* /*
* FrameTimings * FrameTimings
@ -370,6 +371,7 @@ private:
// Private member functions // Private member functions
UINT8 ReadInputs(unsigned reg); UINT8 ReadInputs(unsigned reg);
void WriteInputs(unsigned reg, UINT8 data); void WriteInputs(unsigned reg, UINT8 data);
uint16_t ReadSecurityRAM(uint32_t addr);
UINT32 ReadSecurity(unsigned reg); UINT32 ReadSecurity(unsigned reg);
void WriteSecurity(unsigned reg, UINT32 data); void WriteSecurity(unsigned reg, UINT32 data);
void SetCROMBank(unsigned idx); void SetCROMBank(unsigned idx);
@ -403,10 +405,8 @@ private:
// Game and hardware information // Game and hardware information
const struct GameInfo *Game; const struct GameInfo *Game;
// Game inputs // Game inputs and outputs
CInputs *Inputs; CInputs *Inputs;
// Game outputs
COutputs *Outputs; COutputs *Outputs;
// Input registers (game controls) // Input registers (game controls)
@ -436,6 +436,7 @@ private:
unsigned cromBankReg; // the CROM bank register unsigned cromBankReg; // the CROM bank register
// Security device // Security device
bool m_securityFirstRead = true;
unsigned securityPtr; // pointer to current offset in security data unsigned securityPtr; // pointer to current offset in security data
// PowerPC // PowerPC
@ -482,6 +483,7 @@ private:
CSoundBoard SoundBoard; // Sound board CSoundBoard SoundBoard; // Sound board
CDSB *DSB; // Digital Sound Board (type determined dynamically at load time) CDSB *DSB; // Digital Sound Board (type determined dynamically at load time)
CDriveBoard DriveBoard; // Drive board CDriveBoard DriveBoard; // Drive board
CCrypto m_cryptoDevice; // Encryption device
}; };

33
Src/Util/Format.cpp Normal file
View file

@ -0,0 +1,33 @@
#include "Util/Format.h"
namespace Util
{
static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
const std::string Hex(uint32_t n, size_t num_digits)
{
Util::Format f;
f << "0x";
for (size_t b = num_digits * 4; b; )
{
b -= 4;
f << hex_digits[(n >> b) & 0xf];
}
return f;
}
const std::string Hex(uint32_t n)
{
return Hex(n, 8);
}
const std::string Hex(uint16_t n)
{
return Hex(n, 4);
}
const std::string Hex(uint8_t n)
{
return Hex(n, 2);
}
} // Util

68
Src/Util/Format.h Normal file
View file

@ -0,0 +1,68 @@
#ifndef INCLUDED_FORMAT_H
#define INCLUDED_FORMAT_H
#include <string>
#include <sstream>
#include <iomanip>
namespace Util
{
class Format
{
public:
template <typename T>
Format &operator<<(const T &data)
{
m_stream << data;
return *this;
}
operator std::string() const
{
return str();
}
std::string str() const
{
return m_stream.str();
}
template <typename T>
Format &Join(const T &collection)
{
std::string separator = m_stream.str();
clear();
for (auto it = collection.begin(); it != collection.end(); )
{
m_stream << *it;
++it;
if (it != collection.end())
m_stream << separator;
}
return *this;
}
Format(const std::string &str)
: m_stream(str)
{
}
Format()
{
}
private:
std::stringstream m_stream;
void clear()
{
m_stream.str(std::string());
}
};
const std::string Hex(uint32_t n, size_t num_digits);
const std::string Hex(uint32_t n);
const std::string Hex(uint16_t n);
const std::string Hex(uint8_t n);
} // Util
#endif // INCLUDED_FORMAT_H