naomi: x76f100 and at93cxx implementation. naomi2 elan fix

proper emulation of x76f100 security eeprom and at93cxx serial eeprom
elan: don't reset projection matrix at end of frame. Issue #1177
This commit is contained in:
Flyinghead 2023-08-25 17:01:40 +02:00
parent 10b13dfe9c
commit 129fff1c2a
16 changed files with 893 additions and 642 deletions

View File

@ -819,10 +819,14 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/bba/bba.cpp
core/hw/bba/rtl8139c.h
core/hw/bba/rtl8139c.cpp
core/hw/flashrom/at93cxx.cpp
core/hw/flashrom/at93cxx.h
core/hw/flashrom/flashrom.cpp
core/hw/flashrom/flashrom.h
core/hw/flashrom/nvmem.cpp
core/hw/flashrom/nvmem.h
core/hw/flashrom/x76f100.cpp
core/hw/flashrom/x76f100.h
core/hw/gdrom/gdrom_if.h
core/hw/gdrom/gdrom_response.cpp
core/hw/gdrom/gdromv3.cpp

View File

@ -0,0 +1,152 @@
/*
Copyright 2023 flyinghead
This file is part of Flycast.
Flycast 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 2 of the License, or
(at your option) any later version.
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "at93cxx.h"
//#define DEBUG_EEPROM 1
#ifdef DEBUG_EEPROM
#define EEPROM_LOG(...) DEBUG_LOG(FLASHROM, __VA_ARGS__)
#else
#define EEPROM_LOG(...)
#endif
void AT93CxxSerialEeprom::writeCLK(bool state)
{
// CS asserted and CLK rising
if (!clk && state && cs)
{
if (dataOutBits > 0)
dataOutBits--;
if (dataOutBits == 0)
{
if (command.empty() && !di)
INFO_LOG(NAOMI, "serial eeprom: Ignoring bit 0 (start bit must be 1)");
else
{
command.push_back(di);
if (command.size() == 9)
{
int opCode = (int)command[1] * 2 + (int)command[2];
switch (opCode)
{
case 0: // write enable/disable, erase all, write all
{
int subCode = (int)command[3] * 2 + (int)command[4];
switch (subCode)
{
case 0: // disable write
EEPROM_LOG("serial eeprom: EWDS");
writeEnable = false;
command.clear();
break;
case 1: // write all
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
break;
case 2: // erase all
EEPROM_LOG("serial eeprom: ERAL");
if (writeEnable)
memset(data, 0xff, size);
command.clear();
break;
case 3: // enable write
EEPROM_LOG("serial eeprom: EWEN");
writeEnable = true;
command.clear();
break;
}
}
break;
case 1: // write
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
break;
case 2: // read
dataOut = Read(getCommandAddress() * 2, 2);
dataOutBits = 17; // actually 16 but 0 means no data
EEPROM_LOG("serial eeprom: READ %x: %x", getCommandAddress(), dataOut);
command.clear();
break;
case 3: // erase
EEPROM_LOG("serial eeprom: ERASE %x", getCommandAddress());
if (writeEnable)
*(u16 *)&data[(getCommandAddress() * 2) & mask] = 0xffff;
command.clear();
break;
}
}
else if (expected > 0 && (int)command.size() == expected)
{
int opCode = (int)command[1] * 2 + (int)command[2];
switch (opCode)
{
case 0: // write all
{
u16 v = getCommandData();
EEPROM_LOG("serial eeprom: WRAL = %x", v);
if (writeEnable)
for (u32 i = 0; i < size; i += 2)
*(u16 *)&data[i & mask] = v;
}
break;
case 1: // write
EEPROM_LOG("serial eeprom: WRITE %x = %x", getCommandAddress(), getCommandData());
if (writeEnable)
*(u16 *)&data[(getCommandAddress() * 2) & mask] = getCommandData();
break;
}
command.clear();
expected = 0;
}
}
}
}
clk = state;
}
void AT93CxxSerialEeprom::Serialize(Serializer& ser) const
{
ser << cs;
ser << clk;
ser << di;
ser << (u32)command.size();
for (bool b : command)
ser << b;
ser << expected;
ser << writeEnable;
ser << dataOut;
ser << dataOutBits;
}
void AT93CxxSerialEeprom::Deserialize(Deserializer& deser)
{
deser >> cs;
deser >> clk;
deser >> di;
u32 size;
deser >> size;
command.resize(size);
for (u32 i = 0; i < size; i++) {
bool b;
deser >> b;
command[i] = b;
}
deser >> expected;
deser >> writeEnable;
deser >> dataOut;
deser >> dataOutBits;
}

106
core/hw/flashrom/at93cxx.h Normal file
View File

@ -0,0 +1,106 @@
/*
Copyright 2023 flyinghead
This file is part of Flycast.
Flycast 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 2 of the License, or
(at your option) any later version.
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "flashrom.h"
#include <vector>
//
// Three-wire Serial EEPROM
//
class AT93CxxSerialEeprom : public WritableChip
{
public:
AT93CxxSerialEeprom(u32 size) : WritableChip(size) {
memset(data, 0xff, size);
}
// combined DO + READY/BUSY
bool readDO()
{
if (dataOutBits > 0)
// DO
return (dataOut >> (dataOutBits - 1)) & 1;
else
// Ready
return true;
}
// chip select (active high)
void writeCS(bool state) {
cs = state;
}
// clock
void writeCLK(bool state);
// data in
void writeDI(bool state) {
di = state;
}
void Write(u32 addr, u32 data, u32 size) override {
die("Unsupported");
}
void Serialize(Serializer& ser) const override;
void Deserialize(Deserializer& deser) override;
private:
u8 getCommandAddress() const
{
verify(command.size() >= 9);
u8 addr = 0;
for (int i = 3; i < 9; i++) {
addr <<= 1;
addr |= command[i];
}
return addr;
}
u16 getCommandData() const
{
verify(command.size() >= 25);
u16 v = 0;
for (int i = 9; i < 25; i++) {
v <<= 1;
v |= command[i];
}
return v;
}
bool cs = false;
bool clk = false;
bool di = false;
std::vector<bool> command;
int expected = 0;
bool writeEnable = false;
u16 dataOut = 0;
u8 dataOutBits = 0;
};
//
// Three-wire Serial EEPROM
// 1 Kb (128 x 8)
//
class AT93C46SerialEeprom : public AT93CxxSerialEeprom
{
public:
AT93C46SerialEeprom() : AT93CxxSerialEeprom(128) {}
};

View File

@ -0,0 +1,282 @@
// Derived from mame src/devices/machine/x76f100.{h,cpp}
// license:BSD-3-Clause
// copyright-holders:smf
#include "x76f100.h"
#include "serialize.h"
void X76F100SerialFlash::writeSCL(bool v)
{
if (!lastCS)
{
switch (state)
{
case State::STOP:
break;
case State::RESPONSE_TO_RESET:
if (lastSCL && !v)
{
if (bit == 0)
shift = responseToReset[byteOffset];
sda = shift & 1;
shift >>= 1;
bit++;
if (bit == 8)
{
bit = 0;
byteOffset++;
if (byteOffset == sizeof(responseToReset))
byteOffset = 0;
}
}
break;
case State::LOAD_COMMAND:
case State::LOAD_PASSWORD:
case State::VERIFY_PASSWORD:
case State::WRITE_DATA:
if (!lastSCL && v)
{
if (bit < 8)
{
shift <<= 1;
if (lastSDA)
shift |= 1;
bit++;
}
else
{
sda = false;
switch (state)
{
case State::LOAD_COMMAND:
command = shift;
DEBUG_LOG(FLASHROM, "-> command: %02x", command);
state = State::LOAD_PASSWORD;
break;
case State::LOAD_PASSWORD:
DEBUG_LOG(FLASHROM, "-> password: %02x", shift);
writeBuffer[byteOffset++] = shift;
if (byteOffset == sizeof(writeBuffer))
{
state = State::VERIFY_PASSWORD;
// We don't check the password
u8 *password;
if ((command & 0xe1) == (int)Command::READ)
password = readPassword;
else
password = writePassword;
DEBUG_LOG(FLASHROM, "Password accepted: %d", memcmp(password, writeBuffer, sizeof(writeBuffer)) == 0);
}
break;
case State::VERIFY_PASSWORD:
DEBUG_LOG(FLASHROM, "-> verify password: %02x", shift);
if (shift == (int)Command::ACK_PASSWORD)
{
if (true) // password accepted
{
if ((command & 0x81) == (int)Command::READ)
state = State::READ_DATA;
else if ((command & 0x81) == (int)Command::WRITE)
state = State::WRITE_DATA;
}
else
sda = true;
}
break;
case State::WRITE_DATA:
DEBUG_LOG(FLASHROM, "-> data: %02x", shift );
writeBuffer[byteOffset++] = shift;
if (byteOffset == sizeof(writeBuffer))
{
if (command == (int)Command::CHANGE_WRITE_PASSWORD)
{
memcpy(writeBuffer, writePassword, sizeof(writePassword));
}
else if (command == (int)Command::CHANGE_READ_PASSWORD)
{
memcpy(writeBuffer, readPassword, sizeof(readPassword));
}
else
{
for (byteOffset = 0; byteOffset < sizeof(writeBuffer); byteOffset++)
{
int offset = dataOffset();
if (offset != -1)
data[offset] = writeBuffer[byteOffset];
else
break;
}
}
byteOffset = 0;
}
break;
default:
break;
}
bit = 0;
shift = 0;
}
}
break;
case State::READ_DATA:
if (!lastSCL && v)
{
if (bit < 8)
{
if (bit == 0)
{
int offset = dataOffset();
if (offset != -1)
shift = data[offset];
else
shift = 0;
}
sda = (shift >> 7) & 1;
shift <<= 1;
bit++;
}
else
{
bit = 0;
sda = false;
if (!lastSDA)
{
DEBUG_LOG(FLASHROM, "ack <-");
byteOffset++;
}
else
{
DEBUG_LOG(FLASHROM, "nak <-");
}
}
}
break;
}
}
SCLChanged = (lastSCL != v);
lastSCL = v;
}
void X76F100SerialFlash::writeSDA(bool v)
{
if (lastSCL && !SCLChanged && !lastCS)
{
if (!lastSDA && v)
{
DEBUG_LOG(FLASHROM, "goto stop");
state = State::STOP;
sda = false;
}
if (lastSDA && !v)
{
switch (state)
{
case State::STOP:
DEBUG_LOG(FLASHROM, "goto start");
state = State::LOAD_COMMAND;
break;
case State::LOAD_PASSWORD:
DEBUG_LOG(FLASHROM, "goto start");
break;
case State::READ_DATA:
DEBUG_LOG(FLASHROM, "reading");
break;
default:
DEBUG_LOG(FLASHROM, "skipped start (default)");
break;
}
bit = 0;
byteOffset = 0;
shift = 0;
sda = false;
}
}
lastSDA = v;
}
void X76F100SerialFlash::reset()
{
lastSCL = false;
SCLChanged = false;
lastSDA = false;
sda = false;
lastRST = false;
lastCS = false;
state = State::STOP;
bit = 0;
byteOffset = 0;
command = 0;
shift = 0;
memset(writeBuffer, 0, sizeof(writeBuffer));
}
int X76F100SerialFlash::dataOffset()
{
int block_offset = (command >> 1) & 0x0f;
int offset = (block_offset * 8) + byteOffset;
// Technically there are 4 bits assigned to sector values but since the data array is only 112 bytes,
// it will try reading out of bounds when the sector is 14 (= starts at 112) or 15 (= starts at 120).
if (offset >= (int)sizeof(data))
return -1;
return offset;
}
void X76F100SerialFlash::serialize(Serializer& ser) const
{
ser << writeBuffer;
ser << lastSCL;
ser << SCLChanged;
ser << lastSDA;
ser << sda;
ser << lastRST;
ser << lastCS;
ser << state;
ser << command;
ser << byteOffset;
ser << bit;
ser << shift;
}
void X76F100SerialFlash::deserialize(Deserializer& deser)
{
deser >> writeBuffer;
deser >> lastSCL;
deser >> SCLChanged;
deser >> lastSDA;
deser >> sda;
deser >> lastRST;
deser >> lastCS;
deser >> state;
deser >> command;
deser >> byteOffset;
deser >> bit;
deser >> shift;
}

107
core/hw/flashrom/x76f100.h Normal file
View File

@ -0,0 +1,107 @@
// Derived from mame src/devices/machine/x76f100.{h,cpp}
// license:BSD-3-Clause
// copyright-holders:smf
/*
* The X76F100 is a Password Access Security Supervisor, containing one 896-bit Secure SerialFlash array.
* Access to the memory array can be controlled by two 64-bit passwords. These passwords protect read and
* write operations of the memory array.
*/
#pragma once
#include "types.h"
#include <string.h>
class X76F100SerialFlash
{
public:
void reset();
// Clock
void writeSCL(bool v);
// Data I/O
void writeSDA(bool v);
bool readSDA() {
return lastCS ? 1 : sda;
}
// Chip select
void writeCS(bool v)
{
if (lastCS && !v)
state = State::STOP;
else if (!lastCS && v) {
state = State::STOP;
sda = false;
}
lastCS = v;
}
// Reset
void writeRST(bool v)
{
if (v && !lastRST && !lastCS)
{
DEBUG_LOG(FLASHROM, "reset");
state = State::RESPONSE_TO_RESET;
bit = 0;
byteOffset = 0;
}
lastRST = v;
}
void setData(const u8 *data)
{
size_t index = 0;
memcpy(responseToReset, &data[index], sizeof(responseToReset));
index += sizeof(responseToReset);
memcpy(writePassword, &data[index], sizeof(writePassword));
index += sizeof(writePassword);
memcpy(readPassword, &data[index], sizeof(readPassword));
index += sizeof(readPassword);
memcpy(this->data, &data[index], sizeof(this->data));
}
void serialize(Serializer& ser) const;
void deserialize(Deserializer& deser);
private:
enum class Command
{
WRITE = 0x80,
READ = 0x81,
CHANGE_WRITE_PASSWORD = 0xfc,
CHANGE_READ_PASSWORD = 0xfe,
ACK_PASSWORD = 0x55
};
enum class State
{
STOP,
RESPONSE_TO_RESET,
LOAD_COMMAND,
LOAD_PASSWORD,
VERIFY_PASSWORD,
READ_DATA,
WRITE_DATA
};
int dataOffset();
u8 data[112] {};
u8 readPassword[8] {};
u8 writePassword[8] {};
u8 responseToReset[4] { 0x19, 0x00, 0xaa, 0x55 };
u8 writeBuffer[8] {};
bool lastSCL = false;
bool lastSDA = false;
bool sda = false;
bool lastRST = false;
bool lastCS = false;
bool SCLChanged = false;
State state = State::STOP;
u8 command = 0;
u8 byteOffset = 0;
u8 bit = 0;
u8 shift = 0;
};

View File

@ -19,21 +19,15 @@
#include "hw/sh4/modules/modules.h"
#include "rend/gui.h"
#include "printer.h"
#include "hw/flashrom/x76f100.h"
#include <algorithm>
static NaomiM3Comm m3comm;
Multiboard *multiboard;
static const u32 BoardID = 0x980055AA;
static u32 GSerialBuffer, BSerialBuffer;
static int GBufPos, BBufPos;
static int GState, BState;
static int GOldClk, BOldClk;
static int BControl, BCmd, BLastCmd;
static int GControl, GCmd, GLastCmd;
static int SerStep, SerStep2;
static X76F100SerialFlash mainSerialId;
static X76F100SerialFlash romSerialId;
/*
El numero de serie solo puede contener:
0-9 (0x30-0x39)
@ -41,294 +35,44 @@ A-H (0x41-0x48)
J-N (0x4A-0x4E)
P-Z (0x50-0x5A)
*/
static u8 BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
//static u8 BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
//static u8 BSerial[]="\x09\xa1 0000000000000000\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; // default from mame
static u8 GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
//static u8 GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
static u8 midiTxBuf[4];
static u32 midiTxBufIndex;
static unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds)
void NaomiBoardIDWrite(const u16 data)
{
const unsigned int Magic=0x10210000;
unsigned int i;
for(i=0;i<rounds;++i)
{
if(CRC&0x80000000)
CRC=(CRC<<1)+Magic;
else
CRC=(CRC<<1);
}
return CRC;
}
static unsigned short CRCSerial(const u8 *Serial,unsigned int len)
{
unsigned int CRC=0xDEBDEB00;
unsigned int i;
for(i=0;i<len;++i)
{
unsigned char c=Serial[i];
//CRC&=0xFFFFFF00;
CRC|=c;
CRC=ShiftCRC(CRC,8);
}
CRC=ShiftCRC(CRC,8);
return (u16)(CRC>>16);
}
void NaomiInit()
{
u16 CRC;
CRC=CRCSerial(BSerial+2,0x2E);
BSerial[0]=(u8)(CRC>>8);
BSerial[1]=(u8)(CRC);
CRC=CRCSerial(GSerial+2,0x2E);
GSerial[0]=(u8)(CRC>>8);
GSerial[1]=(u8)(CRC);
}
void NaomiBoardIDWrite(const u16 Data)
{
int Dat=Data&8;
int Clk=Data&4;
int Rst=Data&0x20;
int Sta=Data&0x10;
if(Rst)
{
BState=0;
BBufPos=0;
}
if(Clk!=BOldClk && !Clk) //Falling Edge clock
{
//State change
if(BState==0 && Sta)
BState=1;
if(BState==1 && !Sta)
BState=2;
if((BControl&0xfff)==0xFF0) //Command mode
{
BCmd<<=1;
if(Dat)
BCmd|=1;
else
BCmd&=0xfffffffe;
}
//State processing
if(BState==1) //LoadBoardID
{
BSerialBuffer=BoardID;
BBufPos=0; //??
}
if(BState==2) //ShiftBoardID
{
BBufPos++;
}
}
BOldClk=Clk;
// bit 2: clock
// bit 3: data
// bit 4: reset (x76f100 only)
// bit 5: chip select
mainSerialId.writeCS(data & 0x20);
mainSerialId.writeRST(data & 0x10);
mainSerialId.writeSCL(data & 4);
mainSerialId.writeSDA(data & 8);
}
u16 NaomiBoardIDRead()
{
if((BControl&0xff)==0xFE)
return 0xffff;
return (BSerialBuffer&(1<<(31-BBufPos)))?8:0;
// bit 0 indicates the eeprom is a X76F100, otherwise the BIOS expects a AT93C46
// bit 3 is xf76f100 SDA
// bit 4 is at93c46 DO
return (mainSerialId.readSDA() << 3) | 1;
}
static u32 AdaptByte(u8 val)
void NaomiGameIDWrite(const u16 data)
{
return val<<24;
}
void NaomiBoardIDWriteControl(const u16 Data)
{
if((Data&0xfff)==0xF30 && BCmd!=BLastCmd)
{
if((BCmd&0x81)==0x81)
{
SerStep2=(BCmd>>1)&0x3f;
BSerialBuffer=0x00000000; //First block contains CRC
BBufPos=0;
}
if((BCmd&0xff)==0x55) //Load Offset 0
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2])>>1;
}
if((BCmd&0xff)==0xAA) //Load Offset 1
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+1]);
}
if((BCmd&0xff)==0x54)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+2]);
}
if((BCmd&0xff)==0xA8)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+3]);
}
if((BCmd&0xff)==0x50)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+4]);
}
if((BCmd&0xff)==0xA0)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+5]);
}
if((BCmd&0xff)==0x40)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+6]);
}
if((BCmd&0xff)==0x80)
{
BState=2;
BBufPos=0;
BSerialBuffer=AdaptByte(BSerial[8*SerStep2+7]);
}
BLastCmd=BCmd;
}
BControl=Data;
}
static void NaomiGameIDProcessCmd()
{
if(GCmd!=GLastCmd)
{
if((GCmd&0x81)==0x81)
{
SerStep=(GCmd>>1)&0x3f;
GSerialBuffer=0x00000000; //First block contains CRC
GBufPos=0;
}
if((GCmd&0xff)==0x55) //Load Offset 0
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep])>>0;
}
if((GCmd&0xff)==0xAA) //Load Offset 1
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+1]);
}
if((GCmd&0xff)==0x54)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+2]);
}
if((GCmd&0xff)==0xA8)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+3]);
}
if((GCmd&0xff)==0x50)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+4]);
}
if((GCmd&0xff)==0xA0)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+5]);
}
if((GCmd&0xff)==0x40)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+6]);
}
if((GCmd&0xff)==0x80)
{
GState=2;
GBufPos=0;
GSerialBuffer=AdaptByte(GSerial[8*SerStep+7]);
}
GLastCmd=GCmd;
}
}
void NaomiGameIDWrite(const u16 Data)
{
int Dat=Data&0x01; // mame: SDA
int Clk=Data&0x02; // mame: SCL
int Rst=Data&0x04; // mame: CS
int Sta=Data&0x08; // mame: RST
int Cmd=Data&0x10; // mame: unused...
if(Rst)
{
GState=0;
GBufPos=0;
}
if(Clk!=GOldClk && !Clk) //Falling Edge clock
{
//State change
if(GState==0 && Sta)
GState=1;
if(GState==1 && !Sta)
GState=2;
//State processing
if(GState==1) //LoadBoardID
{
GSerialBuffer=BoardID;
GBufPos=0; //??
}
if(GState==2) //ShiftBoardID
GBufPos++;
if(GControl!=Cmd && !Cmd)
{
NaomiGameIDProcessCmd();
}
GControl=Cmd;
}
if(Clk!=GOldClk && Clk) //Rising Edge clock
{
if(Cmd) //Command mode
{
GCmd<<=1;
if(Dat)
GCmd|=1;
else
GCmd&=0xfffffffe;
GControl=Cmd;
}
}
GOldClk=Clk;
romSerialId.writeCS(data & 4);
romSerialId.writeRST(data & 8);
romSerialId.writeSCL(data & 2);
romSerialId.writeSDA(data & 1);
}
u16 NaomiGameIDRead()
{
return (GSerialBuffer&(1<<(31-GBufPos)))?1:0;
return romSerialId.readSDA() << 15;
}
static bool aw_ram_test_skipped = false;
@ -421,8 +165,23 @@ static void Naomi_DmaEnable(u32 addr, u32 data)
void naomi_reg_Init()
{
NaomiInit();
networkOutput.init();
static const u8 romSerialData[0x84] = {
0x19, 0x00, 0xaa, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x79, 0x68, 0x6b, 0x74, 0x6d, 0x68, 0x6d,
0xa1, 0x09, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
};
romSerialId.setData(romSerialData);
mainSerialId.setData(romSerialData);
}
void setGameSerialId(const u8 *data)
{
romSerialId.setData(data);
}
void naomi_reg_Term()
@ -442,22 +201,7 @@ void naomi_reg_Reset(bool hard)
SB_GDEN = 0;
aw_ram_test_skipped = false;
GSerialBuffer = 0;
BSerialBuffer = 0;
GBufPos = 0;
BBufPos = 0;
GState = 0;
BState = 0;
GOldClk = 0;
BOldClk = 0;
BControl = 0;
BCmd = 0;
BLastCmd = 0;
GControl = 0;
GCmd = 0;
GLastCmd = 0;
SerStep = 0;
SerStep2 = 0;
m3comm.closeNetwork();
if (hard)
{
@ -470,6 +214,8 @@ void naomi_reg_Reset(bool hard)
if (settings.naomi.multiboard)
multiboard = new Multiboard();
networkOutput.reset();
mainSerialId.reset();
romSerialId.reset();
}
else if (multiboard != nullptr)
multiboard->reset();
@ -587,24 +333,8 @@ static bool ffbCalibrating;
void naomi_Serialize(Serializer& ser)
{
ser << GSerialBuffer;
ser << BSerialBuffer;
ser << GBufPos;
ser << BBufPos;
ser << GState;
ser << BState;
ser << GOldClk;
ser << BOldClk;
ser << BControl;
ser << BCmd;
ser << BLastCmd;
ser << GControl;
ser << GCmd;
ser << GLastCmd;
ser << SerStep;
ser << SerStep2;
ser.serialize(BSerial, 69);
ser.serialize(GSerial, 69);
mainSerialId.serialize(ser);
romSerialId.serialize(ser);
ser << aw_maple_devs;
ser << coin_chute_time;
ser << aw_ram_test_skipped;
@ -615,24 +345,32 @@ void naomi_Serialize(Serializer& ser)
}
void naomi_Deserialize(Deserializer& deser)
{
deser >> GSerialBuffer;
deser >> BSerialBuffer;
deser >> GBufPos;
deser >> BBufPos;
deser >> GState;
deser >> BState;
deser >> GOldClk;
deser >> BOldClk;
deser >> BControl;
deser >> BCmd;
deser >> BLastCmd;
deser >> GControl;
deser >> GCmd;
deser >> GLastCmd;
deser >> SerStep;
deser >> SerStep2;
deser.deserialize(BSerial, 69);
deser.deserialize(GSerial, 69);
if (deser.version() < Deserializer::V40)
{
deser.skip<u32>(); // GSerialBuffer
deser.skip<u32>(); // BSerialBuffer
deser.skip<int>(); // GBufPos
deser.skip<int>(); // BBufPos
deser.skip<int>(); // GState
deser.skip<int>(); // BState
deser.skip<int>(); // GOldClk
deser.skip<int>(); // BOldClk
deser.skip<int>(); // BControl
deser.skip<int>(); // BCmd
deser.skip<int>(); // BLastCmd
deser.skip<int>(); // GControl
deser.skip<int>(); // GCmd
deser.skip<int>(); // GLastCmd
deser.skip<int>(); // SerStep
deser.skip<int>(); // SerStep2
deser.skip(69); // BSerial
deser.skip(69); // GSerial
}
else
{
mainSerialId.deserialize(deser);
romSerialId.deserialize(deser);
}
if (deser.version() < Deserializer::V36)
{
deser.skip<u32>(); // reg_dimm_command;

View File

@ -14,11 +14,11 @@ void naomi_Deserialize(Deserializer& deser);
u32 ReadMem_naomi(u32 Addr, u32 size);
void WriteMem_naomi(u32 Addr, u32 data, u32 size);
void NaomiBoardIDWrite(u16 Data);
void NaomiBoardIDWriteControl(u16 Data);
void NaomiBoardIDWrite(u16 data);
u16 NaomiBoardIDRead();
u16 NaomiGameIDRead();
void NaomiGameIDWrite(u16 Data);
void NaomiGameIDWrite(u16 data);
void setGameSerialId(const u8 *data);
void initMidiForceFeedback();
void initDriveSimSerialPipe();

View File

@ -388,14 +388,27 @@ static void loadMameRom(const std::string& path, const std::string& fileName, Lo
case Eeprom:
{
naomi_default_eeprom = (u8 *)malloc(game->blobs[romid].length);
if (naomi_default_eeprom == nullptr)
throw NaomiCartException("Memory allocation failed");
if (game->blobs[romid].length == 0x84)
{
// on-cart X76F100 security eeprom
u8 data[0x84];
u32 read = file->Read(data, sizeof(data));
if (config::GGPOEnable)
md5.add(data, sizeof(data));
setGameSerialId(data);
DEBUG_LOG(NAOMI, "Loaded %s: %x bytes rom serial eeprom", game->blobs[romid].filename, read);
}
else
{
naomi_default_eeprom = (u8 *)malloc(game->blobs[romid].length);
if (naomi_default_eeprom == nullptr)
throw NaomiCartException("Memory allocation failed");
u32 read = file->Read(naomi_default_eeprom, game->blobs[romid].length);
if (config::GGPOEnable)
md5.add(naomi_default_eeprom, game->blobs[romid].length);
DEBUG_LOG(NAOMI, "Loaded %s: %x bytes default eeprom", game->blobs[romid].filename, read);
u32 read = file->Read(naomi_default_eeprom, game->blobs[romid].length);
if (config::GGPOEnable)
md5.add(naomi_default_eeprom, game->blobs[romid].length);
DEBUG_LOG(NAOMI, "Loaded %s: %x bytes default eeprom", game->blobs[romid].filename, read);
}
}
break;
@ -774,7 +787,8 @@ int naomi_cart_GetPlatform(const char *path)
else
{
#ifdef NAOMI_MULTIBOARD
if (game->multiboard > 0)
if (game->multiboard > 0
&& (!strncmp("f355", game->name, 4) || config::MultiboardSlaves == 2))
settings.naomi.multiboard = true;
#endif
return DC_PLATFORM_NAOMI;
@ -911,7 +925,7 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
return (u16)DmaCount;
case NAOMI_BOARDID_READ_addr:
return NaomiGameIDRead() ? 0x8000 : 0x0000;
return NaomiGameIDRead();
case NAOMI_DMA_OFFSETH_addr:
return DmaOffset >> 16;
@ -919,7 +933,6 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
return DmaOffset & 0xFFFF;
case NAOMI_BOARDID_WRITE_addr:
DEBUG_LOG(NAOMI, "naomi ReadBoardId: %X, %d", address, size);
return 1;
default:
@ -999,9 +1012,7 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
NaomiGameIDWrite((u16)data);
return;
//This should be valid
case NAOMI_BOARDID_READ_addr:
DEBUG_LOG(NAOMI, "naomi WriteMem: %X <= %X, %d", address, data, size);
return;
case NAOMI_LED_addr:

View File

@ -947,14 +947,12 @@ const Game Games[] =
{ "mpr-21738.ic11", 0x5800000, 0x800000 },
// on-cart X76F100 eeprom contents
//ROM_REGION( 0x84, "naomibd_eeprom", 0 )
//ROM_LOAD( "airlinepdx.sf", 0x000000, 0x000084, CRC(404b2add) SHA1(540c8474806775646ace111a2993397b1419fee3) )
{ NULL, 0, 0 },
{ "airlinepdx.sf", 0x000000, 0x000084, 0x404b2add, Eeprom },
},
NULL,
&alpilot_inputs,
alpilot_eeprom_dump
alpilot_eeprom_dump,
2,
},
// Airline Pilots (Japan, Rev A)
{
@ -983,7 +981,8 @@ const Game Games[] =
},
NULL,
&alpilot_inputs,
alpilot_eeprom_dump
alpilot_eeprom_dump,
2,
},
// Alien Front (Rev T)
{
@ -1387,7 +1386,11 @@ const Game Games[] =
{ "mpr-22237.ic15s", 0x7800000, 0x800000 },
{ "mpr-22238.ic16s", 0x8000000, 0x800000 },
{ NULL, 0, 0 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club (JPN, USA, EXP, KOR, AUS) (Rev B)
{
@ -1416,7 +1419,11 @@ const Game Games[] =
{ "mpr-22097.ic13s", 0x6800000, 0x0800000 },
{ "mpr-22098.ic14s", 0x7000000, 0x0800000 },
{ NULL, 0, 0 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club II (JPN, USA, EXP, KOR, AUS) (Rev B)
{
@ -1442,7 +1449,11 @@ const Game Games[] =
{ "mpr-22304.ic10", 0x9800000, 0x1000000 },
{ "mpr-22305.ic11", 0xa800000, 0x1000000 },
{ NULL, 0, 0 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club World Edition (JPN, USA, EXP, KOR, AUS) (Rev D)
{
@ -1465,6 +1476,10 @@ const Game Games[] =
{ "mpr-22338.ic7", 0x6800000, 0x1000000, 0x4bda7303 },
{ NULL, 0, 0, 0x00000000 },
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club World Edition (Rev A)
{
@ -1486,7 +1501,11 @@ const Game Games[] =
{ "mpr-22333.ic6", 0x5800000, 0x1000000, 0x96f324aa },
{ "mpr-22334.ic7", 0x6800000, 0x1000000, 0x5389b05a },
{ NULL, 0, 0, 0x00000000 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club World Edition (Rev B)
{
@ -1508,7 +1527,11 @@ const Game Games[] =
{ "mpr-22333.ic6", 0x5800000, 0x1000000, 0x96f324aa },
{ "mpr-22334.ic7", 0x6800000, 0x1000000, 0x5389b05a },
{ NULL, 0, 0, 0x00000000 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club World Edition (Rev C)
{
@ -1530,7 +1553,11 @@ const Game Games[] =
{ "mpr-22333.ic6", 0x5800000, 0x1000000, 0x96f324aa },
{ "mpr-22334.ic7", 0x6800000, 0x1000000, 0x5389b05a },
{ NULL, 0, 0, 0x00000000 },
}
},
nullptr,
nullptr,
nullptr,
1,
},
// Derby Owners Club World Edition (Rev T)
{
@ -1552,6 +1579,10 @@ const Game Games[] =
{ "mpr-22333.ic6", 0x5800000, 0x1000000, 0x96f324aa },
{ "mpr-22334.ic7", 0x6800000, 0x1000000, 0x5389b05a },
},
nullptr,
nullptr,
nullptr,
1,
},
// Dead or Alive 2 (JPN, USA, EXP, KOR, AUS)
{
@ -3464,6 +3495,8 @@ const Game Games[] =
},
nullptr,
&sstrkfgt_inputs,
nullptr,
2,
},
// Sega Strike Fighter (Rev A, no training mode)
{
@ -3501,6 +3534,8 @@ const Game Games[] =
},
nullptr,
&sstrkfgt_inputs,
nullptr,
2,
},
// Idol Janshi Suchie-Pai 3 (JPN)
{

View File

@ -37,11 +37,6 @@
#include "stdclass.h"
#include <errno.h>
#ifdef DEBUG_EEPROM
#define EEPROM_LOG(...) DEBUG_LOG(FLASHROM, __VA_ARGS__)
#else
#define EEPROM_LOG(...)
#endif
#ifdef DEBUG_SERIAL
#define SERIAL_LOG(...) DEBUG_LOG(NAOMI, __VA_ARGS__)
#else
@ -68,100 +63,6 @@ namespace systemsp
SystemSpCart *SystemSpCart::Instance;
void SerialEeprom93Cxx::writeCLK(int state)
{
// CS asserted and CLK rising
if (clk == 0 && state == 1 && cs == 1)
{
if (dataOutBits > 0)
dataOutBits--;
if (dataOutBits == 0)
{
if (command.empty() && di == 0)
INFO_LOG(NAOMI, "serial eeprom: Ignoring bit 0 (start bit must be 1)");
else
{
command.push_back(di);
if (command.size() == 9)
{
int opCode = (int)command[1] * 2 + (int)command[2];
//EEPROM_LOG("Received command: %d", opCode);
switch (opCode)
{
case 0: // write enable/disable, erase all, write all
{
int subCode = (int)command[3] * 2 + (int)command[4];
switch (subCode)
{
case 0: // disable write
EEPROM_LOG("serial eeprom: EWDS");
writeEnable = false;
command.clear();
break;
case 1: // write all
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
break;
case 2: // erase all
EEPROM_LOG("serial eeprom: ERAL");
if (writeEnable)
memset(data, 0xff, size);
command.clear();
break;
case 3: // enable write
EEPROM_LOG("serial eeprom: EWEN");
writeEnable = true;
command.clear();
break;
}
}
break;
case 1: // write
expected = 3 + 6 + 16; // 6 bits of address, 16 bits of data
break;
case 2: // read
dataOut = Read(getCommandAddress() * 2, 2);
dataOutBits = 17; // actually 16 but 0 means no data
EEPROM_LOG("serial eeprom: READ %x: %x", getCommandAddress(), dataOut);
command.clear();
break;
case 3: // erase
EEPROM_LOG("serial eeprom: ERASE %x", getCommandAddress());
if (writeEnable)
*(u16 *)&data[(getCommandAddress() * 2) & mask] = 0xffff;
command.clear();
break;
}
}
else if (expected > 0 && (int)command.size() == expected)
{
int opCode = (int)command[1] * 2 + (int)command[2];
//EEPROM_LOG("Executing write command: %d", opCode);
switch (opCode)
{
case 0: // write all
{
u16 v = getCommandData();
EEPROM_LOG("serial eeprom: WRAL = %x", v);
if (writeEnable)
for (u32 i = 0; i < size; i += 2)
*(u16 *)&data[i & mask] = v;
}
break;
case 1: // write
EEPROM_LOG("serial eeprom: WRITE %x = %x", getCommandAddress(), getCommandData());
if (writeEnable)
*(u16 *)&data[(getCommandAddress() * 2) & mask] = getCommandData();
break;
}
command.clear();
expected = 0;
}
}
}
}
clk = state;
}
//
// RS232C I/F board (838-14244) connected to RFID Chip R/W board (838-14243)
//
@ -1237,10 +1138,25 @@ void SystemSpCart::updateInterrupt(u32 mask)
asic_CancelInterrupt(holly_EXP_PCI);
}
SystemSpCart::SystemSpCart(u32 size) : M4Cartridge(size), eeprom(128), uart1(this, 1), uart2(this, 2)
SystemSpCart::SystemSpCart(u32 size) : M4Cartridge(size), uart1(this, 1), uart2(this, 2)
{
schedId = sh4_sched_register(0, schedCallback, this);
Instance = this;
// mb_serial.ic57
static const u8 eepromData[0x80] = {
0xf5, 0x90, 0x53, 0x45, 0x47, 0x41, 0x20, 0x45, 0x4e, 0x54, 0x45, 0x52,
0x50, 0x52, 0x49, 0x53, 0x45, 0x53, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x00,
0x4e, 0x41, 0x4f, 0x4d, 0x49, 0x00, 0x00, 0x00, 0x41, 0x41, 0x46, 0x45,
0x30, 0x31, 0x44, 0x31, 0x35, 0x39, 0x32, 0x34, 0x38, 0x31, 0x36, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
eeprom.Load(eepromData, sizeof(eepromData));
}
SystemSpCart::~SystemSpCart()
@ -1507,7 +1423,7 @@ void SystemSpCart::Serialize(Serializer& ser) const
sh4_sched_serialize(ser, schedId);
uart1.serialize(ser);
uart2.serialize(ser);
eeprom.serialize(ser);
eeprom.Serialize(ser);
ser << bank;
ser << ata.features;
ser << ata.cylinder;
@ -1534,7 +1450,7 @@ void SystemSpCart::Deserialize(Deserializer& deser)
sh4_sched_deserialize(deser, schedId);
uart1.deserialize(deser);
uart2.deserialize(deser);
eeprom.deserialize(deser);
eeprom.Deserialize(deser);
deser >> bank;
deser >> ata.features;
deser >> ata.cylinder;

View File

@ -21,7 +21,7 @@
#include "emulator.h"
#include "hw/hwreg.h"
#include "hw/naomi/m4cartridge.h"
#include "hw/flashrom/flashrom.h"
#include "hw/flashrom/at93cxx.h"
#include "serialize.h"
#include <deque>
#include <array>
@ -36,109 +36,6 @@ T readMemArea0(u32 addr);
template<typename T>
void writeMemArea0(u32 addr, T v);
//
// rom board eeprom
//
class SerialEeprom93Cxx : public WritableChip
{
public:
SerialEeprom93Cxx(u32 size) : WritableChip(size) {
memset(data, 0xff, size);
}
// combined DO + READY/BUSY
int readDO()
{
if (dataOutBits > 0)
// DO
return (dataOut >> (dataOutBits - 1)) & 1;
else
// Ready
return 1;
}
// chip select (active high)
void writeCS(int state) {
cs = state;
}
// clock
void writeCLK(int state);
// data in
void writeDI(int state) {
di = state;
}
void Write(u32 addr, u32 data, u32 size) override {
die("Unsupported");
}
void serialize(Serializer& ser) const
{
ser << cs;
ser << clk;
ser << di;
ser << (u32)command.size();
for (bool b : command)
ser << b;
ser << expected;
ser << writeEnable;
ser << dataOut;
ser << dataOutBits;
}
void deserialize(Deserializer& deser)
{
deser >> cs;
deser >> clk;
deser >> di;
u32 size;
deser >> size;
command.resize(size);
for (u32 i = 0; i < size; i++) {
bool b;
deser >> b;
command[i] = b;
}
deser >> expected;
deser >> writeEnable;
deser >> dataOut;
deser >> dataOutBits;
}
private:
u8 getCommandAddress() const
{
verify(command.size() >= 9);
u8 addr = 0;
for (int i = 3; i < 9; i++) {
addr <<= 1;
addr |= command[i];
}
return addr;
}
u16 getCommandData() const
{
verify(command.size() >= 25);
u16 v = 0;
for (int i = 9; i < 25; i++) {
v <<= 1;
v |= command[i];
}
return v;
}
u8 cs = 0;
u8 clk = 0;
u8 di = 0;
std::vector<bool> command;
int expected = 0;
bool writeEnable = false;
u16 dataOut = 0;
u8 dataOutBits = 0;
};
class SystemSpCart;
// rom board custom UART ports
@ -293,7 +190,7 @@ private:
std::unique_ptr<u8[]> hunkmem;
u32 hunknum = ~0;
SerialEeprom93Cxx eeprom;
AT93C46SerialEeprom eeprom;
SerialPort uart1;
SerialPort uart2;
u16 bank = 0;

View File

@ -252,7 +252,6 @@ static glm::mat4x4 curMatrix;
static int taMVMatrix = -1;
static int taNormalMatrix = -1;
static glm::mat4 projectionMatrix;
static int taProjMatrix = -1;
static LightModel *curLightModel;
static ElanBase *curLights[MAX_LIGHTS];
static float nearPlane = 0.001f;
@ -273,7 +272,6 @@ struct State
u32 gmp = Null;
u32 instance = Null;
u32 projMatrix = Null;
u32 lightModel = Null;
u32 lights[MAX_LIGHTS] = {
Null, Null, Null, Null, Null, Null, Null, Null,
@ -282,15 +280,17 @@ struct State
bool lightModelUpdated = false;
float envMapUOffset = 0.f;
float envMapVOffset = 0.f;
float projMatrix[4] = { 579.411194f, -320.f, -579.411194f, -240.f };
int projMatrixIdx = -1;
void reset()
{
gmp = Null;
instance = Null;
projMatrix = Null;
lightModel = Null;
for (auto& light : lights)
light = Null;
projMatrixIdx = -1;
update();
if (isDirectX(config::RendererType))
packColor = packColorBGRA;
@ -347,30 +347,43 @@ struct State
void setProjectionMatrix(void *p)
{
projMatrix = elanRamAddress(p);
ProjMatrix *pm = (ProjMatrix *)&RAM[elanRamAddress(p)];
projMatrix[0] = pm->fx;
projMatrix[1] = pm->tx;
projMatrix[2] = pm->fy;
projMatrix[3] = pm->ty;
DEBUG_LOG(PVR, "Proj matrix x: %f %f y: %f %f near %f far %f", pm->fx, pm->tx, pm->fy, pm->ty, nearPlane, farPlane);
updateProjectionMatrix();
}
void updateProjectionMatrix()
{
if (projMatrix == Null)
{
taProjMatrix = -1;
return;
}
ProjMatrix *pm = (ProjMatrix *)&RAM[projMatrix];
DEBUG_LOG(PVR, "Proj matrix x: %f %f y: %f %f near %f far %f", pm->fx, pm->tx, pm->fy, pm->ty, nearPlane, farPlane);
// fx = -m00 * w/2
// tx = -m20 * w/2 + left + w/2
// fy = -m11 * h/2
// ty = -m21 * h/2 + top + h/2
projectionMatrix = glm::mat4(
-pm->fx, 0, 0, 0,
0, pm->fy, 0, 0,
-pm->tx, -pm->ty, -1, -1,
0, 0, 0, 0
-projMatrix[0], 0, 0, 0,
0, projMatrix[2], 0, 0,
-projMatrix[1], -projMatrix[3], -1, -1,
0, 0, 0, 0
);
taProjMatrix = ta_add_matrix(glm::value_ptr(projectionMatrix));
projMatrixIdx = ta_add_matrix(glm::value_ptr(projectionMatrix));
}
void resetProjectionMatrix()
{
projMatrix[0] = 579.411194f;
projMatrix[1] = -320.f;
projMatrix[2] = -579.411194f;
projMatrix[3] = -240.f;
}
int getProjectionMatrixIndex()
{
if (projMatrixIdx == -1)
updateProjectionMatrix();
return projMatrixIdx;
}
void setGMP(void *p)
@ -470,7 +483,6 @@ struct State
void update()
{
updateMatrix();
updateProjectionMatrix();
updateGMP();
updateLightModel();
for (u32 i = 0; i < MAX_LIGHTS; i++)
@ -498,9 +510,11 @@ struct State
void deserialize(Deserializer& deser)
{
projMatrixIdx = -1;
if (deser.version() < Deserializer::V24)
{
reset();
resetProjectionMatrix();
return;
}
ta_parse_reset();
@ -509,7 +523,14 @@ struct State
ta_set_list_type(listType);
deser >> gmp;
deser >> instance;
deser >> projMatrix;
if (deser.version() < Deserializer::V40)
{
deser.skip<u32>(); // projMatrix address
resetProjectionMatrix();
}
else {
deser >> projMatrix;
}
u32 tileclip;
deser >> tileclip;
ta_set_tileclip(tileclip);
@ -1087,7 +1108,7 @@ static void sendMVPolygon(ICHList *list, const T *vtx, bool needClipping)
mvp.isp.VolumeLast = list->pcw.volume;
mvp.isp.DepthMode &= 3;
mvp.mvMatrix = taMVMatrix;
mvp.projMatrix = taProjMatrix;
mvp.projMatrix = state.getProjectionMatrixIndex();
ta_add_poly(list->pcw.listType, mvp);
ModifierVolumeClipper clipper(needClipping);
@ -1242,7 +1263,7 @@ static void setStateParams(PolyParam& pp, const ICHList *list)
sendLights();
pp.mvMatrix = taMVMatrix;
pp.normalMatrix = taNormalMatrix;
pp.projMatrix = taProjMatrix;
pp.projMatrix = state.getProjectionMatrixIndex();
pp.lightModel = taLightModel;
pp.envMapping[0] = false;
pp.envMapping[1] = false;
@ -1279,7 +1300,7 @@ static void setStateParams(PolyParam& pp, const ICHList *list)
pp.tsp1.full ^= modelTSP.full;
// projFlip is for left-handed projection matrices (initd rear view mirror)
bool projFlip = taProjMatrix != -1 && std::signbit(projectionMatrix[0][0]) == std::signbit(projectionMatrix[1][1]);
bool projFlip = std::signbit(projectionMatrix[0][0]) == std::signbit(projectionMatrix[1][1]);
pp.isp.CullMode ^= (u32)cullingReversed ^ (u32)projFlip;
pp.pcw.Shadow ^= shadowedVolume;
if (pp.pcw.Shadow == 0 || pp.pcw.Volume == 0)
@ -1751,6 +1772,7 @@ void reset(bool hard)
{
memset(RAM, 0, ERAM_SIZE);
state.reset();
state.resetProjectionMatrix();
}
}

View File

@ -1319,24 +1319,13 @@ const float identityMat[] {
0.f, 0.f, 0.f, 1.f
};
const float defaultProjMat[] {
579.411194f, 0.f, 0.f, 0.f,
0.f, -579.411194f, 0.f, 0.f,
-320.f, -240.f, -1.f, -1.f,
0.f, 0.f, 0.f, 0.f
};
constexpr int IdentityMatIndex = 0;
constexpr int DefaultProjMatIndex = 1;
constexpr int NoLightIndex = 0;
static void setDefaultMatrices()
{
if (ta_ctx->rend.matrices.empty())
{
ta_ctx->rend.matrices.push_back(*(N2Matrix *)identityMat);
ta_ctx->rend.matrices.push_back(*(N2Matrix *)defaultProjMat);
}
}
static void setDefaultLight()
@ -1363,8 +1352,6 @@ void ta_add_poly(const PolyParam& pp)
n2CurrentPP->mvMatrix = IdentityMatIndex;
if (n2CurrentPP->normalMatrix == -1)
n2CurrentPP->normalMatrix = IdentityMatIndex;
if (n2CurrentPP->projMatrix == -1)
n2CurrentPP->projMatrix = DefaultProjMatIndex;
setDefaultLight();
if (n2CurrentPP->lightModel == -1)
n2CurrentPP->lightModel = NoLightIndex;
@ -1397,8 +1384,6 @@ void ta_add_poly(int listType, const ModifierVolumeParam& mvp)
setDefaultMatrices();
if (n2CurrentMVP->mvMatrix == -1)
n2CurrentMVP->mvMatrix = IdentityMatIndex;
if (n2CurrentMVP->projMatrix == -1)
n2CurrentMVP->projMatrix = DefaultProjMatIndex;
vd_ctx = nullptr;
}

View File

@ -9,56 +9,46 @@
BSCRegisters bsc;
template<typename T>
static void write_BSC_PCTRA(u32 addr, T data)
//u32 port_out_data;
static void write_BSC_PDTRA_arcade(u32 addr, u16 data)
{
BSC_PCTRA.full = data;
if (settings.platform.isNaomi())
NaomiBoardIDWriteControl((u16)data);
//else
//printf("C:BSC_PCTRA = %08X\n",data);
BSC_PDTRA.full = data;
NaomiBoardIDWrite(data);
}
//u32 port_out_data;
static void write_BSC_PDTRA(u32 addr, u16 data)
{
BSC_PDTRA.full = data;
//printf("D:BSC_PDTRA = %04x\n", data);
}
if (settings.platform.isNaomi())
NaomiBoardIDWrite(data);
static u16 read_BSC_PDTRA_arcade(u32 addr)
{
return NaomiBoardIDRead();
}
static u16 read_BSC_PDTRA(u32 addr)
{
if (settings.platform.isNaomi())
{
return NaomiBoardIDRead();
}
/* as seen on chankast */
u32 tpctra = BSC_PCTRA.full;
u32 tpdtra = BSC_PDTRA.full;
u16 tfinal = 0;
// magic values
if ((tpctra & 0xf) == 0x8)
tfinal = 3;
else if ((tpctra & 0xf) == 0xB)
tfinal = 3;
else
{
/* as seen on chankast */
u32 tpctra = BSC_PCTRA.full;
u32 tpdtra = BSC_PDTRA.full;
tfinal = 0;
u16 tfinal = 0;
// magic values
if ((tpctra & 0xf) == 0x8)
tfinal = 3;
else if ((tpctra & 0xf) == 0xB)
tfinal = 3;
else
tfinal = 0;
if ((tpctra & 0xf) == 0xB && (tpdtra & 0xf) == 2)
tfinal = 0;
else if ((tpctra & 0xf) == 0xC && (tpdtra & 0xf) == 2)
tfinal = 3;
if ((tpctra & 0xf) == 0xB && (tpdtra & 0xf) == 2)
tfinal = 0;
else if ((tpctra & 0xf) == 0xC && (tpdtra & 0xf) == 2)
tfinal = 3;
tfinal |= config::Cable << 8;
tfinal |= config::Cable << 8;
return tfinal;
}
return tfinal;
}
void BSCRegisters::init()
@ -101,10 +91,10 @@ void BSCRegisters::init()
//BSC PCTRA 0xFF80002C 0x1F80002C 32 0x00000000 Held Held Held Bclk
// Naomi BIOS writes u16 in this register but ignoring them doesn't seem to hurt
setWriteHandler<BSC_PCTRA_addr>(write_BSC_PCTRA<u32>);
setRW<BSC_PCTRA_addr, u32>();
//BSC PDTRA 0xFF800030 0x1F800030 16 Undefined Held Held Held Bclk
setHandlers<BSC_PDTRA_addr>(read_BSC_PDTRA, write_BSC_PDTRA);
setRW<BSC_PDTRA_addr, u16>();
//BSC PCTRB 0xFF800040 0x1F800040 32 0x00000000 Held Held Held Bclk
setRW<BSC_PCTRB_addr, u32, 0x000000ff>();
@ -149,4 +139,9 @@ void BSCRegisters::reset()
BSC_WCR3.full = 0x07777777;
BSC_RFCR.full = 17;
if (settings.platform.isNaomi() || settings.platform.isSystemSP())
setHandlers<BSC_PDTRA_addr>(read_BSC_PDTRA_arcade, write_BSC_PDTRA_arcade);
else
setHandlers<BSC_PDTRA_addr>(read_BSC_PDTRA, write_BSC_PDTRA);
}

View File

@ -33,7 +33,7 @@ static void updateInterrupts()
// SCIF SCFTDR2
void SCIFSerialPort::writeData(u32 addr, u8 data)
{
INFO_LOG(COMMON, "serial out %02x %c", data, data);
//DEBUG_LOG(COMMON, "serial out %02x %c", data, data);
if (Instance().pipe != nullptr)
Instance().pipe->write(data);

View File

@ -65,7 +65,8 @@ public:
V37,
V38,
V39,
Current = V39,
V40,
Current = V40,
Next = Current + 1,
};