summaryrefslogtreecommitdiff
path: root/src/core/hw
diff options
context:
space:
mode:
authorGravatar darkf2014-12-29 19:47:41 -0800
committerGravatar darkf2014-12-29 19:47:41 -0800
commit8ba9ac0f74abb0408a26207a76a0c1808bad8de0 (patch)
treef1c7c3393fa726435b5b90bf335567c93e528ef1 /src/core/hw
parentAdd comment regarding __WIN32__ in SkyEye code (diff)
parentMerge pull request #367 from bunnei/usat_ssat (diff)
downloadyuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.gz
yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.xz
yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.zip
Fix merge conflicts
Diffstat (limited to 'src/core/hw')
-rw-r--r--src/core/hw/gpu.cpp96
-rw-r--r--src/core/hw/gpu.h5
-rw-r--r--src/core/hw/hw.cpp23
-rw-r--r--src/core/hw/hw.h2
-rw-r--r--src/core/hw/ndma.cpp47
-rw-r--r--src/core/hw/ndma.h26
6 files changed, 60 insertions, 139 deletions
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 3ad801c63..dd619cb16 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
@@ -21,12 +21,14 @@ namespace GPU {
21 21
22Regs g_regs; 22Regs g_regs;
23 23
24u32 g_cur_line = 0; ///< Current vertical screen line 24bool g_skip_frame = false; ///< True if the current frame was skipped
25u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
26u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
27 25
28static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second 26static u64 frame_ticks = 0; ///< 268MHz / gpu_refresh_rate frames per second
29static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame 27static u64 line_ticks = 0; ///< Number of ticks for a screen line
28static u32 cur_line = 0; ///< Current screen line
29static u64 last_update_tick = 0; ///< CPU ticl count from last GPU update
30static u64 frame_count = 0; ///< Number of frames drawn
31static bool last_skip_frame = false; ///< True if the last frame was skipped
30 32
31template <typename T> 33template <typename T>
32inline void Read(T &var, const u32 raw_addr) { 34inline void Read(T &var, const u32 raw_addr) {
@@ -34,8 +36,8 @@ inline void Read(T &var, const u32 raw_addr) {
34 u32 index = addr / 4; 36 u32 index = addr / 4;
35 37
36 // Reads other than u32 are untested, so I'd rather have them abort than silently fail 38 // Reads other than u32 are untested, so I'd rather have them abort than silently fail
37 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 39 if (index >= Regs::NumIds() || !std::is_same<T, u32>::value) {
38 ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 40 LOG_ERROR(HW_GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
39 return; 41 return;
40 } 42 }
41 43
@@ -48,8 +50,8 @@ inline void Write(u32 addr, const T data) {
48 u32 index = addr / 4; 50 u32 index = addr / 4;
49 51
50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail 52 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 53 if (index >= Regs::NumIds() || !std::is_same<T, u32>::value) {
52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 54 LOG_ERROR(HW_GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
53 return; 55 return;
54 } 56 }
55 57
@@ -73,7 +75,7 @@ inline void Write(u32 addr, const T data) {
73 for (u32* ptr = start; ptr < end; ++ptr) 75 for (u32* ptr = start; ptr < end; ++ptr)
74 *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation 76 *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
75 77
76 DEBUG_LOG(GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); 78 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
77 } 79 }
78 break; 80 break;
79 } 81 }
@@ -105,7 +107,7 @@ inline void Write(u32 addr, const T data) {
105 } 107 }
106 108
107 default: 109 default:
108 ERROR_LOG(GPU, "Unknown source framebuffer format %x", config.input_format.Value()); 110 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
109 break; 111 break;
110 } 112 }
111 113
@@ -132,16 +134,16 @@ inline void Write(u32 addr, const T data) {
132 } 134 }
133 135
134 default: 136 default:
135 ERROR_LOG(GPU, "Unknown destination framebuffer format %x", config.output_format.Value()); 137 LOG_ERROR(HW_GPU, "Unknown destination framebuffer format %x", config.output_format.Value());
136 break; 138 break;
137 } 139 }
138 } 140 }
139 } 141 }
140 142
141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 143 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
142 config.output_height * config.output_width * 4, 144 config.output_height * config.output_width * 4,
143 config.GetPhysicalInputAddress(), config.input_width, config.input_height, 145 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
144 config.GetPhysicalOutputAddress(), config.output_width, config.output_height, 146 config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
145 config.output_format.Value()); 147 config.output_format.Value());
146 } 148 }
147 break; 149 break;
@@ -154,8 +156,7 @@ inline void Write(u32 addr, const T data) {
154 if (config.trigger & 1) 156 if (config.trigger & 1)
155 { 157 {
156 u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress())); 158 u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress()));
157 u32 size = config.size << 3; 159 Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
158 Pica::CommandProcessor::ProcessCommandList(buffer, size);
159 } 160 }
160 break; 161 break;
161 } 162 }
@@ -180,37 +181,41 @@ template void Write<u8>(u32 addr, const u8 data);
180/// Update hardware 181/// Update hardware
181void Update() { 182void Update() {
182 auto& framebuffer_top = g_regs.framebuffer_config[0]; 183 auto& framebuffer_top = g_regs.framebuffer_config[0];
183 u64 current_ticks = Core::g_app_core->GetTicks();
184
185 // Update the frame after a certain number of CPU ticks have elapsed. This assumes that the
186 // active frame in memory is always complete to render. There also may be issues with this
187 // becoming out-of-synch with GSP synchrinization code (as follows). At this time, this seems to
188 // be the most effective solution for both homebrew and retail applications. With retail, this
189 // could be moved below (and probably would guarantee more accurate synchronization). However,
190 // primitive homebrew relies on a vertical blank interrupt to happen inevitably (regardless of a
191 // threading reschedule).
192
193 if ((current_ticks - g_last_frame_ticks) > GPU::kFrameTicks) {
194 VideoCore::g_renderer->SwapBuffers();
195 g_last_frame_ticks = current_ticks;
196 }
197 184
198 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical 185 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical
199 // blank, we need to simulate it. Based on testing, it seems that retail applications work more 186 // blank, we need to simulate it. Based on testing, it seems that retail applications work more
200 // accurately when this is signalled between thread switches. 187 // accurately when this is signalled between thread switches.
201 188
202 if (HLE::g_reschedule) { 189 if (HLE::g_reschedule) {
190 u64 current_ticks = Core::g_app_core->GetTicks();
191 u32 num_lines = static_cast<u32>((current_ticks - last_update_tick) / line_ticks);
203 192
204 // Synchronize line... 193 // Synchronize line...
205 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) { 194 if (num_lines > 0) {
206 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); 195 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
207 g_cur_line++; 196 cur_line += num_lines;
208 g_last_line_ticks = current_ticks; 197 last_update_tick += (num_lines * line_ticks);
209 } 198 }
210 199
211 // Synchronize frame... 200 // Synchronize frame...
212 if (g_cur_line >= framebuffer_top.height) { 201 if (cur_line >= framebuffer_top.height) {
213 g_cur_line = 0; 202 cur_line = 0;
203 frame_count++;
204 last_skip_frame = g_skip_frame;
205 g_skip_frame = (frame_count & Settings::values.frame_skip) != 0;
206
207 // Swap buffers based on the frameskip mode, which is a little bit tricky. When
208 // a frame is being skipped, nothing is being rendered to the internal framebuffer(s).
209 // So, we should only swap frames if the last frame was rendered. The rules are:
210 // - If frameskip == 0 (disabled), always swap buffers
211 // - If frameskip == 1, swap buffers every other frame (starting from the first frame)
212 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
213
214 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
215 Settings::values.frame_skip == 0) {
216 VideoCore::g_renderer->SwapBuffers();
217 }
218
214 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); 219 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
215 } 220 }
216 } 221 }
@@ -218,12 +223,6 @@ void Update() {
218 223
219/// Initialize hardware 224/// Initialize hardware
220void Init() { 225void Init() {
221 kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate;
222 kFrameTicks = kFrameCycles / 3;
223
224 g_cur_line = 0;
225 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
226
227 auto& framebuffer_top = g_regs.framebuffer_config[0]; 226 auto& framebuffer_top = g_regs.framebuffer_config[0];
228 auto& framebuffer_sub = g_regs.framebuffer_config[1]; 227 auto& framebuffer_sub = g_regs.framebuffer_config[1];
229 228
@@ -252,12 +251,19 @@ void Init() {
252 framebuffer_sub.color_format = Regs::PixelFormat::RGB8; 251 framebuffer_sub.color_format = Regs::PixelFormat::RGB8;
253 framebuffer_sub.active_fb = 0; 252 framebuffer_sub.active_fb = 0;
254 253
255 NOTICE_LOG(GPU, "initialized OK"); 254 frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
255 line_ticks = (GPU::frame_ticks / framebuffer_top.height);
256 cur_line = 0;
257 last_update_tick = Core::g_app_core->GetTicks();
258 last_skip_frame = false;
259 g_skip_frame = false;
260
261 LOG_DEBUG(HW_GPU, "initialized OK");
256} 262}
257 263
258/// Shutdown hardware 264/// Shutdown hardware
259void Shutdown() { 265void Shutdown() {
260 NOTICE_LOG(GPU, "shutdown OK"); 266 LOG_DEBUG(HW_GPU, "shutdown OK");
261} 267}
262 268
263} // namespace 269} // namespace
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 3fa7b9ccf..292f496c1 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -169,7 +169,7 @@ struct Regs {
169 INSERT_PADDING_WORDS(0x331); 169 INSERT_PADDING_WORDS(0x331);
170 170
171 struct { 171 struct {
172 // command list size 172 // command list size (in bytes)
173 u32 size; 173 u32 size;
174 174
175 INSERT_PADDING_WORDS(0x1); 175 INSERT_PADDING_WORDS(0x1);
@@ -241,6 +241,7 @@ ASSERT_REG_POSITION(command_processor_config, 0x00638);
241static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set"); 241static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set");
242 242
243extern Regs g_regs; 243extern Regs g_regs;
244extern bool g_skip_frame;
244 245
245template <typename T> 246template <typename T>
246void Read(T &var, const u32 addr); 247void Read(T &var, const u32 addr);
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index 4d0719263..848ab5348 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -1,12 +1,11 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6 6
7#include "core/hw/hw.h" 7#include "core/hw/hw.h"
8#include "core/hw/gpu.h" 8#include "core/hw/gpu.h"
9#include "core/hw/ndma.h"
10 9
11namespace HW { 10namespace HW {
12 11
@@ -40,17 +39,12 @@ template <typename T>
40inline void Read(T &var, const u32 addr) { 39inline void Read(T &var, const u32 addr) {
41 switch (addr & 0xFFFFF000) { 40 switch (addr & 0xFFFFF000) {
42 41
43 // TODO(bunnei): What is the virtual address of NDMA?
44 // case VADDR_NDMA:
45 // NDMA::Read(var, addr);
46 // break;
47
48 case VADDR_GPU: 42 case VADDR_GPU:
49 GPU::Read(var, addr); 43 GPU::Read(var, addr);
50 break; 44 break;
51 45
52 default: 46 default:
53 ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 47 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
54 } 48 }
55} 49}
56 50
@@ -58,17 +52,12 @@ template <typename T>
58inline void Write(u32 addr, const T data) { 52inline void Write(u32 addr, const T data) {
59 switch (addr & 0xFFFFF000) { 53 switch (addr & 0xFFFFF000) {
60 54
61 // TODO(bunnei): What is the virtual address of NDMA?
62 // case VADDR_NDMA
63 // NDMA::Write(addr, data);
64 // break;
65
66 case VADDR_GPU: 55 case VADDR_GPU:
67 GPU::Write(addr, data); 56 GPU::Write(addr, data);
68 break; 57 break;
69 58
70 default: 59 default:
71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 60 LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
72 } 61 }
73} 62}
74 63
@@ -87,19 +76,17 @@ template void Write<u8>(u32 addr, const u8 data);
87/// Update hardware 76/// Update hardware
88void Update() { 77void Update() {
89 GPU::Update(); 78 GPU::Update();
90 NDMA::Update();
91} 79}
92 80
93/// Initialize hardware 81/// Initialize hardware
94void Init() { 82void Init() {
95 GPU::Init(); 83 GPU::Init();
96 NDMA::Init(); 84 LOG_DEBUG(HW, "initialized OK");
97 NOTICE_LOG(HW, "initialized OK");
98} 85}
99 86
100/// Shutdown hardware 87/// Shutdown hardware
101void Shutdown() { 88void Shutdown() {
102 NOTICE_LOG(HW, "shutdown OK"); 89 LOG_DEBUG(HW, "shutdown OK");
103} 90}
104 91
105} \ No newline at end of file 92} \ No newline at end of file
diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h
index 1055ed94f..991c0a07d 100644
--- a/src/core/hw/hw.h
+++ b/src/core/hw/hw.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
deleted file mode 100644
index e29a773f1..000000000
--- a/src/core/hw/ndma.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6
7#include "core/hw/ndma.h"
8
9namespace NDMA {
10
11template <typename T>
12inline void Read(T &var, const u32 addr) {
13 ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
14}
15
16template <typename T>
17inline void Write(u32 addr, const T data) {
18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
19}
20
21// Explicitly instantiate template functions because we aren't defining this in the header:
22
23template void Read<u64>(u64 &var, const u32 addr);
24template void Read<u32>(u32 &var, const u32 addr);
25template void Read<u16>(u16 &var, const u32 addr);
26template void Read<u8>(u8 &var, const u32 addr);
27
28template void Write<u64>(u32 addr, const u64 data);
29template void Write<u32>(u32 addr, const u32 data);
30template void Write<u16>(u32 addr, const u16 data);
31template void Write<u8>(u32 addr, const u8 data);
32
33/// Update hardware
34void Update() {
35}
36
37/// Initialize hardware
38void Init() {
39 NOTICE_LOG(GPU, "initialized OK");
40}
41
42/// Shutdown hardware
43void Shutdown() {
44 NOTICE_LOG(GPU, "shutdown OK");
45}
46
47} // namespace
diff --git a/src/core/hw/ndma.h b/src/core/hw/ndma.h
deleted file mode 100644
index d8fa3d40b..000000000
--- a/src/core/hw/ndma.h
+++ /dev/null
@@ -1,26 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace NDMA {
10
11template <typename T>
12inline void Read(T &var, const u32 addr);
13
14template <typename T>
15inline void Write(u32 addr, const T data);
16
17/// Update hardware
18void Update();
19
20/// Initialize hardware
21void Init();
22
23/// Shutdown hardware
24void Shutdown();
25
26} // namespace