mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 05:45:38 +00:00
- New work-in-progress frame timing code (disabled by default, compile with NEW_FRAME_TIMING defined to activate it)
- New JTAG emulation, moved into its own class, CJTAG - Removed game-specific sun clamp hacks from CNew3D (JTAG and Real3D emulation will call the appropriate method to configure this at run-time) - Removed JTAG from Real3D save state data and reused some of that space for new state variables having to do with the internal JTAG-based config as well as new frame timing state variables
This commit is contained in:
parent
c4f8471d7a
commit
55bb02d4e5
|
@ -90,7 +90,7 @@ endif
|
||||||
HEADERS = Src/Supermodel.h Src/Games.h Src/OSD/SDL/Types.h
|
HEADERS = Src/Supermodel.h Src/Games.h Src/OSD/SDL/Types.h
|
||||||
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
||||||
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
$(OBJ_DIR)/JTAG.o $(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
||||||
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
|
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
|
||||||
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
||||||
$(OBJ_DIR)/Model3.o $(OBJ_DIR)/ppc.o $(OBJ_DIR)/Main.o $(OBJ_DIR)/Audio.o $(OBJ_DIR)/Thread.o $(OBJ_DIR)/SoundBoard.o \
|
$(OBJ_DIR)/Model3.o $(OBJ_DIR)/ppc.o $(OBJ_DIR)/Main.o $(OBJ_DIR)/Audio.o $(OBJ_DIR)/Thread.o $(OBJ_DIR)/SoundBoard.o \
|
||||||
|
@ -106,6 +106,13 @@ OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/Crypto.o \
|
$(OBJ_DIR)/Crypto.o \
|
||||||
$(OBJ_DIR)/Format.o \
|
$(OBJ_DIR)/Format.o \
|
||||||
$(OBJ_DIR)/Logger.o \
|
$(OBJ_DIR)/Logger.o \
|
||||||
|
$(OBJ_DIR)/NewConfig.o \
|
||||||
|
$(OBJ_DIR)/ByteSwap.o \
|
||||||
|
$(OBJ_DIR)/ConfigBuilders.o \
|
||||||
|
$(OBJ_DIR)/GameLoader.o \
|
||||||
|
$(OBJ_DIR)/tinyxml2.o \
|
||||||
|
$(OBJ_DIR)/ROMSet.o \
|
||||||
|
$(OBJ_DIR)/BitRegister.o \
|
||||||
$(OBJ_DIR)/SDLMain_tmpl.o
|
$(OBJ_DIR)/SDLMain_tmpl.o
|
||||||
|
|
||||||
# If built-in debugger enabled, include all debugging classes
|
# If built-in debugger enabled, include all debugging classes
|
||||||
|
|
|
@ -97,7 +97,7 @@ endif
|
||||||
HEADERS = Src/Supermodel.h Src/OSD/SDL/Types.h
|
HEADERS = Src/Supermodel.h Src/OSD/SDL/Types.h
|
||||||
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
||||||
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
$(OBJ_DIR)/JTAG.o $(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
||||||
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o $(OBJ_DIR)/R3DScrollFog.o \
|
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o $(OBJ_DIR)/R3DScrollFog.o \
|
||||||
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
||||||
$(OBJ_DIR)/Model3.o $(OBJ_DIR)/ppc.o $(OBJ_DIR)/Main.o $(OBJ_DIR)/Audio.o $(OBJ_DIR)/Thread.o $(OBJ_DIR)/SoundBoard.o \
|
$(OBJ_DIR)/Model3.o $(OBJ_DIR)/ppc.o $(OBJ_DIR)/Main.o $(OBJ_DIR)/Audio.o $(OBJ_DIR)/Thread.o $(OBJ_DIR)/SoundBoard.o \
|
||||||
|
@ -118,7 +118,8 @@ OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/ConfigBuilders.o \
|
$(OBJ_DIR)/ConfigBuilders.o \
|
||||||
$(OBJ_DIR)/GameLoader.o \
|
$(OBJ_DIR)/GameLoader.o \
|
||||||
$(OBJ_DIR)/tinyxml2.o \
|
$(OBJ_DIR)/tinyxml2.o \
|
||||||
$(OBJ_DIR)/ROMSet.o
|
$(OBJ_DIR)/ROMSet.o \
|
||||||
|
$(OBJ_DIR)/BitRegister.o
|
||||||
|
|
||||||
# If built-in debugger enabled, include all debugging classes
|
# If built-in debugger enabled, include all debugging classes
|
||||||
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
|
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
|
||||||
|
|
|
@ -121,7 +121,7 @@ endif
|
||||||
#
|
#
|
||||||
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
|
||||||
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
$(OBJ_DIR)/JTAG.o $(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
|
||||||
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
|
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
|
||||||
$(OBJ_DIR)/R3DScrollFog.o \
|
$(OBJ_DIR)/R3DScrollFog.o \
|
||||||
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \
|
||||||
|
@ -138,7 +138,7 @@ OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
|
||||||
$(OBJ_DIR)/Crypto.o \
|
$(OBJ_DIR)/Crypto.o \
|
||||||
$(OBJ_DIR)/Logger.o \
|
$(OBJ_DIR)/Logger.o \
|
||||||
$(OBJ_DIR)/tinyxml2.o \
|
$(OBJ_DIR)/tinyxml2.o \
|
||||||
$(OBJ_DIR)/ByteSwap.o $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/ConfigBuilders.o $(OBJ_DIR)/GameLoader.o $(OBJ_DIR)/ROMSet.o
|
$(OBJ_DIR)/ByteSwap.o $(OBJ_DIR)/Format.o $(OBJ_DIR)/NewConfig.o $(OBJ_DIR)/ConfigBuilders.o $(OBJ_DIR)/GameLoader.o $(OBJ_DIR)/ROMSet.o $(OBJ_DIR)/BitRegister.o
|
||||||
|
|
||||||
|
|
||||||
# If built-in debugger enabled, include all debugging classes
|
# If built-in debugger enabled, include all debugging classes
|
||||||
|
|
|
@ -786,18 +786,6 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity
|
vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity
|
||||||
vp->lightingParams[5] = 0.0; // reserved
|
vp->lightingParams[5] = 0.0; // reserved
|
||||||
|
|
||||||
// this is a hack because we haven't yet found in memory where these are set
|
|
||||||
if (m_gameName == "dayto2pe"||
|
|
||||||
m_gameName == "lamachin"||
|
|
||||||
m_gameName == "von2" ||
|
|
||||||
m_gameName == "von254g" ||
|
|
||||||
m_gameName == "von2a") {
|
|
||||||
m_sunClamp = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_sunClamp = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vp->sunClamp = m_sunClamp;
|
vp->sunClamp = m_sunClamp;
|
||||||
vp->intensityClamp = (m_step == 0x10); // just step 1.0 ?
|
vp->intensityClamp = (m_step == 0x10); // just step 1.0 ?
|
||||||
vp->hardwareStep = m_step;
|
vp->hardwareStep = m_step;
|
||||||
|
|
216
Src/Model3/JTAG.cpp
Normal file
216
Src/Model3/JTAG.cpp
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
/**
|
||||||
|
** Supermodel
|
||||||
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
** Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis
|
||||||
|
**
|
||||||
|
** 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/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JTAG.cpp
|
||||||
|
*
|
||||||
|
* Model 3's JTAG test access port (TAP). This is accessed through the system
|
||||||
|
* register space and is connected to the Real3D chipset and possibly other
|
||||||
|
* devices. Hence, it is emulated as an independent module.
|
||||||
|
*
|
||||||
|
* It is unclear which exact JTAG standard the device conforms to (and it
|
||||||
|
* probably doesn't matter), so we assume IEEE 1149.1-1990 here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Supermodel.h"
|
||||||
|
#include "Model3/JTAG.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// Finite state machine. Each state has two possible next states.
|
||||||
|
const CJTAG::State CJTAG::s_fsm[][2] =
|
||||||
|
{
|
||||||
|
// tms = 0 tms = 1
|
||||||
|
{ RunTestIdle, TestLogicReset }, // 0 Test-Logic/Reset
|
||||||
|
{ RunTestIdle, SelectDRScan }, // 1 Run-Test/Idle
|
||||||
|
{ CaptureDR, SelectIRScan }, // 2 Select-DR-Scan
|
||||||
|
{ ShiftDR, Exit1DR }, // 3 Capture-DR
|
||||||
|
{ ShiftDR, Exit1DR }, // 4 Shift-DR
|
||||||
|
{ PauseDR, UpdateDR }, // 5 Exit1-DR
|
||||||
|
{ PauseDR, Exit2DR }, // 6 Pause-DR
|
||||||
|
{ ShiftDR, UpdateDR }, // 7 Exit2-DR
|
||||||
|
{ RunTestIdle, SelectDRScan }, // 8 Update-DR
|
||||||
|
{ CaptureIR, TestLogicReset }, // 9 Select-IR-Scan
|
||||||
|
{ ShiftIR, Exit1IR }, // 10 Capture-IR
|
||||||
|
{ ShiftIR, Exit1IR }, // 11 Shift-IR
|
||||||
|
{ PauseIR, UpdateIR }, // 12 Exit1-IR
|
||||||
|
{ PauseIR, Exit2IR }, // 13 Pause-IR
|
||||||
|
{ ShiftIR, UpdateIR }, // 14 Exit2-IR
|
||||||
|
{ RunTestIdle, SelectDRScan } // 15 Update-IR
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *s_state[] =
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SaveBitRegister(CBlockFile *SaveState, const Util::BitRegister ®)
|
||||||
|
{
|
||||||
|
uint16_t size = reg.Size() + 1; // include null terminator
|
||||||
|
SaveState->Write(&size, sizeof(size));
|
||||||
|
SaveState->Write(reg.ToBinaryString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadBitRegister(CBlockFile *SaveState, Util::BitRegister *reg)
|
||||||
|
{
|
||||||
|
uint16_t size;
|
||||||
|
SaveState->Read(&size, sizeof(size));
|
||||||
|
char *str = new char[size];
|
||||||
|
SaveState->Read(str, size);
|
||||||
|
reg->Set(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CJTAG::SaveState(CBlockFile *SaveState)
|
||||||
|
{
|
||||||
|
SaveState->NewBlock("JTAG", __FILE__);
|
||||||
|
SaveBitRegister(SaveState, m_instructionShiftReg);
|
||||||
|
SaveBitRegister(SaveState, m_dataShiftReg);
|
||||||
|
SaveState->Write(&m_instructionReg, sizeof(m_instructionReg));
|
||||||
|
SaveState->Write(&m_state, sizeof(m_state));
|
||||||
|
SaveState->Write(&m_lastTck, sizeof(m_lastTck));
|
||||||
|
SaveState->Write(&m_tdo, sizeof(m_tdo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CJTAG::LoadState(CBlockFile *SaveState)
|
||||||
|
{
|
||||||
|
if (OKAY != SaveState->FindBlock("JTAG"))
|
||||||
|
{
|
||||||
|
ErrorLog("Unable to load JTAG state. Save state file is corrupt.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoadBitRegister(SaveState, &m_instructionShiftReg);
|
||||||
|
LoadBitRegister(SaveState, &m_dataShiftReg);
|
||||||
|
SaveState->Read(&m_instructionReg, sizeof(m_instructionReg));
|
||||||
|
SaveState->Read(&m_state, sizeof(m_state));
|
||||||
|
SaveState->Read(&m_lastTck, sizeof(m_lastTck));
|
||||||
|
SaveState->Read(&m_tdo, sizeof(m_tdo));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CJTAG::Read()
|
||||||
|
{
|
||||||
|
return m_tdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CJTAG::LoadASICIDCodes()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ID code retrieval has not been carefully studied but based on observation,
|
||||||
|
* it appears that the ID codes are loaded on logic reset (Step 2.x games and
|
||||||
|
* some 1.x games rely on this) as well as instruction 0x06318fc63fff. Some
|
||||||
|
* games rely on both (e.g., von2).
|
||||||
|
*/
|
||||||
|
m_dataShiftReg.SetZeros();
|
||||||
|
m_dataShiftReg.Insert(2 + 0*32 + 0, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Jupiter)));
|
||||||
|
m_dataShiftReg.Insert(2 + 1*32 + 0, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Mercury)));
|
||||||
|
m_dataShiftReg.Insert(2 + 2*32 + 0, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Venus)));
|
||||||
|
m_dataShiftReg.Insert(2 + 3*32 + 0, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Earth)));
|
||||||
|
m_dataShiftReg.Insert(2 + 4*32 + 1, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Mars)));
|
||||||
|
m_dataShiftReg.Insert(2 + 5*32 + 1, Util::Hex(m_real3D.GetASICIDCode(CReal3D::ASIC::Mars)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CJTAG::Write(uint8_t tck, uint8_t tms, uint8_t tdi, uint8_t trst)
|
||||||
|
{
|
||||||
|
tck = !!tck;
|
||||||
|
tms = !!tms;
|
||||||
|
tdi = !!tdi;
|
||||||
|
trst = !!trst;
|
||||||
|
|
||||||
|
//TODO: is trst used anywhere? If so, need to emulate.
|
||||||
|
//if (!trst)
|
||||||
|
// printf("TRST=0\n");
|
||||||
|
//printf("%d trst=%d tms=%d tdi=%d\n", tck, trst, tms, tdi);
|
||||||
|
|
||||||
|
// Transitions occur on rising edge
|
||||||
|
uint8_t lastTck = m_lastTck;
|
||||||
|
m_lastTck = tck;
|
||||||
|
if (!tck || lastTck != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Current state logic
|
||||||
|
switch (m_state)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case State::TestLogicReset:
|
||||||
|
LoadASICIDCodes();
|
||||||
|
break;
|
||||||
|
case State::CaptureDR:
|
||||||
|
if (m_instructionReg == Instruction::ReadASICIDCodes)
|
||||||
|
LoadASICIDCodes();
|
||||||
|
break;
|
||||||
|
case State::ShiftDR:
|
||||||
|
m_tdo = m_dataShiftReg.ShiftOutRight(tdi);
|
||||||
|
break;
|
||||||
|
case State::UpdateDR:
|
||||||
|
if (m_instructionReg == Instruction::SetReal3DRenderConfig0 || m_instructionReg == Instruction::SetReal3DRenderConfig1)
|
||||||
|
{
|
||||||
|
uint64_t data = m_dataShiftReg.GetBits(0, 42);
|
||||||
|
m_real3D.WriteJTAGRegister(m_instructionReg, data);
|
||||||
|
}
|
||||||
|
//std::cout << "DR = " << m_dataShiftReg << std::endl;
|
||||||
|
break;
|
||||||
|
case State::CaptureIR:
|
||||||
|
// Load lower 2 bits with 01 as per IEEE 1149.1-1990
|
||||||
|
m_instructionShiftReg.Insert(44, "01");
|
||||||
|
break;
|
||||||
|
case State::ShiftIR:
|
||||||
|
m_tdo = m_instructionShiftReg.ShiftOutRight(tdi);
|
||||||
|
break;
|
||||||
|
case State::UpdateIR:
|
||||||
|
// Latch the instruction register (technically, this should occur on
|
||||||
|
// falling edge of clock as per the spec)
|
||||||
|
m_instructionReg = m_instructionShiftReg.GetBits();
|
||||||
|
//std::cout << "IR = " << Util::Hex(m_instructionReg, 12) << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to next state
|
||||||
|
m_state = s_fsm[m_state][tms];
|
||||||
|
//printf(" -> %s\n", s_state[m_state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CJTAG::Reset()
|
||||||
|
{
|
||||||
|
m_state = State::TestLogicReset;
|
||||||
|
DebugLog("JTAG reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CJTAG::CJTAG(CReal3D &real3D)
|
||||||
|
: m_real3D(real3D),
|
||||||
|
m_instructionShiftReg(46, 0),
|
||||||
|
m_dataShiftReg(197, 0)
|
||||||
|
{
|
||||||
|
DebugLog("Built JTAG logic\n");
|
||||||
|
}
|
86
Src/Model3/JTAG.h
Normal file
86
Src/Model3/JTAG.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
** Supermodel
|
||||||
|
** A Sega Model 3 Arcade Emulator.
|
||||||
|
** Copyright 2011-2017 Bart Trzynadlowski, Nik Henson, Ian Curtis
|
||||||
|
**
|
||||||
|
** 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/>.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JTAG.h
|
||||||
|
*
|
||||||
|
* Header file defining the CJTAG class: the Model 3's JTAG device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_JTAG_H
|
||||||
|
#define INCLUDED_JTAG_H
|
||||||
|
|
||||||
|
#include "Util/BitRegister.h"
|
||||||
|
|
||||||
|
class CReal3D;
|
||||||
|
|
||||||
|
class CJTAG
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Instruction: uint64_t
|
||||||
|
{
|
||||||
|
ReadASICIDCodes = 0x06318fc63fff,
|
||||||
|
SetReal3DRenderConfig0 = 0x3fffffd1ffff,
|
||||||
|
SetReal3DRenderConfig1 = 0x3ffffffe8fff
|
||||||
|
};
|
||||||
|
|
||||||
|
void SaveState(CBlockFile *SaveState);
|
||||||
|
void LoadState(CBlockFile *SaveState);
|
||||||
|
uint8_t Read();
|
||||||
|
void Write(uint8_t tck, uint8_t tms, uint8_t tdi, uint8_t trst);
|
||||||
|
void Reset();
|
||||||
|
CJTAG(CReal3D &real3D);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LoadASICIDCodes();
|
||||||
|
|
||||||
|
enum State: uint8_t
|
||||||
|
{
|
||||||
|
TestLogicReset, // 0
|
||||||
|
RunTestIdle, // 1
|
||||||
|
SelectDRScan, // 2
|
||||||
|
CaptureDR, // 3
|
||||||
|
ShiftDR, // 4
|
||||||
|
Exit1DR, // 5
|
||||||
|
PauseDR, // 6
|
||||||
|
Exit2DR, // 7
|
||||||
|
UpdateDR, // 8
|
||||||
|
SelectIRScan, // 9
|
||||||
|
CaptureIR, // 10
|
||||||
|
ShiftIR, // 11
|
||||||
|
Exit1IR, // 12
|
||||||
|
PauseIR, // 13
|
||||||
|
Exit2IR, // 14
|
||||||
|
UpdateIR // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
static const State s_fsm[][2];
|
||||||
|
|
||||||
|
CReal3D &m_real3D;
|
||||||
|
Util::BitRegister m_instructionShiftReg;
|
||||||
|
Util::BitRegister m_dataShiftReg;
|
||||||
|
uint64_t m_instructionReg = 0;
|
||||||
|
State m_state = State::TestLogicReset;
|
||||||
|
uint8_t m_lastTck = 0;
|
||||||
|
uint8_t m_tdo = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDED_JTAG_H
|
|
@ -814,7 +814,7 @@ UINT8 CModel3::ReadSystemRegister(unsigned reg)
|
||||||
//DebugLog("System register %02X read\n", reg);
|
//DebugLog("System register %02X read\n", reg);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
case 0x10: // JTAG Test Access Port
|
case 0x10: // JTAG Test Access Port
|
||||||
return (GPU.ReadTAP()<< 5);
|
return m_jtag.Read() << 5;
|
||||||
default:
|
default:
|
||||||
//DebugLog("System register %02X read\n", reg);
|
//DebugLog("System register %02X read\n", reg);
|
||||||
break;
|
break;
|
||||||
|
@ -839,8 +839,14 @@ void CModel3::WriteSystemRegister(unsigned reg, UINT8 data)
|
||||||
DebugLog("IRQ ACK? %02X=%02X\n", reg, data);
|
DebugLog("IRQ ACK? %02X=%02X\n", reg, data);
|
||||||
break;
|
break;
|
||||||
case 0x0C: // JTAG Test Access Port
|
case 0x0C: // JTAG Test Access Port
|
||||||
GPU.WriteTAP((data>>6)&1,(data>>2)&1,(data>>5)&1,(data>>7)&1); // TCK, TMS, TDI, TRST
|
{
|
||||||
|
uint8_t tck = (data >> 6) & 1;
|
||||||
|
uint8_t tms = (data >> 2) & 1;
|
||||||
|
uint8_t tdi = (data >> 5) & 1;
|
||||||
|
uint8_t trst = (data >> 7) & 1; // not sure about this one (trst not required to exist by JTAG spec)
|
||||||
|
m_jtag.Write(tck, tms, tdi, trst);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 0x0D:
|
case 0x0D:
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
|
@ -1609,6 +1615,7 @@ void CModel3::SaveState(CBlockFile *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);
|
m_cryptoDevice.SaveState(SaveState);
|
||||||
|
m_jtag.SaveState(SaveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModel3::LoadState(CBlockFile *SaveState)
|
void CModel3::LoadState(CBlockFile *SaveState)
|
||||||
|
@ -1647,6 +1654,7 @@ void CModel3::LoadState(CBlockFile *SaveState)
|
||||||
SoundBoard.LoadState(SaveState);
|
SoundBoard.LoadState(SaveState);
|
||||||
DriveBoard.LoadState(SaveState);
|
DriveBoard.LoadState(SaveState);
|
||||||
m_cryptoDevice.LoadState(SaveState);
|
m_cryptoDevice.LoadState(SaveState);
|
||||||
|
m_jtag.LoadState(SaveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModel3::SaveNVRAM(CBlockFile *NVRAM)
|
void CModel3::SaveNVRAM(CBlockFile *NVRAM)
|
||||||
|
@ -1750,6 +1758,136 @@ ThreadError:
|
||||||
m_multiThreaded = false;
|
m_multiThreaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NEW_FRAME_TIMING
|
||||||
|
void CModel3::RunMainBoardFrame(void)
|
||||||
|
{
|
||||||
|
if (!gpusReady)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UINT32 start = CThread::GetTicks();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Display timing is assumed to be driven by the System 24 tile generator
|
||||||
|
* chip. Charles MacDonald's notes state:
|
||||||
|
*
|
||||||
|
* 656 pixels per scanline:
|
||||||
|
*
|
||||||
|
* 69 pixels from /HSYNC high to /BLANK high (left border)
|
||||||
|
* 496 pixels from /BLANK high to /BLANK low (active display)
|
||||||
|
* 43 pixels from /BLANK low to /HSYNC low (right border)
|
||||||
|
* 48 pixels from /HSYNC low to /HSYNC high (horizontal sync. pulse)
|
||||||
|
*
|
||||||
|
* 424 scanlines per frame:
|
||||||
|
*
|
||||||
|
* 25 scanlines from /VSYNC high to /BLANK high (top border)
|
||||||
|
* 384 scanlines from /BLANK high to /BLANK low (active display)
|
||||||
|
* 11 scanlines from /BLANK low to /VSYNC low (bottom border)
|
||||||
|
* 4 scanlines from /VSYNC low to /VSYNC high (vertical sync. pulse)
|
||||||
|
*
|
||||||
|
* The pixel clock is 16 MHz, giving an effetive frame rate of 57.52
|
||||||
|
* frames per second.
|
||||||
|
*/
|
||||||
|
float ppcCycles = m_config["PowerPCFrequency"].ValueAs<unsigned>() * 1e6;
|
||||||
|
float frameRate = 60; // actually, 57.52 Hz
|
||||||
|
float frameCycles = ppcCycles / frameRate;
|
||||||
|
float lineCycles = frameCycles / 424; // 424 scanlines per tile generator frame
|
||||||
|
unsigned topBorderLines = 25;
|
||||||
|
unsigned activeLines = 384;
|
||||||
|
unsigned bottomBorderLines = 11;
|
||||||
|
unsigned vblLines = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scale PPC timer ratio according to speed at which the PowerPC is being
|
||||||
|
* emulated so that the observed running frequency of the PPC timer registers
|
||||||
|
* is more or less correct. This is needed to get the Virtua Striker 2
|
||||||
|
* series of games running at the right speed (they are too slow otherwise).
|
||||||
|
* Other games appear to not be affected by this ratio so much as their
|
||||||
|
* running speed depends more on the timing of the Real3D status bit below.
|
||||||
|
*/
|
||||||
|
ppc_set_timer_ratio(ppc_get_bus_freq_multipler() * 2 * ppcCycles / ppc_get_cycles_per_sec());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Active frame + bottom border. We treat this as one large chunk save for
|
||||||
|
* the sound IRQs, which we attempt to process first.
|
||||||
|
*
|
||||||
|
* Sound:
|
||||||
|
*
|
||||||
|
* Bit 0x20 of the MIDI control port appears to enable periodic interrupts,
|
||||||
|
* which are used to send MIDI commands. Often games will write 0x27, send
|
||||||
|
* a series of commands, and write 0x06 to stop. Other games, like Star
|
||||||
|
* Wars Trilogy and Sega Rally 2, will enable interrupts at the beginning
|
||||||
|
* by writing 0x37 and will disable/enable interrupts to control command
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned remainingCycles = unsigned(activeLines * lineCycles);
|
||||||
|
unsigned irqCount = 0;
|
||||||
|
while ((midiCtrlPort & 0x20)) // 0x27 triggers IRQ sequence, 0x06 stops it
|
||||||
|
{
|
||||||
|
// Don't waste time firing MIDI interrupts if game has disabled them
|
||||||
|
if ((IRQ.ReadIRQEnable()&0x40) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Process MIDI interrupt
|
||||||
|
IRQ.Assert(0x40);
|
||||||
|
ppc_execute(200); // give PowerPC time to acknowledge IRQ
|
||||||
|
IRQ.Deassert(0x40);
|
||||||
|
ppc_execute(200); // acknowledge that IRQ was deasserted (TODO: is this really needed?)
|
||||||
|
remainingCycles -= 400;
|
||||||
|
|
||||||
|
++irqCount;
|
||||||
|
if (irqCount > 128)
|
||||||
|
{
|
||||||
|
//printf("\tMIDI FIFO OVERFLOW! (IRQEn=%02X, IRQPend=%02X)\n", IRQ.ReadIRQEnable()&0x40, IRQ.ReadIRQState());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ppc_execute(remainingCycles/2);
|
||||||
|
GPU.BeginVBlank(0); // TODO: if this actually occurs before VBL, need to rename this function
|
||||||
|
ppc_execute(remainingCycles/2);
|
||||||
|
ppc_execute(bottomBorderLines * lineCycles);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VBlank period
|
||||||
|
*/
|
||||||
|
TileGen.BeginVBlank();
|
||||||
|
//GPU.BeginVBlank(0); //TODO: remove this parameter
|
||||||
|
IRQ.Assert(0x02);
|
||||||
|
ppc_execute(vblLines * lineCycles);
|
||||||
|
IRQ.Deassert(0x02); // unnecessary because manually cleared, also probably self-clears within 1 line
|
||||||
|
GPU.EndVBlank();
|
||||||
|
TileGen.EndVBlank();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Top border/end of previous frame's VBlank: assuming here (without
|
||||||
|
* sufficient evidence) that IRQ 1 is end-of-VBL. It's certainly triggered
|
||||||
|
* once per frame, like IRQ 2, according to code I ran on a real board.
|
||||||
|
*
|
||||||
|
* We execute a number of miscellaneous, unknown IRQs on the last line of the
|
||||||
|
* top border, again without any proper justification other than to space
|
||||||
|
* them apart from known IRQs. Games will be doing most of their processing
|
||||||
|
* post-VBL (during the border and active display phases), so it seems like a
|
||||||
|
* good time to raise IRQs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// One line for IRQ 1, assuming this is some VBL-related signal
|
||||||
|
IRQ.Assert(0x01);
|
||||||
|
ppc_execute(1 * lineCycles);
|
||||||
|
IRQ.Deassert(0x01);
|
||||||
|
|
||||||
|
// The bulk of the border lines
|
||||||
|
ppc_execute ((topBorderLines - 2) * lineCycles);
|
||||||
|
|
||||||
|
// Reserve one line for miscellaneous IRQs
|
||||||
|
IRQ.Assert(0x0C);
|
||||||
|
ppc_execute(1 * lineCycles);
|
||||||
|
IRQ.Deassert(0x0C);
|
||||||
|
|
||||||
|
timings.ppcTicks = CThread::GetTicks() - start;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NEW_FRAME_TIMING
|
||||||
void CModel3::RunMainBoardFrame(void)
|
void CModel3::RunMainBoardFrame(void)
|
||||||
{
|
{
|
||||||
UINT32 start = CThread::GetTicks();
|
UINT32 start = CThread::GetTicks();
|
||||||
|
@ -1847,6 +1985,7 @@ void CModel3::RunMainBoardFrame(void)
|
||||||
|
|
||||||
timings.ppcTicks = CThread::GetTicks() - start;
|
timings.ppcTicks = CThread::GetTicks() - start;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CModel3::SyncGPUs(void)
|
void CModel3::SyncGPUs(void)
|
||||||
{
|
{
|
||||||
|
@ -2518,6 +2657,7 @@ void CModel3::Reset(void)
|
||||||
TileGen.Reset();
|
TileGen.Reset();
|
||||||
GPU.Reset();
|
GPU.Reset();
|
||||||
SoundBoard.Reset();
|
SoundBoard.Reset();
|
||||||
|
m_jtag.Reset();
|
||||||
|
|
||||||
if (DriveBoard.IsAttached())
|
if (DriveBoard.IsAttached())
|
||||||
DriveBoard.Reset();
|
DriveBoard.Reset();
|
||||||
|
@ -2818,7 +2958,8 @@ CModel3::CModel3(const Util::Config::Node &config)
|
||||||
TileGen(config),
|
TileGen(config),
|
||||||
GPU(config),
|
GPU(config),
|
||||||
SoundBoard(config),
|
SoundBoard(config),
|
||||||
DriveBoard(config)
|
DriveBoard(config),
|
||||||
|
m_jtag(GPU)
|
||||||
{
|
{
|
||||||
// Initialize pointers so dtor can know whether to free them
|
// Initialize pointers so dtor can know whether to free them
|
||||||
memoryPool = NULL;
|
memoryPool = NULL;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define INCLUDED_MODEL3_H
|
#define INCLUDED_MODEL3_H
|
||||||
|
|
||||||
#include "Model3/IEmulator.h"
|
#include "Model3/IEmulator.h"
|
||||||
|
#include "Model3/JTAG.h"
|
||||||
#include "Model3/Crypto.h"
|
#include "Model3/Crypto.h"
|
||||||
#include "Util/NewConfig.h"
|
#include "Util/NewConfig.h"
|
||||||
|
|
||||||
|
@ -282,6 +283,7 @@ private:
|
||||||
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
|
CCrypto m_cryptoDevice; // Encryption device
|
||||||
|
CJTAG m_jtag; // JTAG interface
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Supermodel.h"
|
#include "Supermodel.h"
|
||||||
|
#include "Model3/JTAG.h"
|
||||||
#include "Util/BMPFile.h"
|
#include "Util/BMPFile.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -70,6 +71,9 @@
|
||||||
#define MEM_POOL_SIZE_DIRTY (DIRTY_SIZE(MEM_POOL_SIZE_RO))
|
#define MEM_POOL_SIZE_DIRTY (DIRTY_SIZE(MEM_POOL_SIZE_RO))
|
||||||
#define MEMORY_POOL_SIZE (MEM_POOL_SIZE_RW+MEM_POOL_SIZE_RO+MEM_POOL_SIZE_DIRTY)
|
#define MEMORY_POOL_SIZE (MEM_POOL_SIZE_RW+MEM_POOL_SIZE_RO+MEM_POOL_SIZE_DIRTY)
|
||||||
|
|
||||||
|
static void UpdateRenderConfig(IRender3D *Render3D, uint64_t internalRenderConfig[]);
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Save States
|
Save States
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -90,12 +94,15 @@ void CReal3D::SaveState(CBlockFile *SaveState)
|
||||||
SaveState->Write(&dmaStatus, sizeof(dmaStatus));
|
SaveState->Write(&dmaStatus, sizeof(dmaStatus));
|
||||||
SaveState->Write(&dmaConfig, sizeof(dmaConfig));
|
SaveState->Write(&dmaConfig, sizeof(dmaConfig));
|
||||||
|
|
||||||
SaveState->Write(&tapCurrentInstruction, sizeof(tapCurrentInstruction));
|
// These used to be occupied by JTAG state
|
||||||
SaveState->Write(&tapIR, sizeof(tapIR));
|
SaveState->Write(m_internalRenderConfig, sizeof(m_internalRenderConfig));
|
||||||
SaveState->Write(tapID, sizeof(tapID));
|
SaveState->Write(commandPortWritten);
|
||||||
SaveState->Write(&tapIDSize, sizeof(tapIDSize));
|
SaveState->Write(&m_pingPong, sizeof(m_pingPong));
|
||||||
SaveState->Write(&tapTDO, sizeof(tapTDO));
|
for (int i = 0; i < 39; i++)
|
||||||
SaveState->Write(&tapState, sizeof(tapState));
|
{
|
||||||
|
uint8_t nul = 0;
|
||||||
|
SaveState->Write(&nul, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
SaveState->Write(&m_vromTextureFIFOIdx, sizeof(m_vromTextureFIFOIdx));
|
SaveState->Write(&m_vromTextureFIFOIdx, sizeof(m_vromTextureFIFOIdx));
|
||||||
}
|
}
|
||||||
|
@ -125,12 +132,15 @@ void CReal3D::LoadState(CBlockFile *SaveState)
|
||||||
SaveState->Read(&dmaStatus, sizeof(dmaStatus));
|
SaveState->Read(&dmaStatus, sizeof(dmaStatus));
|
||||||
SaveState->Read(&dmaConfig, sizeof(dmaConfig));
|
SaveState->Read(&dmaConfig, sizeof(dmaConfig));
|
||||||
|
|
||||||
SaveState->Read(&tapCurrentInstruction, sizeof(tapCurrentInstruction));
|
SaveState->Read(m_internalRenderConfig, sizeof(m_internalRenderConfig));
|
||||||
SaveState->Read(&tapIR, sizeof(tapIR));
|
UpdateRenderConfig(Render3D, m_internalRenderConfig);
|
||||||
SaveState->Read(tapID, sizeof(tapID));
|
SaveState->Read(&commandPortWritten);
|
||||||
SaveState->Read(&tapIDSize, sizeof(tapIDSize));
|
SaveState->Read(&m_pingPong, sizeof(m_pingPong));
|
||||||
SaveState->Read(&tapTDO, sizeof(tapTDO));
|
for (int i = 0; i < 39; i++)
|
||||||
SaveState->Read(&tapState, sizeof(tapState));
|
{
|
||||||
|
uint8_t nul;
|
||||||
|
SaveState->Read(&nul, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
SaveState->Read(&m_vromTextureFIFOIdx, sizeof(m_vromTextureFIFOIdx));
|
SaveState->Read(&m_vromTextureFIFOIdx, sizeof(m_vromTextureFIFOIdx));
|
||||||
}
|
}
|
||||||
|
@ -140,12 +150,28 @@ void CReal3D::LoadState(CBlockFile *SaveState)
|
||||||
Rendering
|
Rendering
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
static void UpdateRenderConfig(IRender3D *Render3D, uint64_t internalRenderConfig[])
|
||||||
|
{
|
||||||
|
bool noSunClamp = (internalRenderConfig[0] & 0x800000) != 0 && (internalRenderConfig[1] & 0x400000) != 0;
|
||||||
|
Render3D->SetSunClamp(!noSunClamp);
|
||||||
|
}
|
||||||
|
|
||||||
void CReal3D::BeginVBlank(int statusCycles)
|
void CReal3D::BeginVBlank(int statusCycles)
|
||||||
{
|
{
|
||||||
|
#ifndef NEW_FRAME_TIMING
|
||||||
// Calculate point at which status bit should change value. Currently the same timing is used for both the status bit in ReadRegister
|
// Calculate point at which status bit should change value. Currently the same timing is used for both the status bit in ReadRegister
|
||||||
// and in WriteDMARegister32/ReadDMARegister32, however it may be that they are completely unrelated. It appears that step 1.x games
|
// and in WriteDMARegister32/ReadDMARegister32, however it may be that they are completely unrelated. It appears that step 1.x games
|
||||||
// access just the former while step 2.x access the latter. It is not known yet what this bit/these bits actually represent.
|
// access just the former while step 2.x access the latter. It is not known yet what this bit/these bits actually represent.
|
||||||
statusChange = ppc_total_cycles() + statusCycles;
|
statusChange = ppc_total_cycles() + statusCycles;
|
||||||
|
#else
|
||||||
|
// Buffers are swapped at a specific point in the frame if a flush (command
|
||||||
|
// port write) was performed
|
||||||
|
if (commandPortWritten)
|
||||||
|
{
|
||||||
|
m_pingPong ^= 0x02000000;
|
||||||
|
commandPortWritten = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CReal3D::EndVBlank(void)
|
void CReal3D::EndVBlank(void)
|
||||||
|
@ -157,7 +183,9 @@ uint32_t CReal3D::SyncSnapshots(void)
|
||||||
{
|
{
|
||||||
// Update read-only copy of command port flag
|
// Update read-only copy of command port flag
|
||||||
commandPortWrittenRO = commandPortWritten;
|
commandPortWrittenRO = commandPortWritten;
|
||||||
|
#ifndef NEW_FRAME_TIMING
|
||||||
commandPortWritten = false;
|
commandPortWritten = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!m_gpuMultiThreaded)
|
if (!m_gpuMultiThreaded)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -255,181 +283,6 @@ void CReal3D::EndFrame(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
JTAG Test Access Port Simulation
|
|
||||||
|
|
||||||
What I term as "IDs" here are really boundary scan values.
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
static const int tapFSM[][2] = // finite state machine, each state can lead to 2 next states
|
|
||||||
{
|
|
||||||
{ 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
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* InsertBit():
|
|
||||||
*
|
|
||||||
* Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be
|
|
||||||
* the MSB of the first byte in the buffer.
|
|
||||||
*/
|
|
||||||
void CReal3D::InsertBit(uint8_t *buf, unsigned bitNum, unsigned bit)
|
|
||||||
{
|
|
||||||
unsigned bitInByte = 7 - (bitNum & 7);
|
|
||||||
buf[bitNum / 8] &= ~(1 << bitInByte);
|
|
||||||
buf[bitNum / 8] |= (bit << bitInByte);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* InsertID():
|
|
||||||
*
|
|
||||||
* Inserts a 32-bit ID code into the ID bit field.
|
|
||||||
*/
|
|
||||||
void CReal3D::InsertID(uint32_t id, unsigned startBit)
|
|
||||||
{
|
|
||||||
for (int i = 31; i >= 0; i--)
|
|
||||||
InsertBit(tapID, startBit++, (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.
|
|
||||||
*/
|
|
||||||
unsigned CReal3D::Shift(uint8_t *data, unsigned numBits)
|
|
||||||
{
|
|
||||||
// This loop takes care of all the fully-filled bytes
|
|
||||||
unsigned shiftIn = 0;
|
|
||||||
unsigned shiftOut = 0;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < numBits / 8; i++)
|
|
||||||
{
|
|
||||||
shiftOut = data[i] & 1;
|
|
||||||
data[i] >>= 1;
|
|
||||||
data[i] |= (shiftIn << 7);
|
|
||||||
shiftIn = shiftOut; // carry over to next element's MSB
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take care of the last partial byte (if there is one)
|
|
||||||
if ((numBits & 7) != 0)
|
|
||||||
{
|
|
||||||
shiftOut = (data[i] >> (8 - (numBits & 7))) & 1;
|
|
||||||
data[i] >>= 1;
|
|
||||||
data[i] |= (shiftIn << 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
return shiftOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned CReal3D::ReadTAP(void)
|
|
||||||
{
|
|
||||||
return tapTDO;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CReal3D::WriteTAP(unsigned tck, unsigned tms, unsigned tdi, unsigned trst)
|
|
||||||
{
|
|
||||||
if (!tck)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Go to next state
|
|
||||||
tapState = tapFSM[tapState][tms];
|
|
||||||
switch (tapState)
|
|
||||||
{
|
|
||||||
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 (step == 0x10)
|
|
||||||
{
|
|
||||||
InsertID(0x116C7057, 1 + 0 * 32);
|
|
||||||
InsertID(0x216C3057, 1 + 1 * 32);
|
|
||||||
InsertID(0x116C4057, 1 + 2 * 32);
|
|
||||||
InsertID(0x216C5057, 1 + 3 * 32);
|
|
||||||
InsertID(0x116C6057, 1 + 4 * 32 + 1);
|
|
||||||
InsertID(0x116C6057, 1 + 5 * 32 + 1);
|
|
||||||
}
|
|
||||||
else if (step == 0x15)
|
|
||||||
{
|
|
||||||
InsertID(0x316C7057, 1 + 0 * 32);
|
|
||||||
InsertID(0x316C3057, 1 + 1 * 32);
|
|
||||||
InsertID(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057
|
|
||||||
InsertID(0x316C5057, 1 + 3 * 32);
|
|
||||||
InsertID(0x216C6057, 1 + 4 * 32 + 1);
|
|
||||||
InsertID(0x216C6057, 1 + 5 * 32 + 1);
|
|
||||||
}
|
|
||||||
else if (step >= 0x20)
|
|
||||||
{
|
|
||||||
InsertID(0x416C7057, 1 + 0 * 32);
|
|
||||||
InsertID(0x416C3057, 1 + 1 * 32);
|
|
||||||
InsertID(0x316C4057, 1 + 2 * 32); // skichamp at PC=A89F4, this value causes "NO DAUGHTER BOARD" message
|
|
||||||
InsertID(0x416C5057, 1 + 3 * 32);
|
|
||||||
InsertID(0x316C6057, 1 + 4 * 32 + 1);
|
|
||||||
InsertID(0x316C6057, 1 + 5 * 32 + 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4: // Shift-DR
|
|
||||||
tapTDO = Shift(tapID, tapIDSize);
|
|
||||||
//printf("TAP: Shift-DR Bit %d\n", bit++);
|
|
||||||
break;
|
|
||||||
case 10: // Capture-IR
|
|
||||||
// Load lower 2 bits with 01 as per IEEE 1149.1-1990
|
|
||||||
tapIR = 1;
|
|
||||||
break;
|
|
||||||
case 11: // Shift-IR
|
|
||||||
// Shift IR towards output and load in new data from TDI
|
|
||||||
tapTDO = tapIR & 1; // shift LSB to output
|
|
||||||
tapIR >>= 1;
|
|
||||||
tapIR |= ((uint64_t) tdi << 45);
|
|
||||||
break;
|
|
||||||
case 15: // Update-IR
|
|
||||||
/*
|
|
||||||
* Latch IR (technically, this should occur on the falling edge of
|
|
||||||
* TCK)
|
|
||||||
*/
|
|
||||||
tapIR &= 0x3FFFFFFFFFFFULL;
|
|
||||||
tapCurrentInstruction = tapIR;
|
|
||||||
//printf("TAP: Update-IR %XLL\n", tapCurrentInstruction);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
Texture Uploading and Decoding
|
Texture Uploading and Decoding
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -600,7 +453,7 @@ void CReal3D::UploadTexture(uint32_t header, const uint16_t *texData)
|
||||||
// Process texture data
|
// Process texture data
|
||||||
DebugLog("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
DebugLog("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
||||||
//printf("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
//printf("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
||||||
switch ((header>>24)&0x0F)
|
switch ((header>>24)&0xFF)
|
||||||
{
|
{
|
||||||
case 0x00: // texture w/ mipmaps
|
case 0x00: // texture w/ mipmaps
|
||||||
{
|
{
|
||||||
|
@ -652,7 +505,14 @@ void CReal3D::UploadTexture(uint32_t header, const uint16_t *texData)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x80: // MAME thinks these might be a gamma table
|
case 0x80: // MAME thinks these might be a gamma table
|
||||||
//break;
|
/*
|
||||||
|
printf("Special texture format 0x80:\n");
|
||||||
|
for (int i = 0; i < 32*32; i++)
|
||||||
|
{
|
||||||
|
printf(" %02x=%02x\n", i, texData[i]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
break;
|
||||||
default: // unknown
|
default: // unknown
|
||||||
DebugLog("Unknown texture format %02X\n", header>>24);
|
DebugLog("Unknown texture format %02X\n", header>>24);
|
||||||
//printf("unknown texture format %02X\n", header>>24);
|
//printf("unknown texture format %02X\n", header>>24);
|
||||||
|
@ -884,17 +744,30 @@ void CReal3D::WritePolygonRAM(uint32_t addr, uint32_t data)
|
||||||
polyRAM[addr/4] = data;
|
polyRAM[addr/4] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal registers accessible via JTAG port
|
||||||
|
void CReal3D::WriteJTAGRegister(uint64_t instruction, uint64_t data)
|
||||||
|
{
|
||||||
|
if (instruction == CJTAG::Instruction::SetReal3DRenderConfig0)
|
||||||
|
m_internalRenderConfig[0] = data;
|
||||||
|
else if (instruction == CJTAG::Instruction::SetReal3DRenderConfig1)
|
||||||
|
m_internalRenderConfig[1] = data;
|
||||||
|
UpdateRenderConfig(Render3D, m_internalRenderConfig);
|
||||||
|
}
|
||||||
|
|
||||||
// Registers seem to range from 0x00 to around 0x3C but they are not understood
|
// Registers seem to range from 0x00 to around 0x3C but they are not understood
|
||||||
uint32_t CReal3D::ReadRegister(unsigned reg)
|
uint32_t CReal3D::ReadRegister(unsigned reg)
|
||||||
{
|
{
|
||||||
DebugLog("Real3D: Read reg %X\n", reg);
|
DebugLog("Real3D: Read reg %X\n", reg);
|
||||||
if (reg == 0)
|
if (reg == 0)
|
||||||
{
|
{
|
||||||
|
#ifndef NEW_FRAME_TIMING
|
||||||
uint32_t status = (ppc_total_cycles() >= statusChange ? 0x0 : 0x02000000);
|
uint32_t status = (ppc_total_cycles() >= statusChange ? 0x0 : 0x02000000);
|
||||||
return 0xFDFFFFFF|status;
|
return 0xfdffffff | status;
|
||||||
|
#else
|
||||||
|
return 0xfdffffff | m_pingPong;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
return 0xffffffff;
|
||||||
return 0xFFFFFFFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This returns data in the way that the PowerPC bus expects. Other functions in CReal3D should
|
// TODO: This returns data in the way that the PowerPC bus expects. Other functions in CReal3D should
|
||||||
|
@ -946,6 +819,7 @@ void CReal3D::Reset(void)
|
||||||
{
|
{
|
||||||
error = false;
|
error = false;
|
||||||
|
|
||||||
|
m_pingPong = 0;
|
||||||
commandPortWritten = false;
|
commandPortWritten = false;
|
||||||
commandPortWrittenRO = false;
|
commandPortWrittenRO = false;
|
||||||
|
|
||||||
|
@ -954,14 +828,13 @@ void CReal3D::Reset(void)
|
||||||
|
|
||||||
fifoIdx = 0;
|
fifoIdx = 0;
|
||||||
m_vromTextureFIFOIdx = 0;
|
m_vromTextureFIFOIdx = 0;
|
||||||
tapState = 0;
|
|
||||||
tapIDSize = 197;
|
|
||||||
dmaStatus = 0;
|
dmaStatus = 0;
|
||||||
dmaUnknownReg = 0;
|
dmaUnknownReg = 0;
|
||||||
|
|
||||||
unsigned memSize = (m_gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW);
|
unsigned memSize = (m_gpuMultiThreaded ? MEMORY_POOL_SIZE : MEM_POOL_SIZE_RW);
|
||||||
memset(memoryPool, 0, memSize);
|
memset(memoryPool, 0, memSize);
|
||||||
memset(m_vromTextureFIFO, 0, sizeof(m_vromTextureFIFO));
|
memset(m_vromTextureFIFO, 0, sizeof(m_vromTextureFIFO));
|
||||||
|
memset(m_internalRenderConfig, 0, sizeof(m_internalRenderConfig));
|
||||||
|
|
||||||
DebugLog("Real3D reset\n");
|
DebugLog("Real3D reset\n");
|
||||||
}
|
}
|
||||||
|
@ -986,6 +859,12 @@ void CReal3D::AttachRenderer(IRender3D *Render3DPtr)
|
||||||
DebugLog("Real3D attached a Render3D object\n");
|
DebugLog("Real3D attached a Render3D object\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t CReal3D::GetASICIDCode(ASIC asic) const
|
||||||
|
{
|
||||||
|
auto it = m_asicID.find(asic);
|
||||||
|
return it == m_asicID.end() ? 0 : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
void CReal3D::SetStepping(int stepping)
|
void CReal3D::SetStepping(int stepping)
|
||||||
{
|
{
|
||||||
step = stepping;
|
step = stepping;
|
||||||
|
@ -1005,6 +884,42 @@ void CReal3D::SetStepping(int stepping)
|
||||||
if (Render3D != NULL)
|
if (Render3D != NULL)
|
||||||
Render3D->SetStepping(step);
|
Render3D->SetStepping(step);
|
||||||
|
|
||||||
|
// Set ASIC ID codes
|
||||||
|
m_asicID.clear();
|
||||||
|
if (step == 0x10)
|
||||||
|
{
|
||||||
|
m_asicID =
|
||||||
|
{
|
||||||
|
{ ASIC::Mercury, 0x216c3057 },
|
||||||
|
{ ASIC::Venus, 0x116c4057 },
|
||||||
|
{ ASIC::Earth, 0x216c5057 },
|
||||||
|
{ ASIC::Mars, 0x116c6057 },
|
||||||
|
{ ASIC::Jupiter, 0x116c7057 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (step == 0x15)
|
||||||
|
{
|
||||||
|
m_asicID =
|
||||||
|
{
|
||||||
|
{ ASIC::Mercury, 0x316c3057 },
|
||||||
|
{ ASIC::Venus, 0x216c4057 },
|
||||||
|
{ ASIC::Earth, 0x316c5057 },
|
||||||
|
{ ASIC::Mars, 0x216c6057 },
|
||||||
|
{ ASIC::Jupiter, 0x316c7057 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (step >= 0x20)
|
||||||
|
{
|
||||||
|
m_asicID =
|
||||||
|
{
|
||||||
|
{ ASIC::Mercury, 0x416c3057 },
|
||||||
|
{ ASIC::Venus, 0x316c4057 }, // skichamp @ pc=0xa89f4, this value causes 'NO DAUGHTER BOARD' message
|
||||||
|
{ ASIC::Earth, 0x416c5057 },
|
||||||
|
{ ASIC::Mars, 0x316c6057 },
|
||||||
|
{ ASIC::Jupiter, 0x416c7057 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
DebugLog("Real3D set to Step %d.%d\n", (step>>4)&0xF, step&0xF);
|
DebugLog("Real3D set to Step %d.%d\n", (step>>4)&0xF, step&0xF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,8 +979,6 @@ CReal3D::CReal3D(const Util::Config::Node &config)
|
||||||
vrom = NULL;
|
vrom = NULL;
|
||||||
error = false;
|
error = false;
|
||||||
fifoIdx = 0;
|
fifoIdx = 0;
|
||||||
tapState = 0;
|
|
||||||
tapIDSize = 197;
|
|
||||||
m_vromTextureFIFO[0] = 0;
|
m_vromTextureFIFO[0] = 0;
|
||||||
m_vromTextureFIFO[1] = 0;
|
m_vromTextureFIFO[1] = 0;
|
||||||
m_vromTextureFIFOIdx = 0;
|
m_vromTextureFIFOIdx = 0;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#define INCLUDED_REAL3D_H
|
#define INCLUDED_REAL3D_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* QueuedUploadTextures:
|
* QueuedUploadTextures:
|
||||||
|
@ -58,6 +59,21 @@ struct QueuedUploadTextures
|
||||||
class CReal3D: public IPCIDevice
|
class CReal3D: public IPCIDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/*
|
||||||
|
* ASIC Names
|
||||||
|
*
|
||||||
|
* These were determined from Virtual On, which prints them out if any of the
|
||||||
|
* ID codes are incorrect. ID codes depend on stepping.
|
||||||
|
*/
|
||||||
|
enum ASIC
|
||||||
|
{
|
||||||
|
Mercury,
|
||||||
|
Venus,
|
||||||
|
Earth,
|
||||||
|
Mars,
|
||||||
|
Jupiter
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SaveState(SaveState):
|
* SaveState(SaveState):
|
||||||
*
|
*
|
||||||
|
@ -240,30 +256,18 @@ public:
|
||||||
void WritePolygonRAM(uint32_t addr, uint32_t data);
|
void WritePolygonRAM(uint32_t addr, uint32_t data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReadTAP(void):
|
* WriteJTAGRegister(instruction, data):
|
||||||
*
|
*
|
||||||
* Reads the JTAG Test Access Port.
|
* Write to an internal register using the JTAG interface. This is intended
|
||||||
*
|
* to be called from the JTAG emulation for instructions that are known to
|
||||||
* Returns:
|
* poke the internal state of Real3D ASICs.
|
||||||
* The TDO bit (either 1 or 0).
|
|
||||||
*/
|
|
||||||
unsigned ReadTAP(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* void WriteTAP(tck, tms, tdi, trst):
|
|
||||||
*
|
|
||||||
* Writes to the JTAG TAP. State changes only occur on the rising edge of
|
|
||||||
* the clock (tck = 1). Each of the inputs is a single bit only and must be
|
|
||||||
* either 0 or 1, or the code will fail.
|
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* tck Clock.
|
* instruction Value of the JTAG instruction register.
|
||||||
* tms Test mode select.
|
* data Data written.
|
||||||
* tdi Serial data input. Must be 0 or 1 only!
|
|
||||||
* trst Reset.
|
|
||||||
*/
|
*/
|
||||||
void WriteTAP(unsigned tck, unsigned tms, unsigned tdi, unsigned trst);
|
void WriteJTAGRegister(uint64_t instruction, uint64_t data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReadRegister(reg):
|
* ReadRegister(reg):
|
||||||
*
|
*
|
||||||
|
@ -333,6 +337,20 @@ public:
|
||||||
*/
|
*/
|
||||||
void AttachRenderer(IRender3D *Render3DPtr);
|
void AttachRenderer(IRender3D *Render3DPtr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetASICIDCodes(asic):
|
||||||
|
*
|
||||||
|
* Obtain ASIC ID code for the specified ASIC under the currently configured
|
||||||
|
* hardware stepping.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* asic ASIC ID.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The ASIC ID code. Undefined for invalid ASIC ID.
|
||||||
|
*/
|
||||||
|
uint32_t GetASICIDCode(ASIC asic) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SetStepping(stepping):
|
* SetStepping(stepping):
|
||||||
*
|
*
|
||||||
|
@ -456,15 +474,12 @@ private:
|
||||||
bool commandPortWrittenRO; // Read-only copy of flag
|
bool commandPortWrittenRO; // Read-only copy of flag
|
||||||
|
|
||||||
// Status and command registers
|
// Status and command registers
|
||||||
uint64_t statusChange;
|
uint32_t m_pingPong;
|
||||||
|
uint64_t statusChange;
|
||||||
|
|
||||||
// JTAG Test Access Port
|
// Internal ASIC state
|
||||||
uint64_t tapCurrentInstruction; // latched IR (not always equal to IR)
|
std::map<ASIC, uint32_t> m_asicID;
|
||||||
uint64_t tapIR; // instruction register (46 bits)
|
uint64_t m_internalRenderConfig[2] = { 0, 0 };
|
||||||
uint8_t tapID[32]; // ASIC ID code data buffer
|
|
||||||
unsigned tapIDSize; // size of ID data in bits
|
|
||||||
unsigned tapTDO; // bit shifted out to TDO
|
|
||||||
unsigned tapState; // current state
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue