1 #include "make_unique.h"
2 #include "../Log.h"
3 #include "../states/RegisterStateFile.h"
4 #include "../Ps2Const.h"
5 #include "../FrameDump.h"
6 #include "Vif.h"
7 #include "Vif1.h"
8 #include "GIF.h"
9 #include "Vpu.h"
10 
11 #define LOG_NAME ("ee_vpu")
12 
CVpu(unsigned int number,const VPUINIT & vpuInit,CGIF & gif,CINTC & intc,uint8 * ram,uint8 * spr)13 CVpu::CVpu(unsigned int number, const VPUINIT& vpuInit, CGIF& gif, CINTC& intc, uint8* ram, uint8* spr)
14     : m_number(number)
15     , m_vif((number == 0) ? std::make_unique<CVif>(0, *this, intc, ram, spr) : std::make_unique<CVif1>(1, *this, gif, intc, ram, spr))
16     , m_microMem(vpuInit.microMem)
17     , m_microMemSize((number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE)
18     , m_vuMem(vpuInit.vuMem)
19     , m_vuMemSize((number == 0) ? PS2::VUMEM0SIZE : PS2::VUMEM1SIZE)
20     , m_ctx(vpuInit.context)
21     , m_gif(gif)
22     , m_vuProfilerZone(CProfiler::GetInstance().RegisterZone("VU"))
23 #ifdef DEBUGGER_INCLUDED
24     , m_microMemMiniState(new uint8[(number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE])
25     , m_vuMemMiniState(new uint8[(number == 0) ? PS2::VUMEM0SIZE : PS2::VUMEM1SIZE])
26     , m_topMiniState(0)
27     , m_itopMiniState(0)
28 #endif
29 {
30 }
31 
~CVpu()32 CVpu::~CVpu()
33 {
34 #ifdef DEBUGGER_INCLUDED
35 	delete[] m_microMemMiniState;
36 	delete[] m_vuMemMiniState;
37 #endif
38 }
39 
Execute(int32 quota)40 void CVpu::Execute(int32 quota)
41 {
42 	if(!m_running) return;
43 
44 #ifdef PROFILE
45 	CProfilerZone profilerZone(m_vuProfilerZone);
46 #endif
47 
48 	m_ctx->m_executor->Execute(quota);
49 	if(m_ctx->m_State.nHasException)
50 	{
51 		//E bit encountered
52 		m_running = false;
53 		VuStateChanged(m_running);
54 	}
55 }
56 
57 #ifdef DEBUGGER_INCLUDED
58 
SaveMiniState()59 void CVpu::SaveMiniState()
60 {
61 	memcpy(m_microMemMiniState, m_microMem, (m_number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE);
62 	memcpy(m_vuMemMiniState, m_vuMem, (m_number == 0) ? PS2::VUMEM0SIZE : PS2::VUMEM1SIZE);
63 	memcpy(&m_vuMiniState, &m_ctx->m_State, sizeof(MIPSSTATE));
64 	m_topMiniState = (m_number == 0) ? 0 : m_vif->GetTOP();
65 	m_itopMiniState = m_vif->GetITOP();
66 }
67 
GetVuMiniState() const68 const MIPSSTATE& CVpu::GetVuMiniState() const
69 {
70 	return m_vuMiniState;
71 }
72 
GetVuMemoryMiniState() const73 uint8* CVpu::GetVuMemoryMiniState() const
74 {
75 	return m_vuMemMiniState;
76 }
77 
GetMicroMemoryMiniState() const78 uint8* CVpu::GetMicroMemoryMiniState() const
79 {
80 	return m_microMemMiniState;
81 }
82 
GetVuTopMiniState() const83 uint32 CVpu::GetVuTopMiniState() const
84 {
85 	return m_topMiniState;
86 }
87 
GetVuItopMiniState() const88 uint32 CVpu::GetVuItopMiniState() const
89 {
90 	return m_itopMiniState;
91 }
92 
93 #endif
94 
Reset()95 void CVpu::Reset()
96 {
97 	m_running = false;
98 	m_ctx->m_executor->Reset();
99 	m_vif->Reset();
100 }
101 
SaveState(Framework::CZipArchiveWriter & archive)102 void CVpu::SaveState(Framework::CZipArchiveWriter& archive)
103 {
104 	m_vif->SaveState(archive);
105 }
106 
LoadState(Framework::CZipArchiveReader & archive)107 void CVpu::LoadState(Framework::CZipArchiveReader& archive)
108 {
109 	m_vif->LoadState(archive);
110 }
111 
GetContext() const112 CMIPS& CVpu::GetContext() const
113 {
114 	return *m_ctx;
115 }
116 
GetMicroMemory() const117 uint8* CVpu::GetMicroMemory() const
118 {
119 	return m_microMem;
120 }
121 
GetMicroMemorySize() const122 uint32 CVpu::GetMicroMemorySize() const
123 {
124 	return m_microMemSize;
125 }
126 
GetVuMemory() const127 uint8* CVpu::GetVuMemory() const
128 {
129 	return m_vuMem;
130 }
131 
GetVuMemorySize() const132 uint32 CVpu::GetVuMemorySize() const
133 {
134 	return m_vuMemSize;
135 }
136 
IsVuRunning() const137 bool CVpu::IsVuRunning() const
138 {
139 	return m_running;
140 }
141 
GetVif()142 CVif& CVpu::GetVif()
143 {
144 	return *m_vif.get();
145 }
146 
ExecuteMicroProgram(uint32 nAddress)147 void CVpu::ExecuteMicroProgram(uint32 nAddress)
148 {
149 	CLog::GetInstance().Print(LOG_NAME, "Starting microprogram execution at 0x%08X.\r\n", nAddress);
150 
151 	m_ctx->m_State.nPC = nAddress;
152 	m_ctx->m_State.pipeTime = 0;
153 	m_ctx->m_State.nHasException = 0;
154 
155 #ifdef DEBUGGER_INCLUDED
156 	SaveMiniState();
157 #endif
158 
159 	assert(!m_running);
160 	m_running = true;
161 	VuStateChanged(m_running);
162 	for(unsigned int i = 0; i < 100; i++)
163 	{
164 		Execute(5000);
165 		if(!m_running) break;
166 	}
167 }
168 
InvalidateMicroProgram()169 void CVpu::InvalidateMicroProgram()
170 {
171 	m_ctx->m_executor->ClearActiveBlocksInRange(0, (m_number == 0) ? PS2::MICROMEM0SIZE : PS2::MICROMEM1SIZE, false);
172 }
173 
InvalidateMicroProgram(uint32 start,uint32 end)174 void CVpu::InvalidateMicroProgram(uint32 start, uint32 end)
175 {
176 	m_ctx->m_executor->ClearActiveBlocksInRange(start, end, false);
177 }
178 
ProcessXgKick(uint32 address)179 void CVpu::ProcessXgKick(uint32 address)
180 {
181 	address &= 0x3FF;
182 	address *= 0x10;
183 
184 	//	assert(nAddress < PS2::VUMEM1SIZE);
185 
186 	CGsPacketMetadata metadata;
187 	metadata.pathIndex = 1;
188 #ifdef DEBUGGER_INCLUDED
189 	metadata.vuMemPacketAddress = address;
190 	metadata.vpu1Top = GetVuTopMiniState();
191 	metadata.vpu1Itop = GetVuItopMiniState();
192 	memcpy(&metadata.vu1State, &GetVuMiniState(), sizeof(MIPSSTATE));
193 	memcpy(metadata.vuMem1, GetVuMemoryMiniState(), PS2::VUMEM1SIZE);
194 	memcpy(metadata.microMem1, GetMicroMemoryMiniState(), PS2::MICROMEM1SIZE);
195 #endif
196 
197 	m_gif.ProcessSinglePacket(GetVuMemory(), PS2::VUMEM1SIZE, address, PS2::VUMEM1SIZE, metadata);
198 
199 #ifdef DEBUGGER_INCLUDED
200 	SaveMiniState();
201 #endif
202 }
203