Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/core/bus.cpp
4223 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "bus.h"
5
#include "bios.h"
6
#include "cdrom.h"
7
#include "cpu_code_cache.h"
8
#include "cpu_core.h"
9
#include "cpu_core_private.h"
10
#include "cpu_disasm.h"
11
#include "dma.h"
12
#include "gpu.h"
13
#include "host.h"
14
#include "interrupt_controller.h"
15
#include "mdec.h"
16
#include "pad.h"
17
#include "pio.h"
18
#include "psf_loader.h"
19
#include "settings.h"
20
#include "sio.h"
21
#include "spu.h"
22
#include "system.h"
23
#include "timers.h"
24
#include "timing_event.h"
25
26
#include "util/cd_image.h"
27
#include "util/elf_file.h"
28
#include "util/state_wrapper.h"
29
30
#include "common/align.h"
31
#include "common/assert.h"
32
#include "common/binary_reader_writer.h"
33
#include "common/error.h"
34
#include "common/file_system.h"
35
#include "common/intrin.h"
36
#include "common/log.h"
37
#include "common/memmap.h"
38
#include "common/path.h"
39
#include "common/string_util.h"
40
41
#include <cstdio>
42
#include <tuple>
43
#include <utility>
44
45
LOG_CHANNEL(Bus);
46
47
// Exports for external debugger access
48
#ifndef __ANDROID__
49
namespace Exports {
50
51
extern "C" {
52
#ifdef _WIN32
53
_declspec(dllexport) uintptr_t RAM;
54
_declspec(dllexport) u32 RAM_SIZE, RAM_MASK;
55
#else
56
__attribute__((visibility("default"), used)) uintptr_t RAM;
57
__attribute__((visibility("default"), used)) u32 RAM_SIZE, RAM_MASK;
58
#endif
59
}
60
61
} // namespace Exports
62
#endif
63
64
namespace Bus {
65
66
namespace {
67
union MEMDELAY
68
{
69
u32 bits;
70
71
BitField<u32, u8, 4, 4> access_time; // cycles
72
BitField<u32, bool, 8, 1> use_com0_time;
73
BitField<u32, bool, 9, 1> use_com1_time;
74
BitField<u32, bool, 10, 1> use_com2_time;
75
BitField<u32, bool, 11, 1> use_com3_time;
76
BitField<u32, bool, 12, 1> data_bus_16bit;
77
BitField<u32, u8, 16, 5> memory_window_size;
78
79
static constexpr u32 WRITE_MASK = 0b10101111'00011111'11111111'11111111;
80
};
81
82
union COMDELAY
83
{
84
u32 bits;
85
86
BitField<u32, u8, 0, 4> com0;
87
BitField<u32, u8, 4, 4> com1;
88
BitField<u32, u8, 8, 4> com2;
89
BitField<u32, u8, 12, 4> com3;
90
BitField<u32, u8, 16, 2> comunk;
91
92
static constexpr u32 WRITE_MASK = 0b00000000'00000011'11111111'11111111;
93
};
94
95
union MEMCTRL
96
{
97
u32 regs[MEMCTRL_REG_COUNT];
98
99
struct
100
{
101
u32 exp1_base;
102
u32 exp2_base;
103
MEMDELAY exp1_delay_size;
104
MEMDELAY exp3_delay_size;
105
MEMDELAY bios_delay_size;
106
MEMDELAY spu_delay_size;
107
MEMDELAY cdrom_delay_size;
108
MEMDELAY exp2_delay_size;
109
COMDELAY common_delay;
110
};
111
};
112
113
union RAM_SIZE_REG
114
{
115
u32 bits;
116
117
// All other bits unknown/unhandled.
118
BitField<u32, u8, 9, 3> memory_window;
119
};
120
} // namespace
121
122
static void* s_shmem_handle = nullptr;
123
static std::string s_shmem_name;
124
125
std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits{};
126
u8* g_ram = nullptr;
127
u8* g_unprotected_ram = nullptr;
128
u32 g_ram_size = 0;
129
u32 g_ram_mapped_size = 0;
130
u32 g_ram_mask = 0;
131
u8* g_bios = nullptr;
132
void** g_memory_handlers = nullptr;
133
void** g_memory_handlers_isc = nullptr;
134
135
std::array<TickCount, 3> g_exp1_access_time = {};
136
std::array<TickCount, 3> g_exp2_access_time = {};
137
std::array<TickCount, 3> g_bios_access_time = {};
138
std::array<TickCount, 3> g_cdrom_access_time = {};
139
std::array<TickCount, 3> g_spu_access_time = {};
140
141
static MEMCTRL s_MEMCTRL = {};
142
static RAM_SIZE_REG s_RAM_SIZE = {};
143
144
static std::string s_tty_line_buffer;
145
146
#ifdef ENABLE_MMAP_FASTMEM
147
static SharedMemoryMappingArea s_fastmem_arena;
148
static std::vector<std::pair<u8*, size_t>> s_fastmem_ram_views;
149
#endif
150
151
static u8** s_fastmem_lut = nullptr;
152
153
static bool s_kernel_initialize_hook_run = false;
154
155
static bool AllocateMemoryMap(bool export_shared_memory, Error* error);
156
static void ReleaseMemoryMap();
157
static void SetRAMSize(bool enable_8mb_ram);
158
159
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
160
static void RecalculateMemoryTimings();
161
162
static void MapFastmemViews();
163
static void UnmapFastmemViews();
164
static u8* GetLUTFastmemPointer(u32 address, u8* ram_ptr);
165
166
static void SetRAMPageWritable(u32 page_index, bool writable);
167
168
static void KernelInitializedHook();
169
static bool SideloadEXE(const std::string& path, Error* error);
170
static bool InjectCPE(std::span<const u8> buffer, bool set_pc, Error* error);
171
static bool InjectELF(const ELFFile& elf, bool set_pc, Error* error);
172
173
static void SetHandlers();
174
static void UpdateMappedRAMSize();
175
176
} // namespace Bus
177
178
namespace MemoryMap {
179
static constexpr size_t RAM_OFFSET = 0;
180
static constexpr size_t RAM_SIZE = Bus::RAM_8MB_SIZE;
181
static constexpr size_t BIOS_OFFSET = RAM_OFFSET + RAM_SIZE;
182
static constexpr size_t BIOS_SIZE = Bus::BIOS_SIZE;
183
static constexpr size_t LUT_OFFSET = BIOS_OFFSET + BIOS_SIZE;
184
static constexpr size_t LUT_SIZE = (sizeof(void*) * Bus::MEMORY_LUT_SLOTS) * 2; // normal and isolated
185
static constexpr size_t TOTAL_SIZE = LUT_OFFSET + LUT_SIZE;
186
} // namespace MemoryMap
187
188
#define FIXUP_HALFWORD_OFFSET(size, offset) ((size >= MemoryAccessSize::HalfWord) ? (offset) : ((offset) & ~1u))
189
#define FIXUP_HALFWORD_READ_VALUE(size, offset, value) \
190
((size >= MemoryAccessSize::HalfWord) ? (value) : ((value) >> (((offset) & u32(1)) * 8u)))
191
#define FIXUP_HALFWORD_WRITE_VALUE(size, offset, value) \
192
((size >= MemoryAccessSize::HalfWord) ? (value) : ((value) << (((offset) & u32(1)) * 8u)))
193
194
#define FIXUP_WORD_OFFSET(size, offset) ((size == MemoryAccessSize::Word) ? (offset) : ((offset) & ~3u))
195
#define FIXUP_WORD_READ_VALUE(size, offset, value) \
196
((size == MemoryAccessSize::Word) ? (value) : ((value) >> (((offset) & 3u) * 8)))
197
#define FIXUP_WORD_WRITE_VALUE(size, offset, value) \
198
((size == MemoryAccessSize::Word) ? (value) : ((value) << (((offset) & 3u) * 8)))
199
200
bool Bus::AllocateMemoryMap(bool export_shared_memory, Error* error)
201
{
202
INFO_LOG("Allocating{} shared memory map.", export_shared_memory ? " EXPORTED" : "");
203
if (export_shared_memory)
204
{
205
s_shmem_name = MemMap::GetFileMappingName("duckstation");
206
INFO_LOG("Shared memory object name is \"{}\".", s_shmem_name);
207
}
208
s_shmem_handle = MemMap::CreateSharedMemory(s_shmem_name.c_str(), MemoryMap::TOTAL_SIZE, error);
209
if (!s_shmem_handle)
210
{
211
#ifndef __linux__
212
Error::AddSuffix(error, "\nYou may need to close some programs to free up additional memory.");
213
#else
214
Error::AddSuffix(
215
error, "\nYou may need to close some programs to free up additional memory, or increase the size of /dev/shm.");
216
#endif
217
return false;
218
}
219
220
g_ram = static_cast<u8*>(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::RAM_OFFSET, nullptr, MemoryMap::RAM_SIZE,
221
PageProtect::ReadWrite));
222
g_unprotected_ram = static_cast<u8*>(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::RAM_OFFSET, nullptr,
223
MemoryMap::RAM_SIZE, PageProtect::ReadWrite));
224
if (!g_ram || !g_unprotected_ram)
225
{
226
Error::SetStringView(error, "Failed to map memory for RAM");
227
ReleaseMemoryMap();
228
return false;
229
}
230
231
VERBOSE_LOG("RAM is mapped at {}.", static_cast<void*>(g_ram));
232
233
g_bios = static_cast<u8*>(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::BIOS_OFFSET, nullptr,
234
MemoryMap::BIOS_SIZE, PageProtect::ReadWrite));
235
if (!g_bios)
236
{
237
Error::SetStringView(error, "Failed to map memory for BIOS");
238
ReleaseMemoryMap();
239
return false;
240
}
241
242
VERBOSE_LOG("BIOS is mapped at {}.", static_cast<void*>(g_bios));
243
244
g_memory_handlers = static_cast<void**>(MemMap::MapSharedMemory(s_shmem_handle, MemoryMap::LUT_OFFSET, nullptr,
245
MemoryMap::LUT_SIZE, PageProtect::ReadWrite));
246
if (!g_memory_handlers)
247
{
248
Error::SetStringView(error, "Failed to map memory for LUTs");
249
ReleaseMemoryMap();
250
return false;
251
}
252
253
VERBOSE_LOG("LUTs are mapped at {}.", static_cast<void*>(g_memory_handlers));
254
g_memory_handlers_isc = g_memory_handlers + MEMORY_LUT_SLOTS;
255
g_ram_mapped_size = RAM_8MB_SIZE;
256
SetHandlers();
257
258
#ifndef __ANDROID__
259
Exports::RAM = reinterpret_cast<uintptr_t>(g_unprotected_ram);
260
#endif
261
262
return true;
263
}
264
265
void Bus::ReleaseMemoryMap()
266
{
267
#ifndef __ANDROID__
268
Exports::RAM = 0;
269
Exports::RAM_SIZE = 0;
270
Exports::RAM_MASK = 0;
271
#endif
272
273
g_memory_handlers_isc = nullptr;
274
if (g_memory_handlers)
275
{
276
MemMap::UnmapSharedMemory(g_memory_handlers, MemoryMap::LUT_SIZE);
277
g_memory_handlers = nullptr;
278
}
279
280
if (g_bios)
281
{
282
MemMap::UnmapSharedMemory(g_bios, MemoryMap::BIOS_SIZE);
283
g_bios = nullptr;
284
}
285
286
if (g_unprotected_ram)
287
{
288
MemMap::UnmapSharedMemory(g_unprotected_ram, MemoryMap::RAM_SIZE);
289
g_unprotected_ram = nullptr;
290
}
291
292
if (g_ram)
293
{
294
MemMap::UnmapSharedMemory(g_ram, MemoryMap::RAM_SIZE);
295
g_ram = nullptr;
296
}
297
298
if (s_shmem_handle)
299
{
300
MemMap::DestroySharedMemory(s_shmem_handle);
301
s_shmem_handle = nullptr;
302
303
if (!s_shmem_name.empty())
304
{
305
MemMap::DeleteSharedMemory(s_shmem_name.c_str());
306
s_shmem_name = {};
307
}
308
}
309
}
310
311
bool Bus::AllocateMemory(bool export_shared_memory, Error* error)
312
{
313
if (!AllocateMemoryMap(export_shared_memory, error))
314
return false;
315
316
#ifdef ENABLE_MMAP_FASTMEM
317
if (!s_fastmem_arena.Create(FASTMEM_ARENA_SIZE))
318
{
319
Error::SetStringView(error, "Failed to create fastmem arena");
320
ReleaseMemory();
321
return false;
322
}
323
324
INFO_LOG("Fastmem base: {}", static_cast<void*>(s_fastmem_arena.BasePointer()));
325
#endif
326
327
return true;
328
}
329
330
void Bus::ReleaseMemory()
331
{
332
#ifdef ENABLE_MMAP_FASTMEM
333
DebugAssert(s_fastmem_ram_views.empty());
334
s_fastmem_arena.Destroy();
335
#endif
336
337
std::free(s_fastmem_lut);
338
s_fastmem_lut = nullptr;
339
340
ReleaseMemoryMap();
341
}
342
343
bool Bus::ReallocateMemoryMap(bool export_shared_memory, Error* error)
344
{
345
// Need to back up RAM+BIOS.
346
DynamicHeapArray<u8> ram_backup;
347
DynamicHeapArray<u8> bios_backup;
348
349
if (System::IsValid())
350
{
351
CPU::CodeCache::InvalidateAllRAMBlocks();
352
UnmapFastmemViews();
353
354
ram_backup.resize(RAM_8MB_SIZE);
355
std::memcpy(ram_backup.data(), g_unprotected_ram, RAM_8MB_SIZE);
356
bios_backup.resize(BIOS_SIZE);
357
std::memcpy(bios_backup.data(), g_bios, BIOS_SIZE);
358
}
359
360
ReleaseMemoryMap();
361
if (!AllocateMemoryMap(export_shared_memory, error)) [[unlikely]]
362
return false;
363
364
if (System::IsValid())
365
{
366
UpdateMappedRAMSize();
367
std::memcpy(g_unprotected_ram, ram_backup.data(), RAM_8MB_SIZE);
368
std::memcpy(g_bios, bios_backup.data(), BIOS_SIZE);
369
MapFastmemViews();
370
}
371
372
return true;
373
}
374
375
void Bus::CleanupMemoryMap()
376
{
377
#if !defined(_WIN32) && !defined(__ANDROID__)
378
// This is only needed on Linux.
379
if (!s_shmem_name.empty())
380
MemMap::DeleteSharedMemory(s_shmem_name.c_str());
381
#endif
382
}
383
384
void Bus::Initialize()
385
{
386
SetRAMSize(g_settings.enable_8mb_ram);
387
MapFastmemViews();
388
}
389
390
void Bus::SetRAMSize(bool enable_8mb_ram)
391
{
392
g_ram_size = enable_8mb_ram ? RAM_8MB_SIZE : RAM_2MB_SIZE;
393
g_ram_mask = enable_8mb_ram ? RAM_8MB_MASK : RAM_2MB_MASK;
394
395
#ifndef __ANDROID__
396
Exports::RAM_SIZE = g_ram_size;
397
Exports::RAM_MASK = g_ram_mask;
398
#endif
399
}
400
401
void Bus::Shutdown()
402
{
403
UnmapFastmemViews();
404
CPU::g_state.fastmem_base = nullptr;
405
406
g_ram_mask = 0;
407
g_ram_size = 0;
408
}
409
410
void Bus::Reset()
411
{
412
std::memset(g_ram, 0, g_ram_size);
413
s_MEMCTRL.exp1_base = 0x1F000000;
414
s_MEMCTRL.exp2_base = 0x1F802000;
415
s_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
416
s_MEMCTRL.exp3_delay_size.bits = 0x00003022;
417
s_MEMCTRL.bios_delay_size.bits = 0x0013243F;
418
s_MEMCTRL.spu_delay_size.bits = 0x200931E1;
419
s_MEMCTRL.cdrom_delay_size.bits = 0x00020843;
420
s_MEMCTRL.exp2_delay_size.bits = 0x00070777;
421
s_MEMCTRL.common_delay.bits = 0x00031125;
422
g_ram_code_bits = {};
423
s_kernel_initialize_hook_run = false;
424
RecalculateMemoryTimings();
425
426
// Avoid remapping if unchanged.
427
if (s_RAM_SIZE.bits != 0x00000B88)
428
{
429
s_RAM_SIZE.bits = 0x00000B88;
430
UpdateMappedRAMSize();
431
}
432
}
433
434
bool Bus::DoState(StateWrapper& sw)
435
{
436
u32 ram_size = g_ram_size;
437
sw.DoEx(&ram_size, 52, static_cast<u32>(RAM_2MB_SIZE));
438
if (ram_size != g_ram_size)
439
{
440
const bool using_8mb_ram = (ram_size == RAM_8MB_SIZE);
441
SetRAMSize(using_8mb_ram);
442
RemapFastmemViews();
443
}
444
445
sw.Do(&g_exp1_access_time);
446
sw.Do(&g_exp2_access_time);
447
sw.Do(&g_bios_access_time);
448
sw.Do(&g_cdrom_access_time);
449
sw.Do(&g_spu_access_time);
450
sw.DoBytes(g_ram, g_ram_size);
451
452
if (sw.GetVersion() < 58) [[unlikely]]
453
{
454
WARNING_LOG("Overwriting loaded BIOS with old save state.");
455
sw.DoBytes(g_bios, BIOS_SIZE);
456
}
457
458
sw.DoArray(s_MEMCTRL.regs, countof(s_MEMCTRL.regs));
459
460
const RAM_SIZE_REG old_ram_size_reg = s_RAM_SIZE;
461
sw.Do(&s_RAM_SIZE.bits);
462
if (s_RAM_SIZE.memory_window != old_ram_size_reg.memory_window)
463
UpdateMappedRAMSize();
464
465
sw.Do(&s_tty_line_buffer);
466
467
sw.DoEx(&s_kernel_initialize_hook_run, 68, true);
468
469
return !sw.HasError();
470
}
471
472
std::tuple<TickCount, TickCount, TickCount> Bus::CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay)
473
{
474
// from nocash spec
475
s32 first = 0, seq = 0, min = 0;
476
if (mem_delay.use_com0_time)
477
{
478
first += s32(common_delay.com0) - 1;
479
seq += s32(common_delay.com0) - 1;
480
}
481
if (mem_delay.use_com2_time)
482
{
483
first += s32(common_delay.com2);
484
seq += s32(common_delay.com2);
485
}
486
if (mem_delay.use_com3_time)
487
{
488
min = s32(common_delay.com3);
489
}
490
if (first < 6)
491
first++;
492
493
first = first + s32(mem_delay.access_time) + 2;
494
seq = seq + s32(mem_delay.access_time) + 2;
495
496
if (first < (min + 6))
497
first = min + 6;
498
if (seq < (min + 2))
499
seq = min + 2;
500
501
const TickCount byte_access_time = first;
502
const TickCount halfword_access_time = mem_delay.data_bus_16bit ? first : (first + seq);
503
const TickCount word_access_time = mem_delay.data_bus_16bit ? (first + seq) : (first + seq + seq + seq);
504
return std::tie(std::max(byte_access_time - 1, 0), std::max(halfword_access_time - 1, 0),
505
std::max(word_access_time - 1, 0));
506
}
507
508
void Bus::RecalculateMemoryTimings()
509
{
510
std::tie(g_bios_access_time[0], g_bios_access_time[1], g_bios_access_time[2]) =
511
CalculateMemoryTiming(s_MEMCTRL.bios_delay_size, s_MEMCTRL.common_delay);
512
std::tie(g_cdrom_access_time[0], g_cdrom_access_time[1], g_cdrom_access_time[2]) =
513
CalculateMemoryTiming(s_MEMCTRL.cdrom_delay_size, s_MEMCTRL.common_delay);
514
std::tie(g_spu_access_time[0], g_spu_access_time[1], g_spu_access_time[2]) =
515
CalculateMemoryTiming(s_MEMCTRL.spu_delay_size, s_MEMCTRL.common_delay);
516
std::tie(g_exp1_access_time[0], g_exp1_access_time[1], g_exp1_access_time[2]) =
517
CalculateMemoryTiming(s_MEMCTRL.exp1_delay_size, s_MEMCTRL.common_delay);
518
519
TRACE_LOG("BIOS Memory Timing: {} bit bus, byte={}, halfword={}, word={}",
520
s_MEMCTRL.bios_delay_size.data_bus_16bit ? 16 : 8, g_bios_access_time[0] + 1, g_bios_access_time[1] + 1,
521
g_bios_access_time[2] + 1);
522
TRACE_LOG("CDROM Memory Timing: {} bit bus, byte={}, halfword={}, word={}",
523
s_MEMCTRL.cdrom_delay_size.data_bus_16bit ? 16 : 8, g_cdrom_access_time[0] + 1, g_cdrom_access_time[1] + 1,
524
g_cdrom_access_time[2] + 1);
525
TRACE_LOG("SPU Memory Timing: {} bit bus, byte={}, halfword={}, word={}",
526
s_MEMCTRL.spu_delay_size.data_bus_16bit ? 16 : 8, g_spu_access_time[0] + 1, g_spu_access_time[1] + 1,
527
g_spu_access_time[2] + 1);
528
TRACE_LOG("EXP1 Memory Timing: {} bit bus, byte={}, halfword={}, word={}",
529
s_MEMCTRL.spu_delay_size.data_bus_16bit ? 16 : 8, g_spu_access_time[0] + 1, g_spu_access_time[1] + 1,
530
g_spu_access_time[2] + 1);
531
}
532
533
void* Bus::GetFastmemBase(bool isc)
534
{
535
#ifdef ENABLE_MMAP_FASTMEM
536
if (g_settings.cpu_fastmem_mode == CPUFastmemMode::MMap)
537
return isc ? nullptr : s_fastmem_arena.BasePointer();
538
#endif
539
if (g_settings.cpu_fastmem_mode == CPUFastmemMode::LUT)
540
return reinterpret_cast<u8*>(s_fastmem_lut + (isc ? (FASTMEM_LUT_SIZE * sizeof(void*)) : 0));
541
542
return nullptr;
543
}
544
545
u8* Bus::GetLUTFastmemPointer(u32 address, u8* ram_ptr)
546
{
547
return ram_ptr - address;
548
}
549
550
void Bus::MapFastmemViews()
551
{
552
#ifdef ENABLE_MMAP_FASTMEM
553
Assert(s_fastmem_ram_views.empty());
554
#endif
555
556
const CPUFastmemMode mode = g_settings.cpu_fastmem_mode;
557
if (mode == CPUFastmemMode::MMap)
558
{
559
#ifdef ENABLE_MMAP_FASTMEM
560
auto MapRAM = [](u32 base_address) {
561
u8* map_address = s_fastmem_arena.BasePointer() + base_address;
562
if (!s_fastmem_arena.Map(s_shmem_handle, 0, map_address, g_ram_size, PageProtect::ReadWrite)) [[unlikely]]
563
{
564
ERROR_LOG("Failed to map RAM at fastmem area {} (offset 0x{:08X})", static_cast<void*>(map_address),
565
g_ram_size);
566
return;
567
}
568
569
// mark all pages with code as non-writable
570
const u32 page_count = g_ram_size >> HOST_PAGE_SHIFT;
571
for (u32 i = 0; i < page_count; i++)
572
{
573
if (g_ram_code_bits[i])
574
{
575
u8* page_address = map_address + (i << HOST_PAGE_SHIFT);
576
if (!MemMap::MemProtect(page_address, HOST_PAGE_SIZE, PageProtect::ReadOnly)) [[unlikely]]
577
{
578
ERROR_LOG("Failed to write-protect code page at {}", static_cast<void*>(page_address));
579
s_fastmem_arena.Unmap(map_address, g_ram_size);
580
return;
581
}
582
}
583
}
584
585
s_fastmem_ram_views.emplace_back(map_address, g_ram_size);
586
};
587
588
// KUSEG - cached
589
MapRAM(0x00000000);
590
591
// KSEG0 - cached
592
MapRAM(0x80000000);
593
594
// KSEG1 - uncached
595
MapRAM(0xA0000000);
596
597
// Mirrors of 2MB
598
if (g_ram_size == RAM_2MB_SIZE)
599
{
600
// Instead of mapping all the RAM mirrors, we only map the KSEG0 uppermost mirror.
601
// This is where some games place their stack, so we avoid the backpatching overhead/slowdown,
602
// but don't pay the cost of 4x the mprotect() calls when a page's protection changes, which
603
// can have a non-trivial impact on slow ARM devices.
604
MapRAM(0x80600000);
605
}
606
#else
607
Panic("MMap fastmem should not be selected on this platform.");
608
#endif
609
}
610
else if (mode == CPUFastmemMode::LUT)
611
{
612
if (!s_fastmem_lut)
613
{
614
s_fastmem_lut = static_cast<u8**>(std::malloc(sizeof(u8*) * FASTMEM_LUT_SLOTS));
615
Assert(s_fastmem_lut);
616
617
INFO_LOG("Fastmem base (software): {}", static_cast<void*>(s_fastmem_lut));
618
}
619
620
// This assumes the top 4KB of address space is not mapped. It shouldn't be on any sane OSes.
621
for (u32 i = 0; i < FASTMEM_LUT_SLOTS; i++)
622
s_fastmem_lut[i] = GetLUTFastmemPointer(i << FASTMEM_LUT_PAGE_SHIFT, nullptr);
623
624
auto MapRAM = [](u32 base_address) {
625
// Don't map RAM that isn't accessible.
626
if (CPU::VirtualAddressToPhysical(base_address) >= g_ram_mapped_size)
627
return;
628
629
u8* ram_ptr = g_ram + (base_address & g_ram_mask);
630
for (u32 address = 0; address < g_ram_size; address += FASTMEM_LUT_PAGE_SIZE)
631
{
632
const u32 lut_index = (base_address + address) >> FASTMEM_LUT_PAGE_SHIFT;
633
s_fastmem_lut[lut_index] = GetLUTFastmemPointer(base_address + address, ram_ptr);
634
ram_ptr += FASTMEM_LUT_PAGE_SIZE;
635
}
636
};
637
638
// KUSEG - cached
639
MapRAM(0x00000000);
640
MapRAM(0x00200000);
641
MapRAM(0x00400000);
642
MapRAM(0x00600000);
643
644
// KSEG0 - cached
645
MapRAM(0x80000000);
646
MapRAM(0x80200000);
647
MapRAM(0x80400000);
648
MapRAM(0x80600000);
649
650
// KSEG1 - uncached
651
MapRAM(0xA0000000);
652
MapRAM(0xA0200000);
653
MapRAM(0xA0400000);
654
MapRAM(0xA0600000);
655
}
656
657
CPU::UpdateMemoryPointers();
658
}
659
660
void Bus::UnmapFastmemViews()
661
{
662
#ifdef ENABLE_MMAP_FASTMEM
663
for (const auto& it : s_fastmem_ram_views)
664
s_fastmem_arena.Unmap(it.first, it.second);
665
s_fastmem_ram_views.clear();
666
#endif
667
}
668
669
void Bus::RemapFastmemViews()
670
{
671
UnmapFastmemViews();
672
MapFastmemViews();
673
}
674
675
bool Bus::CanUseFastmemForAddress(VirtualMemoryAddress address)
676
{
677
const PhysicalMemoryAddress paddr = CPU::VirtualAddressToPhysical(address);
678
679
switch (g_settings.cpu_fastmem_mode)
680
{
681
#ifdef ENABLE_MMAP_FASTMEM
682
case CPUFastmemMode::MMap:
683
{
684
// Currently since we don't map the mirrors, don't use fastmem for them.
685
// This is because the swapping of page code bits for SMC is too expensive.
686
// Except for the uppermost mirror in KSEG0, see above.
687
return (paddr < g_ram_size) || (address >= 0x80600000 && address < 0x80800000);
688
}
689
#endif
690
691
case CPUFastmemMode::LUT:
692
return (paddr < RAM_MIRROR_END);
693
694
case CPUFastmemMode::Disabled:
695
default:
696
return false;
697
}
698
}
699
700
void Bus::SetRAMCodePage(u32 index)
701
{
702
if (g_ram_code_bits[index])
703
return;
704
705
// protect fastmem pages
706
g_ram_code_bits[index] = true;
707
SetRAMPageWritable(index, false);
708
}
709
710
void Bus::ClearRAMCodePage(u32 index)
711
{
712
if (!g_ram_code_bits[index])
713
return;
714
715
// unprotect fastmem pages
716
g_ram_code_bits[index] = false;
717
SetRAMPageWritable(index, true);
718
}
719
720
void Bus::SetRAMPageWritable(u32 page_index, bool writable)
721
{
722
if (!MemMap::MemProtect(&g_ram[page_index << HOST_PAGE_SHIFT], HOST_PAGE_SIZE,
723
writable ? PageProtect::ReadWrite : PageProtect::ReadOnly)) [[unlikely]]
724
{
725
ERROR_LOG("Failed to set RAM host page {} ({}) to {}", page_index,
726
reinterpret_cast<const void*>(&g_ram[page_index * HOST_PAGE_SIZE]),
727
writable ? "read-write" : "read-only");
728
}
729
730
#ifdef ENABLE_MMAP_FASTMEM
731
if (g_settings.cpu_fastmem_mode == CPUFastmemMode::MMap)
732
{
733
const PageProtect protect = writable ? PageProtect::ReadWrite : PageProtect::ReadOnly;
734
735
// unprotect fastmem pages
736
for (const auto& it : s_fastmem_ram_views)
737
{
738
u8* page_address = it.first + (page_index << HOST_PAGE_SHIFT);
739
if (!MemMap::MemProtect(page_address, HOST_PAGE_SIZE, protect)) [[unlikely]]
740
{
741
ERROR_LOG("Failed to {} code page {} (0x{:08X}) @ {}", writable ? "unprotect" : "protect", page_index,
742
page_index << HOST_PAGE_SHIFT, static_cast<void*>(page_address));
743
}
744
}
745
746
return;
747
}
748
#endif
749
}
750
751
void Bus::ClearRAMCodePageFlags()
752
{
753
g_ram_code_bits.reset();
754
755
if (!MemMap::MemProtect(g_ram, RAM_8MB_SIZE, PageProtect::ReadWrite))
756
ERROR_LOG("Failed to restore RAM protection to read-write.");
757
758
#ifdef ENABLE_MMAP_FASTMEM
759
if (g_settings.cpu_fastmem_mode == CPUFastmemMode::MMap)
760
{
761
// unprotect fastmem pages
762
for (const auto& it : s_fastmem_ram_views)
763
{
764
if (!MemMap::MemProtect(it.first, it.second, PageProtect::ReadWrite))
765
ERROR_LOG("Failed to unprotect code pages for fastmem view @ {}", static_cast<void*>(it.first));
766
}
767
}
768
#endif
769
}
770
771
bool Bus::IsCodePageAddress(PhysicalMemoryAddress address)
772
{
773
return IsRAMAddress(address) ? g_ram_code_bits[(address & g_ram_mask) >> HOST_PAGE_SHIFT] : false;
774
}
775
776
bool Bus::HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
777
{
778
if (!IsRAMAddress(start_address))
779
return false;
780
781
start_address = (start_address & g_ram_mask);
782
783
const u32 end_address = start_address + size;
784
while (start_address < end_address)
785
{
786
const u32 code_page_index = start_address >> HOST_PAGE_SHIFT;
787
if (g_ram_code_bits[code_page_index])
788
return true;
789
790
start_address += HOST_PAGE_SIZE;
791
}
792
793
return false;
794
}
795
796
const TickCount* Bus::GetMemoryAccessTimePtr(PhysicalMemoryAddress address, MemoryAccessSize size)
797
{
798
// Currently only BIOS, but could be EXP1 as well.
799
if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_MIRROR_SIZE))
800
return &g_bios_access_time[static_cast<size_t>(size)];
801
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
802
return &g_exp1_access_time[static_cast<size_t>(size)];
803
804
return nullptr;
805
}
806
807
std::optional<Bus::MemoryRegion> Bus::GetMemoryRegionForAddress(PhysicalMemoryAddress address)
808
{
809
if (address < RAM_2MB_SIZE)
810
return MemoryRegion::RAM;
811
else if (address < RAM_MIRROR_END)
812
return static_cast<MemoryRegion>(static_cast<u32>(MemoryRegion::RAM) + (address / RAM_2MB_SIZE));
813
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
814
return MemoryRegion::EXP1;
815
else if (address >= CPU::SCRATCHPAD_ADDR && address < (CPU::SCRATCHPAD_ADDR + CPU::SCRATCHPAD_SIZE))
816
return MemoryRegion::Scratchpad;
817
else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE))
818
return MemoryRegion::BIOS;
819
820
return std::nullopt;
821
}
822
823
static constexpr std::array<std::tuple<PhysicalMemoryAddress, PhysicalMemoryAddress, bool>,
824
static_cast<u32>(Bus::MemoryRegion::Count)>
825
s_code_region_ranges = {{
826
{0, Bus::RAM_2MB_SIZE, true},
827
{Bus::RAM_2MB_SIZE, Bus::RAM_2MB_SIZE * 2, true},
828
{Bus::RAM_2MB_SIZE * 2, Bus::RAM_2MB_SIZE * 3, true},
829
{Bus::RAM_2MB_SIZE * 3, Bus::RAM_MIRROR_END, true},
830
{Bus::EXP1_BASE, Bus::EXP1_BASE + Bus::EXP1_SIZE, false},
831
{CPU::SCRATCHPAD_ADDR, CPU::SCRATCHPAD_ADDR + CPU::SCRATCHPAD_SIZE, true},
832
{Bus::BIOS_BASE, Bus::BIOS_BASE + Bus::BIOS_SIZE, false},
833
}};
834
835
PhysicalMemoryAddress Bus::GetMemoryRegionStart(MemoryRegion region)
836
{
837
return std::get<0>(s_code_region_ranges[static_cast<u32>(region)]);
838
}
839
840
PhysicalMemoryAddress Bus::GetMemoryRegionEnd(MemoryRegion region)
841
{
842
return std::get<1>(s_code_region_ranges[static_cast<u32>(region)]);
843
}
844
845
bool Bus::IsMemoryRegionWritable(MemoryRegion region)
846
{
847
return std::get<2>(s_code_region_ranges[static_cast<u32>(region)]);
848
}
849
850
u8* Bus::GetMemoryRegionPointer(MemoryRegion region)
851
{
852
switch (region)
853
{
854
case MemoryRegion::RAM:
855
return g_unprotected_ram;
856
857
case MemoryRegion::RAMMirror1:
858
return (g_unprotected_ram + (RAM_2MB_SIZE & g_ram_mask));
859
860
case MemoryRegion::RAMMirror2:
861
return (g_unprotected_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask));
862
863
case MemoryRegion::RAMMirror3:
864
return (g_unprotected_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask));
865
866
case MemoryRegion::EXP1:
867
return nullptr;
868
869
case MemoryRegion::Scratchpad:
870
return CPU::g_state.scratchpad.data();
871
872
case MemoryRegion::BIOS:
873
return g_bios;
874
875
default:
876
return nullptr;
877
}
878
}
879
880
static ALWAYS_INLINE_RELEASE bool MaskedMemoryCompare(const u8* pattern, const u8* mask, u32 pattern_length,
881
const u8* mem)
882
{
883
if (!mask)
884
return std::memcmp(mem, pattern, pattern_length) == 0;
885
886
for (u32 i = 0; i < pattern_length; i++)
887
{
888
if ((mem[i] & mask[i]) != (pattern[i] & mask[i]))
889
return false;
890
}
891
892
return true;
893
}
894
895
std::optional<PhysicalMemoryAddress> Bus::SearchMemory(PhysicalMemoryAddress start_address, const u8* pattern,
896
const u8* mask, u32 pattern_length)
897
{
898
std::optional<MemoryRegion> region = GetMemoryRegionForAddress(start_address);
899
if (!region.has_value())
900
return std::nullopt;
901
902
PhysicalMemoryAddress current_address = start_address;
903
MemoryRegion current_region = region.value();
904
while (current_region != MemoryRegion::Count)
905
{
906
const u8* mem = GetMemoryRegionPointer(current_region);
907
const PhysicalMemoryAddress region_start = GetMemoryRegionStart(current_region);
908
const PhysicalMemoryAddress region_end = GetMemoryRegionEnd(current_region);
909
910
if (mem)
911
{
912
PhysicalMemoryAddress region_offset = current_address - region_start;
913
PhysicalMemoryAddress bytes_remaining = region_end - current_address;
914
while (bytes_remaining >= pattern_length)
915
{
916
if (MaskedMemoryCompare(pattern, mask, pattern_length, mem + region_offset))
917
return region_start + region_offset;
918
919
region_offset++;
920
bytes_remaining--;
921
}
922
}
923
924
// skip RAM mirrors
925
if (current_region == MemoryRegion::RAM)
926
current_region = MemoryRegion::EXP1;
927
else
928
current_region = static_cast<MemoryRegion>(static_cast<int>(current_region) + 1);
929
930
if (current_region != MemoryRegion::Count)
931
current_address = GetMemoryRegionStart(current_region);
932
}
933
934
return std::nullopt;
935
}
936
937
void Bus::AddTTYCharacter(char ch)
938
{
939
if (ch == '\r')
940
{
941
}
942
else if (ch == '\n')
943
{
944
if (!s_tty_line_buffer.empty())
945
{
946
Log::FastWrite(Log::Channel::TTY, Log::Level::Info, Log::Color::StrongBlue, s_tty_line_buffer);
947
#if defined(_DEBUG) || defined(_DEVEL)
948
if (CPU::IsTraceEnabled())
949
CPU::WriteToExecutionLog("TTY: %s\n", s_tty_line_buffer.c_str());
950
#endif
951
}
952
s_tty_line_buffer.clear();
953
}
954
else if (ch != '\0')
955
{
956
s_tty_line_buffer += ch;
957
}
958
}
959
960
void Bus::AddTTYString(std::string_view str)
961
{
962
for (char ch : str)
963
AddTTYCharacter(ch);
964
}
965
966
bool Bus::InjectExecutable(std::span<const u8> buffer, bool set_pc, Error* error)
967
{
968
BIOS::PSEXEHeader header;
969
if (buffer.size() < sizeof(header))
970
{
971
Error::SetStringView(error, "Executable does not contain a header.");
972
return false;
973
}
974
975
std::memcpy(&header, buffer.data(), sizeof(header));
976
if (!BIOS::IsValidPSExeHeader(header, buffer.size()))
977
{
978
Error::SetStringView(error, "Executable does not contain a valid header.");
979
return false;
980
}
981
982
if (header.memfill_size > 0 &&
983
!CPU::SafeZeroMemoryBytes(header.memfill_start & ~UINT32_C(3), Common::AlignDownPow2(header.memfill_size, 4)))
984
{
985
Error::SetStringFmt(error, "Failed to zero {} bytes of memory at address 0x{:08X}.", header.memfill_start,
986
header.memfill_size);
987
return false;
988
}
989
990
const u32 data_load_size =
991
std::min(static_cast<u32>(static_cast<u32>(buffer.size() - sizeof(BIOS::PSEXEHeader))), header.file_size);
992
if (data_load_size > 0)
993
{
994
if (!CPU::SafeWriteMemoryBytes(header.load_address, &buffer[sizeof(header)], data_load_size))
995
{
996
Error::SetStringFmt(error, "Failed to upload {} bytes to memory at address 0x{:08X}.", data_load_size,
997
header.load_address);
998
}
999
}
1000
1001
// patch the BIOS to jump to the executable directly
1002
if (set_pc)
1003
{
1004
const u32 r_pc = header.initial_pc;
1005
const u32 r_gp = header.initial_gp;
1006
const u32 r_sp = header.initial_sp_base + header.initial_sp_offset;
1007
CPU::g_state.regs.gp = r_gp;
1008
if (r_sp != 0)
1009
{
1010
CPU::g_state.regs.sp = r_sp;
1011
CPU::g_state.regs.fp = r_sp;
1012
}
1013
CPU::SetPC(r_pc);
1014
}
1015
1016
return true;
1017
}
1018
1019
bool Bus::InjectCPE(std::span<const u8> buffer, bool set_pc, Error* error)
1020
{
1021
// https://psx-spx.consoledev.net/cdromfileformats/#cdrom-file-psyq-cpe-files-debug-executables
1022
BinarySpanReader reader(buffer);
1023
if (reader.ReadU32() != BIOS::CPE_MAGIC)
1024
{
1025
Error::SetStringView(error, "Invalid CPE signature.");
1026
return false;
1027
}
1028
1029
static constexpr auto set_register = [](u32 reg, u32 value) {
1030
if (reg == 0x90)
1031
{
1032
CPU::SetPC(value);
1033
}
1034
else
1035
{
1036
WARNING_LOG("Ignoring set register 0x{:X} to 0x{:X}", reg, value);
1037
}
1038
};
1039
1040
for (;;)
1041
{
1042
if (!reader.CheckRemaining(1))
1043
{
1044
Error::SetStringView(error, "End of file reached before EOF chunk.");
1045
return false;
1046
}
1047
1048
// Little error checking on chunk sizes, because if any of them run out of buffer,
1049
// it'll loop around and hit the EOF if above.
1050
const u8 chunk = reader.ReadU8();
1051
switch (chunk)
1052
{
1053
case 0x00:
1054
{
1055
// End of file
1056
return true;
1057
}
1058
1059
case 0x01:
1060
{
1061
// Load data
1062
const u32 addr = reader.ReadU32();
1063
const u32 size = reader.ReadU32();
1064
if (size > 0)
1065
{
1066
if (!reader.CheckRemaining(size))
1067
{
1068
Error::SetStringFmt(error, "EOF reached in the middle of load to 0x{:08X}", addr);
1069
return false;
1070
}
1071
1072
if (const auto data = reader.GetRemainingSpan(size); !CPU::SafeWriteMemoryBytes(addr, data))
1073
{
1074
Error::SetStringFmt(error, "Failed to write {} bytes to address 0x{:08X}", size, addr);
1075
return false;
1076
}
1077
1078
reader.IncrementPosition(size);
1079
}
1080
}
1081
break;
1082
1083
case 0x02:
1084
{
1085
// Run address, ignored
1086
DEV_LOG("Ignoring run address 0x{:X}", reader.ReadU32());
1087
}
1088
break;
1089
1090
case 0x03:
1091
{
1092
// Set register 32-bit
1093
const u16 reg = reader.ReadU16();
1094
const u32 value = reader.ReadU32();
1095
set_register(reg, value);
1096
}
1097
break;
1098
1099
case 0x04:
1100
{
1101
// Set register 16-bit
1102
const u16 reg = reader.ReadU16();
1103
const u16 value = reader.ReadU16();
1104
set_register(reg, value);
1105
}
1106
break;
1107
1108
case 0x05:
1109
{
1110
// Set register 8-bit
1111
const u16 reg = reader.ReadU16();
1112
const u8 value = reader.ReadU8();
1113
set_register(reg, value);
1114
}
1115
break;
1116
1117
case 0x06:
1118
{
1119
// Set register 24-bit
1120
const u16 reg = reader.ReadU16();
1121
const u16 low = reader.ReadU16();
1122
const u8 high = reader.ReadU8();
1123
set_register(reg, ZeroExtend32(low) | (ZeroExtend32(high) << 16));
1124
}
1125
break;
1126
1127
case 0x07:
1128
{
1129
// Select workspace
1130
DEV_LOG("Ignoring set workspace 0x{:X}", reader.ReadU32());
1131
}
1132
break;
1133
1134
case 0x08:
1135
{
1136
// Select unit
1137
DEV_LOG("Ignoring select unit 0x{:X}", reader.ReadU8());
1138
}
1139
break;
1140
1141
default:
1142
{
1143
WARNING_LOG("Unknown chunk 0x{:02X} in CPE file, parsing will probably fail now.", chunk);
1144
}
1145
break;
1146
}
1147
}
1148
1149
return true;
1150
}
1151
1152
bool Bus::InjectELF(const ELFFile& elf, bool set_pc, Error* error)
1153
{
1154
const bool okay = elf.LoadExecutableSections(
1155
[](std::span<const u8> data, u32 dest_addr, u32 dest_size, Error* error) {
1156
if (!data.empty() && !CPU::SafeWriteMemoryBytes(dest_addr, data))
1157
{
1158
Error::SetStringFmt(error, "Failed to load {} bytes to 0x{:08X}", data.size(), dest_addr);
1159
return false;
1160
}
1161
1162
const u32 zero_addr = dest_addr + static_cast<u32>(data.size());
1163
const u32 zero_bytes = dest_size - static_cast<u32>(data.size());
1164
if (zero_bytes > 0 && !CPU::SafeZeroMemoryBytes(zero_addr, zero_bytes))
1165
{
1166
Error::SetStringFmt(error, "Failed to zero {} bytes at 0x{:08X}", zero_bytes, zero_addr);
1167
return false;
1168
}
1169
1170
return true;
1171
},
1172
error);
1173
1174
if (okay && set_pc)
1175
CPU::SetPC(elf.GetEntryPoint());
1176
1177
return okay;
1178
}
1179
1180
void Bus::KernelInitializedHook()
1181
{
1182
if (s_kernel_initialize_hook_run)
1183
return;
1184
1185
INFO_LOG("Kernel initialized.");
1186
s_kernel_initialize_hook_run = true;
1187
1188
const System::BootMode boot_mode = System::GetBootMode();
1189
if (boot_mode == System::BootMode::BootEXE || boot_mode == System::BootMode::BootPSF)
1190
{
1191
Error error;
1192
if (((boot_mode == System::BootMode::BootEXE) ? SideloadEXE(System::GetExeOverride(), &error) :
1193
PSFLoader::Load(System::GetExeOverride(), &error)))
1194
{
1195
// Clear all state, since we're blatently overwriting memory.
1196
CPU::CodeCache::Reset();
1197
CPU::ClearICache();
1198
1199
// Stop executing the current block and shell init, and jump straight to the new code.
1200
DebugAssert(!TimingEvents::IsRunningEvents());
1201
CPU::ExitExecution();
1202
}
1203
else
1204
{
1205
// Shut down system on load failure.
1206
Host::ReportErrorAsync("EXE/PSF Load Failed", error.GetDescription());
1207
System::ShutdownSystem(false);
1208
}
1209
}
1210
}
1211
1212
bool Bus::SideloadEXE(const std::string& path, Error* error)
1213
{
1214
std::optional<DynamicHeapArray<u8>> exe_data = FileSystem::ReadBinaryFile(path.c_str(), error);
1215
if (!exe_data.has_value())
1216
{
1217
Error::AddPrefixFmt(error, "Failed to read {}: ", Path::GetFileName(path));
1218
return false;
1219
}
1220
1221
// Stupid Android...
1222
std::string filename = FileSystem::GetDisplayNameFromPath(path);
1223
1224
bool okay = true;
1225
if (StringUtil::EndsWithNoCase(filename, ".cpe"))
1226
{
1227
okay = InjectCPE(exe_data->cspan(), true, error);
1228
}
1229
else if (StringUtil::EndsWithNoCase(filename, ".elf"))
1230
{
1231
ELFFile elf;
1232
if (!elf.Open(std::move(exe_data.value()), error))
1233
return false;
1234
1235
okay = InjectELF(elf, true, error);
1236
}
1237
else
1238
{
1239
// look for a libps.exe next to the exe, if it exists, load it
1240
if (const std::string libps_path = Path::BuildRelativePath(path, "libps.exe");
1241
FileSystem::FileExists(libps_path.c_str()))
1242
{
1243
const std::optional<DynamicHeapArray<u8>> libps_data = FileSystem::ReadBinaryFile(libps_path.c_str(), error);
1244
if (!libps_data.has_value() || !InjectExecutable(libps_data->cspan(), false, error))
1245
{
1246
Error::AddPrefix(error, "Failed to load libps.exe: ");
1247
return false;
1248
}
1249
}
1250
1251
okay = InjectExecutable(exe_data->cspan(), true, error);
1252
}
1253
1254
if (!okay)
1255
{
1256
Error::AddPrefixFmt(error, "Failed to load {}: ", Path::GetFileName(path));
1257
return false;
1258
}
1259
1260
return okay;
1261
}
1262
1263
#define BUS_CYCLES(n) CPU::g_state.pending_ticks += n
1264
1265
// TODO: Move handlers to own files for better inlining.
1266
namespace Bus {
1267
static void ClearHandlers(void** handlers);
1268
static void SetHandlerForRegion(void** handlers, VirtualMemoryAddress address, u32 size,
1269
MemoryReadHandler read_byte_handler, MemoryReadHandler read_halfword_handler,
1270
MemoryReadHandler read_word_handler, MemoryWriteHandler write_byte_handler,
1271
MemoryWriteHandler write_halfword_handler, MemoryWriteHandler write_word_handler);
1272
1273
// clang-format off
1274
template<MemoryAccessSize size> static u32 UnknownReadHandler(VirtualMemoryAddress address);
1275
template<MemoryAccessSize size> static void UnknownWriteHandler(VirtualMemoryAddress address, u32 value);
1276
template<MemoryAccessSize size> static void IgnoreWriteHandler(VirtualMemoryAddress address, u32 value);
1277
template<MemoryAccessSize size> static u32 UnmappedReadHandler(VirtualMemoryAddress address);
1278
template<MemoryAccessSize size> static void UnmappedWriteHandler(VirtualMemoryAddress address, u32 value);
1279
1280
template<MemoryAccessSize size> static u32 RAMReadHandler(VirtualMemoryAddress address);
1281
template<MemoryAccessSize size> static void RAMWriteHandler(VirtualMemoryAddress address, u32 value);
1282
1283
template<MemoryAccessSize size> static u32 BIOSReadHandler(VirtualMemoryAddress address);
1284
1285
template<MemoryAccessSize size> static u32 ScratchpadReadHandler(VirtualMemoryAddress address);
1286
template<MemoryAccessSize size> static void ScratchpadWriteHandler(VirtualMemoryAddress address, u32 value);
1287
1288
template<MemoryAccessSize size> static u32 CacheControlReadHandler(VirtualMemoryAddress address);
1289
template<MemoryAccessSize size> static void CacheControlWriteHandler(VirtualMemoryAddress address, u32 value);
1290
1291
template<MemoryAccessSize size> static u32 ICacheReadHandler(VirtualMemoryAddress address);
1292
template<MemoryAccessSize size> static void ICacheWriteHandler(VirtualMemoryAddress address, u32 value);
1293
1294
template<MemoryAccessSize size> static u32 EXP1ReadHandler(VirtualMemoryAddress address);
1295
template<MemoryAccessSize size> static void EXP1WriteHandler(VirtualMemoryAddress address, u32 value);
1296
template<MemoryAccessSize size> static u32 EXP2ReadHandler(VirtualMemoryAddress address);
1297
template<MemoryAccessSize size> static void EXP2WriteHandler(VirtualMemoryAddress address, u32 value);
1298
template<MemoryAccessSize size> static u32 EXP3ReadHandler(VirtualMemoryAddress address);
1299
template<MemoryAccessSize size> static void EXP3WriteHandler(VirtualMemoryAddress address, u32 value);
1300
template<MemoryAccessSize size> static u32 SIO2ReadHandler(PhysicalMemoryAddress address);
1301
template<MemoryAccessSize size> static void SIO2WriteHandler(PhysicalMemoryAddress address, u32 value);
1302
1303
template<MemoryAccessSize size> static u32 HardwareReadHandler(VirtualMemoryAddress address);
1304
template<MemoryAccessSize size> static void HardwareWriteHandler(VirtualMemoryAddress address, u32 value);
1305
1306
// clang-format on
1307
} // namespace Bus
1308
1309
template<MemoryAccessSize size>
1310
u32 Bus::UnknownReadHandler(VirtualMemoryAddress address)
1311
{
1312
static constexpr const char* sizes[3] = {"byte", "halfword", "word"};
1313
ERROR_LOG("Invalid {} read at address 0x{:08X}, pc 0x{:08X}", sizes[static_cast<u32>(size)], address,
1314
CPU::g_state.pc);
1315
return 0xFFFFFFFFu;
1316
}
1317
1318
template<MemoryAccessSize size>
1319
void Bus::UnknownWriteHandler(VirtualMemoryAddress address, u32 value)
1320
{
1321
static constexpr const char* sizes[3] = {"byte", "halfword", "word"};
1322
ERROR_LOG("Invalid {} write at address 0x{:08X}, value 0x{:08X}, pc 0x{:08X}", sizes[static_cast<u32>(size)], address,
1323
value, CPU::g_state.pc);
1324
CPU::g_state.bus_error = true;
1325
}
1326
1327
template<MemoryAccessSize size>
1328
void Bus::IgnoreWriteHandler(VirtualMemoryAddress address, u32 value)
1329
{
1330
// noop
1331
}
1332
1333
template<MemoryAccessSize size>
1334
u32 Bus::UnmappedReadHandler(VirtualMemoryAddress address)
1335
{
1336
CPU::g_state.bus_error = true;
1337
return UnknownReadHandler<size>(address);
1338
}
1339
1340
template<MemoryAccessSize size>
1341
void Bus::UnmappedWriteHandler(VirtualMemoryAddress address, u32 value)
1342
{
1343
CPU::g_state.bus_error = true;
1344
UnknownWriteHandler<size>(address, value);
1345
}
1346
1347
template<MemoryAccessSize size>
1348
u32 Bus::RAMReadHandler(VirtualMemoryAddress address)
1349
{
1350
BUS_CYCLES(RAM_READ_TICKS);
1351
1352
const u32 offset = address & g_ram_mask;
1353
if constexpr (size == MemoryAccessSize::Byte)
1354
{
1355
return ZeroExtend32(g_ram[offset]);
1356
}
1357
else if constexpr (size == MemoryAccessSize::HalfWord)
1358
{
1359
u16 temp;
1360
std::memcpy(&temp, &g_ram[offset], sizeof(u16));
1361
return ZeroExtend32(temp);
1362
}
1363
else if constexpr (size == MemoryAccessSize::Word)
1364
{
1365
u32 value;
1366
std::memcpy(&value, &g_ram[offset], sizeof(u32));
1367
return value;
1368
}
1369
}
1370
1371
template<MemoryAccessSize size>
1372
void Bus::RAMWriteHandler(VirtualMemoryAddress address, u32 value)
1373
{
1374
const u32 offset = address & g_ram_mask;
1375
1376
if constexpr (size == MemoryAccessSize::Byte)
1377
{
1378
g_ram[offset] = Truncate8(value);
1379
}
1380
else if constexpr (size == MemoryAccessSize::HalfWord)
1381
{
1382
const u16 temp = Truncate16(value);
1383
std::memcpy(&g_ram[offset], &temp, sizeof(u16));
1384
}
1385
else if constexpr (size == MemoryAccessSize::Word)
1386
{
1387
std::memcpy(&g_ram[offset], &value, sizeof(u32));
1388
}
1389
}
1390
1391
template<MemoryAccessSize size>
1392
u32 Bus::BIOSReadHandler(VirtualMemoryAddress address)
1393
{
1394
BUS_CYCLES(g_bios_access_time[static_cast<u32>(size)]);
1395
1396
// TODO: Configurable mirroring.
1397
const u32 offset = address & UINT32_C(0x7FFFF);
1398
if constexpr (size == MemoryAccessSize::Byte)
1399
{
1400
return ZeroExtend32(g_bios[offset]);
1401
}
1402
else if constexpr (size == MemoryAccessSize::HalfWord)
1403
{
1404
u16 temp;
1405
std::memcpy(&temp, &g_bios[offset], sizeof(u16));
1406
return ZeroExtend32(temp);
1407
}
1408
else
1409
{
1410
u32 value;
1411
std::memcpy(&value, &g_bios[offset], sizeof(u32));
1412
return value;
1413
}
1414
}
1415
1416
template<MemoryAccessSize size>
1417
u32 Bus::ScratchpadReadHandler(VirtualMemoryAddress address)
1418
{
1419
const PhysicalMemoryAddress cache_offset = address & MEMORY_LUT_PAGE_MASK;
1420
if (cache_offset >= CPU::SCRATCHPAD_SIZE) [[unlikely]]
1421
return UnknownReadHandler<size>(address);
1422
1423
if constexpr (size == MemoryAccessSize::Byte)
1424
{
1425
return ZeroExtend32(CPU::g_state.scratchpad[cache_offset]);
1426
}
1427
else if constexpr (size == MemoryAccessSize::HalfWord)
1428
{
1429
u16 temp;
1430
std::memcpy(&temp, &CPU::g_state.scratchpad[cache_offset], sizeof(temp));
1431
return ZeroExtend32(temp);
1432
}
1433
else
1434
{
1435
u32 value;
1436
std::memcpy(&value, &CPU::g_state.scratchpad[cache_offset], sizeof(value));
1437
return value;
1438
}
1439
}
1440
1441
template<MemoryAccessSize size>
1442
void Bus::ScratchpadWriteHandler(VirtualMemoryAddress address, u32 value)
1443
{
1444
const PhysicalMemoryAddress cache_offset = address & MEMORY_LUT_PAGE_MASK;
1445
if (cache_offset >= CPU::SCRATCHPAD_SIZE) [[unlikely]]
1446
{
1447
UnknownWriteHandler<size>(address, value);
1448
return;
1449
}
1450
1451
if constexpr (size == MemoryAccessSize::Byte)
1452
CPU::g_state.scratchpad[cache_offset] = Truncate8(value);
1453
else if constexpr (size == MemoryAccessSize::HalfWord)
1454
std::memcpy(&CPU::g_state.scratchpad[cache_offset], &value, sizeof(u16));
1455
else if constexpr (size == MemoryAccessSize::Word)
1456
std::memcpy(&CPU::g_state.scratchpad[cache_offset], &value, sizeof(u32));
1457
}
1458
1459
template<MemoryAccessSize size>
1460
u32 Bus::CacheControlReadHandler(VirtualMemoryAddress address)
1461
{
1462
if (address != 0xFFFE0130)
1463
return UnknownReadHandler<size>(address);
1464
1465
return CPU::g_state.cache_control.bits;
1466
}
1467
1468
template<MemoryAccessSize size>
1469
void Bus::CacheControlWriteHandler(VirtualMemoryAddress address, u32 value)
1470
{
1471
if (address != 0xFFFE0130)
1472
return UnknownWriteHandler<size>(address, value);
1473
1474
DEV_LOG("Cache control <- 0x{:08X}", value);
1475
CPU::g_state.cache_control.bits = value;
1476
}
1477
1478
template<MemoryAccessSize size>
1479
u32 Bus::ICacheReadHandler(VirtualMemoryAddress address)
1480
{
1481
const u32 line = CPU::GetICacheLine(address);
1482
const u32* line_data = &CPU::g_state.icache_data[line * CPU::ICACHE_WORDS_PER_LINE];
1483
const u32 offset = CPU::GetICacheLineOffset(address);
1484
u32 result;
1485
std::memcpy(&result, reinterpret_cast<const u8*>(line_data) + offset, sizeof(result));
1486
return result;
1487
}
1488
1489
template<MemoryAccessSize size>
1490
void Bus::ICacheWriteHandler(VirtualMemoryAddress address, u32 value)
1491
{
1492
const u32 line = CPU::GetICacheLine(address);
1493
u32* line_data = &CPU::g_state.icache_data[line * CPU::ICACHE_WORDS_PER_LINE];
1494
const u32 offset = CPU::GetICacheLineOffset(address);
1495
CPU::g_state.icache_tags[line] = CPU::GetICacheTagForAddress(address) | CPU::ICACHE_INVALID_BITS;
1496
if constexpr (size == MemoryAccessSize::Byte)
1497
std::memcpy(reinterpret_cast<u8*>(line_data) + offset, &value, sizeof(u8));
1498
else if constexpr (size == MemoryAccessSize::HalfWord)
1499
std::memcpy(reinterpret_cast<u8*>(line_data) + offset, &value, sizeof(u16));
1500
else
1501
std::memcpy(reinterpret_cast<u8*>(line_data) + offset, &value, sizeof(u32));
1502
}
1503
1504
template<MemoryAccessSize size>
1505
u32 Bus::EXP1ReadHandler(VirtualMemoryAddress address)
1506
{
1507
BUS_CYCLES(g_exp1_access_time[static_cast<u32>(size)]);
1508
1509
// TODO: auto-increment should be handled elsewhere...
1510
1511
const u32 offset = address & EXP1_MASK;
1512
u32 ret;
1513
1514
if constexpr (size >= MemoryAccessSize::HalfWord)
1515
{
1516
ret = g_pio_device->ReadHandler(offset);
1517
ret |= ZeroExtend32(g_pio_device->ReadHandler(offset + 1)) << 8;
1518
if constexpr (size == MemoryAccessSize::Word)
1519
{
1520
ret |= ZeroExtend32(g_pio_device->ReadHandler(offset + 2)) << 16;
1521
ret |= ZeroExtend32(g_pio_device->ReadHandler(offset + 3)) << 24;
1522
}
1523
}
1524
else
1525
{
1526
ret = ZeroExtend32(g_pio_device->ReadHandler(offset));
1527
}
1528
1529
return ret;
1530
}
1531
1532
template<MemoryAccessSize size>
1533
void Bus::EXP1WriteHandler(VirtualMemoryAddress address, u32 value)
1534
{
1535
// TODO: auto-increment should be handled elsewhere...
1536
1537
const u32 offset = address & EXP1_MASK;
1538
if constexpr (size >= MemoryAccessSize::HalfWord)
1539
{
1540
g_pio_device->WriteHandler(offset, Truncate8(value));
1541
g_pio_device->WriteHandler(offset + 1, Truncate8(value >> 8));
1542
if constexpr (size == MemoryAccessSize::Word)
1543
{
1544
g_pio_device->WriteHandler(offset + 2, Truncate8(value >> 16));
1545
g_pio_device->WriteHandler(offset + 3, Truncate8(value >> 24));
1546
}
1547
}
1548
else
1549
{
1550
g_pio_device->WriteHandler(offset, Truncate8(value));
1551
}
1552
}
1553
1554
template<MemoryAccessSize size>
1555
u32 Bus::EXP2ReadHandler(VirtualMemoryAddress address)
1556
{
1557
BUS_CYCLES(g_exp2_access_time[static_cast<u32>(size)]);
1558
1559
const u32 offset = address & EXP2_MASK;
1560
u32 value;
1561
1562
// rx/tx buffer empty
1563
if (offset == 0x21)
1564
{
1565
value = 0x04 | 0x08;
1566
}
1567
else if (offset >= 0x60 && offset <= 0x67)
1568
{
1569
// nocash expansion area
1570
value = UINT32_C(0xFFFFFFFF);
1571
}
1572
else if (offset == 0x80)
1573
{
1574
// pcsx_present()
1575
value = UINT32_C(0xFFFFFFFF);
1576
}
1577
else
1578
{
1579
WARNING_LOG("EXP2 read: 0x{:08X}", address);
1580
value = UINT32_C(0xFFFFFFFF);
1581
}
1582
1583
return value;
1584
}
1585
1586
template<MemoryAccessSize size>
1587
void Bus::EXP2WriteHandler(VirtualMemoryAddress address, u32 value)
1588
{
1589
const u32 offset = address & EXP2_MASK;
1590
if (offset == 0x23 || offset == 0x80)
1591
{
1592
AddTTYCharacter(static_cast<char>(value));
1593
}
1594
else if (offset == 0x41 || offset == 0x42)
1595
{
1596
const u32 post_code = value & UINT32_C(0x0F);
1597
DEV_LOG("BIOS POST status: {:02X}", post_code);
1598
if (post_code == 0x07)
1599
KernelInitializedHook();
1600
}
1601
else if (offset == 0x70)
1602
{
1603
DEV_LOG("BIOS POST2 status: {:02X}", value & UINT32_C(0x0F));
1604
}
1605
#if 0
1606
// TODO: Put behind configuration variable
1607
else if (offset == 0x81)
1608
{
1609
Log_WarningPrint("pcsx_debugbreak()");
1610
Host::ReportErrorAsync("Error", "pcsx_debugbreak()");
1611
System::PauseSystem(true);
1612
CPU::ExitExecution();
1613
}
1614
else if (offset == 0x82)
1615
{
1616
Log_WarningFmt("pcsx_exit() with status 0x{:02X}", value & UINT32_C(0xFF));
1617
Host::ReportErrorAsync("Error", fmt::format("pcsx_exit() with status 0x{:02X}", value & UINT32_C(0xFF)));
1618
System::ShutdownSystem(false);
1619
CPU::ExitExecution();
1620
}
1621
#endif
1622
else
1623
{
1624
WARNING_LOG("EXP2 write: 0x{:08X} <- 0x{:08X}", address, value);
1625
}
1626
}
1627
1628
template<MemoryAccessSize size>
1629
u32 Bus::EXP3ReadHandler(VirtualMemoryAddress address)
1630
{
1631
WARNING_LOG("EXP3 read: 0x{:08X}", address);
1632
return UINT32_C(0xFFFFFFFF);
1633
}
1634
1635
template<MemoryAccessSize size>
1636
void Bus::EXP3WriteHandler(VirtualMemoryAddress address, u32 value)
1637
{
1638
const u32 offset = address & EXP3_MASK;
1639
if (offset == 0)
1640
{
1641
const u32 post_code = value & UINT32_C(0x0F);
1642
WARNING_LOG("BIOS POST3 status: {:02X}", post_code);
1643
if (post_code == 0x07)
1644
KernelInitializedHook();
1645
}
1646
}
1647
1648
template<MemoryAccessSize size>
1649
u32 Bus::SIO2ReadHandler(PhysicalMemoryAddress address)
1650
{
1651
// Stub for using PS2 BIOS.
1652
if (System::IsUsingKnownPS1BIOS()) [[unlikely]]
1653
{
1654
// Throw exception when not using PS2 BIOS.
1655
return UnmappedReadHandler<size>(address);
1656
}
1657
1658
WARNING_LOG("SIO2 read: 0x{:08X}", address);
1659
return 0;
1660
}
1661
1662
template<MemoryAccessSize size>
1663
void Bus::SIO2WriteHandler(PhysicalMemoryAddress address, u32 value)
1664
{
1665
// Stub for using PS2 BIOS.
1666
if (System::IsUsingKnownPS1BIOS()) [[unlikely]]
1667
{
1668
// Throw exception when not using PS2 BIOS.
1669
UnmappedWriteHandler<size>(address, value);
1670
return;
1671
}
1672
1673
WARNING_LOG("SIO2 write: 0x{:08X} <- 0x{:08X}", address, value);
1674
}
1675
1676
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1677
// HARDWARE HANDLERS
1678
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1679
1680
namespace Bus::HWHandlers {
1681
// clang-format off
1682
template<MemoryAccessSize size> static u32 MemCtrlRead(PhysicalMemoryAddress address);
1683
template<MemoryAccessSize size> static void MemCtrlWrite(PhysicalMemoryAddress address, u32 value);
1684
template<MemoryAccessSize size> static u32 PADRead(PhysicalMemoryAddress address);
1685
template<MemoryAccessSize size> static void PADWrite(PhysicalMemoryAddress address, u32 value);
1686
template<MemoryAccessSize size> static u32 SIORead(PhysicalMemoryAddress address);
1687
template<MemoryAccessSize size> static void SIOWrite(PhysicalMemoryAddress address, u32 value);
1688
template<MemoryAccessSize size> static u32 MemCtrl2Read(PhysicalMemoryAddress address);
1689
template<MemoryAccessSize size> static void MemCtrl2Write(PhysicalMemoryAddress address, u32 value);
1690
template<MemoryAccessSize size> static u32 INTCRead(PhysicalMemoryAddress address);
1691
template<MemoryAccessSize size> static void INTCWrite(PhysicalMemoryAddress address, u32 value);
1692
template<MemoryAccessSize size> static u32 DMARead(PhysicalMemoryAddress address);
1693
template<MemoryAccessSize size> static void DMAWrite(PhysicalMemoryAddress address, u32 value);
1694
template<MemoryAccessSize size> static u32 TimersRead(PhysicalMemoryAddress address);
1695
template<MemoryAccessSize size> static void TimersWrite(PhysicalMemoryAddress address, u32 value);
1696
template<MemoryAccessSize size> static u32 CDROMRead(PhysicalMemoryAddress address);
1697
template<MemoryAccessSize size> static void CDROMWrite(PhysicalMemoryAddress address, u32 value);
1698
template<MemoryAccessSize size> static u32 GPURead(PhysicalMemoryAddress address);
1699
template<MemoryAccessSize size> static void GPUWrite(PhysicalMemoryAddress address, u32 value);
1700
template<MemoryAccessSize size> static u32 MDECRead(PhysicalMemoryAddress address);
1701
template<MemoryAccessSize size> static void MDECWrite(PhysicalMemoryAddress address, u32 value);
1702
template<MemoryAccessSize size> static u32 SPURead(PhysicalMemoryAddress address);
1703
template<MemoryAccessSize size> static void SPUWrite(PhysicalMemoryAddress address, u32 value);
1704
// clang-format on
1705
} // namespace Bus::HWHandlers
1706
1707
template<MemoryAccessSize size>
1708
u32 Bus::HWHandlers::MemCtrlRead(PhysicalMemoryAddress address)
1709
{
1710
const u32 offset = address & MEMCTRL_MASK;
1711
const u32 index = FIXUP_WORD_OFFSET(size, offset) / 4;
1712
if (index >= std::size(s_MEMCTRL.regs)) [[unlikely]]
1713
return 0;
1714
1715
u32 value = s_MEMCTRL.regs[index];
1716
value = FIXUP_WORD_READ_VALUE(size, offset, value);
1717
BUS_CYCLES(2);
1718
return value;
1719
}
1720
1721
template<MemoryAccessSize size>
1722
void Bus::HWHandlers::MemCtrlWrite(PhysicalMemoryAddress address, u32 value)
1723
{
1724
const u32 offset = address & MEMCTRL_MASK;
1725
const u32 index = FIXUP_WORD_OFFSET(size, offset) / 4;
1726
if (index >= std::size(s_MEMCTRL.regs)) [[unlikely]]
1727
return;
1728
1729
value = FIXUP_WORD_WRITE_VALUE(size, offset, value);
1730
1731
const u32 write_mask = (index == 8) ? COMDELAY::WRITE_MASK : MEMDELAY::WRITE_MASK;
1732
const u32 new_value = (s_MEMCTRL.regs[index] & ~write_mask) | (value & write_mask);
1733
if (s_MEMCTRL.regs[index] != new_value)
1734
{
1735
s_MEMCTRL.regs[index] = new_value;
1736
RecalculateMemoryTimings();
1737
}
1738
}
1739
1740
template<MemoryAccessSize size>
1741
u32 Bus::HWHandlers::MemCtrl2Read(PhysicalMemoryAddress address)
1742
{
1743
const u32 offset = address & MEMCTRL2_MASK;
1744
1745
u32 value;
1746
if (offset == 0x00)
1747
{
1748
value = s_RAM_SIZE.bits;
1749
}
1750
else
1751
{
1752
return UnknownReadHandler<size>(address);
1753
}
1754
1755
BUS_CYCLES(2);
1756
return value;
1757
}
1758
1759
template<MemoryAccessSize size>
1760
void Bus::HWHandlers::MemCtrl2Write(PhysicalMemoryAddress address, u32 value)
1761
{
1762
const u32 offset = address & MEMCTRL2_MASK;
1763
1764
if (offset == 0x00)
1765
{
1766
if (s_RAM_SIZE.bits != value)
1767
{
1768
DEV_LOG("RAM size register set to 0x{:08X}", value);
1769
1770
const RAM_SIZE_REG old_ram_size_reg = s_RAM_SIZE;
1771
s_RAM_SIZE.bits = value;
1772
1773
if (s_RAM_SIZE.memory_window != old_ram_size_reg.memory_window)
1774
UpdateMappedRAMSize();
1775
}
1776
}
1777
else
1778
{
1779
return UnknownWriteHandler<size>(address, value);
1780
}
1781
}
1782
1783
template<MemoryAccessSize size>
1784
u32 Bus::HWHandlers::PADRead(PhysicalMemoryAddress address)
1785
{
1786
const u32 offset = address & PAD_MASK;
1787
1788
u32 value = Pad::ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
1789
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value);
1790
BUS_CYCLES(2);
1791
return value;
1792
}
1793
1794
template<MemoryAccessSize size>
1795
void Bus::HWHandlers::PADWrite(PhysicalMemoryAddress address, u32 value)
1796
{
1797
const u32 offset = address & PAD_MASK;
1798
Pad::WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value));
1799
}
1800
1801
template<MemoryAccessSize size>
1802
u32 Bus::HWHandlers::SIORead(PhysicalMemoryAddress address)
1803
{
1804
const u32 offset = address & SIO_MASK;
1805
u32 value = SIO::ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
1806
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value);
1807
BUS_CYCLES(2);
1808
return value;
1809
}
1810
1811
template<MemoryAccessSize size>
1812
void Bus::HWHandlers::SIOWrite(PhysicalMemoryAddress address, u32 value)
1813
{
1814
const u32 offset = address & SIO_MASK;
1815
SIO::WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value));
1816
}
1817
1818
template<MemoryAccessSize size>
1819
u32 Bus::HWHandlers::CDROMRead(PhysicalMemoryAddress address)
1820
{
1821
const u32 offset = address & CDROM_MASK;
1822
1823
u32 value;
1824
switch (size)
1825
{
1826
case MemoryAccessSize::Word:
1827
{
1828
const u32 b0 = ZeroExtend32(CDROM::ReadRegister(offset));
1829
const u32 b1 = ZeroExtend32(CDROM::ReadRegister(offset + 1u));
1830
const u32 b2 = ZeroExtend32(CDROM::ReadRegister(offset + 2u));
1831
const u32 b3 = ZeroExtend32(CDROM::ReadRegister(offset + 3u));
1832
value = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
1833
}
1834
break;
1835
1836
case MemoryAccessSize::HalfWord:
1837
{
1838
const u32 lsb = ZeroExtend32(CDROM::ReadRegister(offset));
1839
const u32 msb = ZeroExtend32(CDROM::ReadRegister(offset + 1u));
1840
value = lsb | (msb << 8);
1841
}
1842
break;
1843
1844
case MemoryAccessSize::Byte:
1845
default:
1846
value = ZeroExtend32(CDROM::ReadRegister(offset));
1847
break;
1848
}
1849
1850
BUS_CYCLES(Bus::g_cdrom_access_time[static_cast<u32>(size)]);
1851
return value;
1852
}
1853
1854
template<MemoryAccessSize size>
1855
void Bus::HWHandlers::CDROMWrite(PhysicalMemoryAddress address, u32 value)
1856
{
1857
const u32 offset = address & CDROM_MASK;
1858
switch (size)
1859
{
1860
case MemoryAccessSize::Word:
1861
{
1862
CDROM::WriteRegister(offset, Truncate8(value & 0xFFu));
1863
CDROM::WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu));
1864
CDROM::WriteRegister(offset + 2u, Truncate8((value >> 16) & 0xFFu));
1865
CDROM::WriteRegister(offset + 3u, Truncate8((value >> 24) & 0xFFu));
1866
}
1867
break;
1868
1869
case MemoryAccessSize::HalfWord:
1870
{
1871
CDROM::WriteRegister(offset, Truncate8(value & 0xFFu));
1872
CDROM::WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu));
1873
}
1874
break;
1875
1876
case MemoryAccessSize::Byte:
1877
default:
1878
CDROM::WriteRegister(offset, Truncate8(value));
1879
break;
1880
}
1881
}
1882
1883
template<MemoryAccessSize size>
1884
u32 Bus::HWHandlers::GPURead(PhysicalMemoryAddress address)
1885
{
1886
const u32 offset = address & GPU_MASK;
1887
u32 value = g_gpu.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
1888
value = FIXUP_WORD_READ_VALUE(size, offset, value);
1889
BUS_CYCLES(2);
1890
return value;
1891
}
1892
1893
template<MemoryAccessSize size>
1894
void Bus::HWHandlers::GPUWrite(PhysicalMemoryAddress address, u32 value)
1895
{
1896
const u32 offset = address & GPU_MASK;
1897
g_gpu.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
1898
}
1899
1900
template<MemoryAccessSize size>
1901
u32 Bus::HWHandlers::MDECRead(PhysicalMemoryAddress address)
1902
{
1903
const u32 offset = address & MDEC_MASK;
1904
u32 value = MDEC::ReadRegister(FIXUP_WORD_OFFSET(size, offset));
1905
value = FIXUP_WORD_READ_VALUE(size, offset, value);
1906
BUS_CYCLES(2);
1907
return value;
1908
}
1909
1910
template<MemoryAccessSize size>
1911
void Bus::HWHandlers::MDECWrite(PhysicalMemoryAddress address, u32 value)
1912
{
1913
const u32 offset = address & MDEC_MASK;
1914
MDEC::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
1915
}
1916
1917
template<MemoryAccessSize size>
1918
u32 Bus::HWHandlers::INTCRead(PhysicalMemoryAddress address)
1919
{
1920
const u32 offset = address & INTERRUPT_CONTROLLER_MASK;
1921
u32 value = InterruptController::ReadRegister(FIXUP_WORD_OFFSET(size, offset));
1922
value = FIXUP_WORD_READ_VALUE(size, offset, value);
1923
BUS_CYCLES(2);
1924
return value;
1925
}
1926
1927
template<MemoryAccessSize size>
1928
void Bus::HWHandlers::INTCWrite(PhysicalMemoryAddress address, u32 value)
1929
{
1930
const u32 offset = address & INTERRUPT_CONTROLLER_MASK;
1931
InterruptController::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
1932
}
1933
1934
template<MemoryAccessSize size>
1935
u32 Bus::HWHandlers::TimersRead(PhysicalMemoryAddress address)
1936
{
1937
const u32 offset = address & TIMERS_MASK;
1938
u32 value = Timers::ReadRegister(FIXUP_WORD_OFFSET(size, offset));
1939
value = FIXUP_WORD_READ_VALUE(size, offset, value);
1940
BUS_CYCLES(2);
1941
return value;
1942
}
1943
1944
template<MemoryAccessSize size>
1945
void Bus::HWHandlers::TimersWrite(PhysicalMemoryAddress address, u32 value)
1946
{
1947
const u32 offset = address & TIMERS_MASK;
1948
Timers::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
1949
}
1950
1951
template<MemoryAccessSize size>
1952
u32 Bus::HWHandlers::SPURead(PhysicalMemoryAddress address)
1953
{
1954
const u32 offset = address & SPU_MASK;
1955
u32 value;
1956
1957
switch (size)
1958
{
1959
case MemoryAccessSize::Word:
1960
{
1961
// 32-bit reads are read as two 16-bit accesses.
1962
const u16 lsb = SPU::ReadRegister(offset);
1963
const u16 msb = SPU::ReadRegister(offset + 2);
1964
value = ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16);
1965
}
1966
break;
1967
1968
case MemoryAccessSize::HalfWord:
1969
{
1970
value = ZeroExtend32(SPU::ReadRegister(offset));
1971
}
1972
break;
1973
1974
case MemoryAccessSize::Byte:
1975
default:
1976
{
1977
const u16 value16 = SPU::ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
1978
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value16);
1979
}
1980
break;
1981
}
1982
1983
BUS_CYCLES(Bus::g_spu_access_time[static_cast<u32>(size)]);
1984
return value;
1985
}
1986
1987
template<MemoryAccessSize size>
1988
void Bus::HWHandlers::SPUWrite(PhysicalMemoryAddress address, u32 value)
1989
{
1990
const u32 offset = address & SPU_MASK;
1991
1992
// 32-bit writes are written as two 16-bit writes.
1993
switch (size)
1994
{
1995
case MemoryAccessSize::Word:
1996
{
1997
DebugAssert(Common::IsAlignedPow2(offset, 2));
1998
SPU::WriteRegister(offset, Truncate16(value));
1999
SPU::WriteRegister(offset + 2, Truncate16(value >> 16));
2000
break;
2001
}
2002
2003
case MemoryAccessSize::HalfWord:
2004
{
2005
DebugAssert(Common::IsAlignedPow2(offset, 2));
2006
SPU::WriteRegister(offset, Truncate16(value));
2007
break;
2008
}
2009
2010
case MemoryAccessSize::Byte:
2011
{
2012
// Byte writes to unaligned addresses are apparently ignored.
2013
if (address & 1)
2014
return;
2015
2016
SPU::WriteRegister(offset, Truncate16(FIXUP_HALFWORD_READ_VALUE(size, offset, value)));
2017
break;
2018
}
2019
}
2020
}
2021
2022
template<MemoryAccessSize size>
2023
u32 Bus::HWHandlers::DMARead(PhysicalMemoryAddress address)
2024
{
2025
const u32 offset = address & DMA_MASK;
2026
u32 value = DMA::ReadRegister(FIXUP_WORD_OFFSET(size, offset));
2027
value = FIXUP_WORD_READ_VALUE(size, offset, value);
2028
BUS_CYCLES(2);
2029
return value;
2030
}
2031
2032
template<MemoryAccessSize size>
2033
void Bus::HWHandlers::DMAWrite(PhysicalMemoryAddress address, u32 value)
2034
{
2035
const u32 offset = address & DMA_MASK;
2036
DMA::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
2037
}
2038
2039
#undef BUS_CYCLES
2040
2041
namespace Bus::HWHandlers {
2042
// We index hardware registers by bits 15..8.
2043
template<MemoryAccessType type, MemoryAccessSize size,
2044
typename RT = std::conditional_t<type == MemoryAccessType::Read, MemoryReadHandler, MemoryWriteHandler>>
2045
static constexpr std::array<RT, 256> GetHardwareRegisterHandlerTable()
2046
{
2047
std::array<RT, 256> ret = {};
2048
for (size_t i = 0; i < ret.size(); i++)
2049
{
2050
if constexpr (type == MemoryAccessType::Read)
2051
ret[i] = UnmappedReadHandler<size>;
2052
else
2053
ret[i] = UnmappedWriteHandler<size>;
2054
}
2055
2056
#if 0
2057
// Verifies no region has >1 handler, but doesn't compile on older GCC.
2058
#define SET(raddr, rsize, read_handler, write_handler) \
2059
static_assert(raddr >= 0x1F801000 && (raddr + rsize) <= 0x1F802000); \
2060
for (u32 taddr = raddr; taddr < (raddr + rsize); taddr += 16) \
2061
{ \
2062
const u32 i = (taddr >> 4) & 0xFFu; \
2063
if constexpr (type == MemoryAccessType::Read) \
2064
ret[i] = (ret[i] == UnmappedReadHandler<size>) ? read_handler<size> : (abort(), read_handler<size>); \
2065
else \
2066
ret[i] = (ret[i] == UnmappedWriteHandler<size>) ? write_handler<size> : (abort(), write_handler<size>); \
2067
}
2068
#else
2069
#define SET(raddr, rsize, read_handler, write_handler) \
2070
static_assert(raddr >= 0x1F801000 && (raddr + rsize) <= 0x1F802000); \
2071
for (u32 taddr = raddr; taddr < (raddr + rsize); taddr += 16) \
2072
{ \
2073
const u32 i = (taddr >> 4) & 0xFFu; \
2074
if constexpr (type == MemoryAccessType::Read) \
2075
ret[i] = read_handler<size>; \
2076
else \
2077
ret[i] = write_handler<size>; \
2078
}
2079
#endif
2080
2081
SET(MEMCTRL_BASE, MEMCTRL_SIZE, MemCtrlRead, MemCtrlWrite);
2082
SET(PAD_BASE, PAD_SIZE, PADRead, PADWrite);
2083
SET(SIO_BASE, SIO_SIZE, SIORead, SIOWrite);
2084
SET(MEMCTRL2_BASE, MEMCTRL2_SIZE, MemCtrl2Read, MemCtrl2Write);
2085
SET(INTC_BASE, INTC_SIZE, INTCRead, INTCWrite);
2086
SET(DMA_BASE, DMA_SIZE, DMARead, DMAWrite);
2087
SET(TIMERS_BASE, TIMERS_SIZE, TimersRead, TimersWrite);
2088
SET(CDROM_BASE, CDROM_SIZE, CDROMRead, CDROMWrite);
2089
SET(GPU_BASE, GPU_SIZE, GPURead, GPUWrite);
2090
SET(MDEC_BASE, MDEC_SIZE, MDECRead, MDECWrite);
2091
SET(SPU_BASE, SPU_SIZE, SPURead, SPUWrite);
2092
2093
#undef SET
2094
2095
return ret;
2096
}
2097
} // namespace Bus::HWHandlers
2098
2099
template<MemoryAccessSize size>
2100
u32 Bus::HardwareReadHandler(VirtualMemoryAddress address)
2101
{
2102
static constexpr const auto table = HWHandlers::GetHardwareRegisterHandlerTable<MemoryAccessType::Read, size>();
2103
const u32 table_index = (address >> 4) & 0xFFu;
2104
return table[table_index](address);
2105
}
2106
2107
template<MemoryAccessSize size>
2108
void Bus::HardwareWriteHandler(VirtualMemoryAddress address, u32 value)
2109
{
2110
static constexpr const auto table = HWHandlers::GetHardwareRegisterHandlerTable<MemoryAccessType::Write, size>();
2111
const u32 table_index = (address >> 4) & 0xFFu;
2112
return table[table_index](address, value);
2113
}
2114
2115
//////////////////////////////////////////////////////////////////////////
2116
2117
static constexpr u32 KUSEG = 0;
2118
static constexpr u32 KSEG0 = 0x80000000U;
2119
static constexpr u32 KSEG1 = 0xA0000000U;
2120
static constexpr u32 KSEG2 = 0xC0000000U;
2121
2122
void Bus::SetHandlers()
2123
{
2124
ClearHandlers(g_memory_handlers);
2125
ClearHandlers(g_memory_handlers_isc);
2126
2127
#define SET(table, start, size, read_handler, write_handler) \
2128
SetHandlerForRegion(table, start, size, read_handler<MemoryAccessSize::Byte>, \
2129
read_handler<MemoryAccessSize::HalfWord>, read_handler<MemoryAccessSize::Word>, \
2130
write_handler<MemoryAccessSize::Byte>, write_handler<MemoryAccessSize::HalfWord>, \
2131
write_handler<MemoryAccessSize::Word>)
2132
#define SETUC(start, size, read_handler, write_handler) \
2133
SET(g_memory_handlers, start, size, read_handler, write_handler); \
2134
SET(g_memory_handlers_isc, start, size, read_handler, write_handler)
2135
2136
// KUSEG - Cached
2137
// Cache isolated appears to affect KUSEG+KSEG0.
2138
SET(g_memory_handlers, KUSEG | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
2139
SET(g_memory_handlers, KUSEG | CPU::SCRATCHPAD_ADDR, 0x1000, ScratchpadReadHandler, ScratchpadWriteHandler);
2140
SET(g_memory_handlers, KUSEG | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
2141
SET(g_memory_handlers, KUSEG | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
2142
SET(g_memory_handlers, KUSEG | HW_BASE, HW_SIZE, HardwareReadHandler, HardwareWriteHandler);
2143
SET(g_memory_handlers, KUSEG | EXP2_BASE, EXP2_SIZE, EXP2ReadHandler, EXP2WriteHandler);
2144
SET(g_memory_handlers, KUSEG | EXP3_BASE, EXP3_SIZE, EXP3ReadHandler, EXP3WriteHandler);
2145
SET(g_memory_handlers, KUSEG | SIO2_BASE, SIO2_SIZE, SIO2ReadHandler, SIO2WriteHandler);
2146
SET(g_memory_handlers_isc, KUSEG, 0x80000000, ICacheReadHandler, ICacheWriteHandler);
2147
2148
// KSEG0 - Cached
2149
SET(g_memory_handlers, KSEG0 | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
2150
SET(g_memory_handlers, KSEG0 | CPU::SCRATCHPAD_ADDR, 0x1000, ScratchpadReadHandler, ScratchpadWriteHandler);
2151
SET(g_memory_handlers, KSEG0 | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
2152
SET(g_memory_handlers, KSEG0 | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
2153
SET(g_memory_handlers, KSEG0 | HW_BASE, HW_SIZE, HardwareReadHandler, HardwareWriteHandler);
2154
SET(g_memory_handlers, KSEG0 | EXP2_BASE, EXP2_SIZE, EXP2ReadHandler, EXP2WriteHandler);
2155
SET(g_memory_handlers, KSEG0 | EXP3_BASE, EXP3_SIZE, EXP3ReadHandler, EXP3WriteHandler);
2156
SET(g_memory_handlers, KSEG0 | SIO2_BASE, SIO2_SIZE, SIO2ReadHandler, SIO2WriteHandler);
2157
SET(g_memory_handlers_isc, KSEG0, 0x20000000, ICacheReadHandler, ICacheWriteHandler);
2158
2159
// KSEG1 - Uncached
2160
SETUC(KSEG1 | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
2161
SETUC(KSEG1 | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
2162
SETUC(KSEG1 | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
2163
SETUC(KSEG1 | HW_BASE, HW_SIZE, HardwareReadHandler, HardwareWriteHandler);
2164
SETUC(KSEG1 | EXP2_BASE, EXP2_SIZE, EXP2ReadHandler, EXP2WriteHandler);
2165
SETUC(KSEG1 | EXP3_BASE, EXP3_SIZE, EXP3ReadHandler, EXP3WriteHandler);
2166
SETUC(KSEG1 | SIO2_BASE, SIO2_SIZE, SIO2ReadHandler, SIO2WriteHandler);
2167
2168
// KSEG2 - Uncached - 0xFFFE0130
2169
SETUC(KSEG2 | 0xFFFE0000, 0x1000, CacheControlReadHandler, CacheControlWriteHandler);
2170
}
2171
2172
void Bus::UpdateMappedRAMSize()
2173
{
2174
const u32 prev_mapped_size = g_ram_mapped_size;
2175
2176
switch (s_RAM_SIZE.memory_window)
2177
{
2178
case 4: // 2MB memory + 6MB unmapped
2179
{
2180
// Used by Rock-Climbing - Mitouhou e no Chousen - Alps Hen (Japan).
2181
// By default, all 8MB is mapped, so we only need to remap the high 6MB.
2182
constexpr u32 MAPPED_SIZE = RAM_2MB_SIZE;
2183
constexpr u32 UNMAPPED_START = RAM_BASE + MAPPED_SIZE;
2184
constexpr u32 UNMAPPED_SIZE = RAM_MIRROR_SIZE - MAPPED_SIZE;
2185
SET(g_memory_handlers, KUSEG | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
2186
SET(g_memory_handlers, KSEG0 | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
2187
SET(g_memory_handlers, KSEG1 | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
2188
g_ram_mapped_size = MAPPED_SIZE;
2189
}
2190
break;
2191
2192
case 0: // 1MB memory + 7MB unmapped
2193
case 1: // 4MB memory + 4MB unmapped
2194
case 2: // 1MB memory + 1MB HighZ + 6MB unmapped
2195
case 3: // 4MB memory + 4MB HighZ
2196
case 6: // 2MB memory + 2MB HighZ + 4MB unmapped
2197
case 7: // 8MB memory
2198
{
2199
// These aren't implemented because nothing is known to use them, so it can't be tested.
2200
// If you find something that does, please let us know.
2201
WARNING_LOG("Unhandled memory window 0x{} (register 0x{:08X}). Please report this game to developers.",
2202
s_RAM_SIZE.memory_window.GetValue(), s_RAM_SIZE.bits);
2203
}
2204
[[fallthrough]];
2205
2206
case 5: // 8MB memory
2207
{
2208
// We only unmap the upper 6MB above, so we only need to remap this as well.
2209
constexpr u32 REMAP_START = RAM_BASE + RAM_2MB_SIZE;
2210
constexpr u32 REMAP_SIZE = RAM_MIRROR_SIZE - RAM_2MB_SIZE;
2211
SET(g_memory_handlers, KUSEG | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
2212
SET(g_memory_handlers, KSEG0 | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
2213
SET(g_memory_handlers, KSEG1 | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
2214
g_ram_mapped_size = RAM_8MB_SIZE;
2215
}
2216
break;
2217
}
2218
2219
// Fastmem needs to be remapped.
2220
if (prev_mapped_size != g_ram_mapped_size)
2221
RemapFastmemViews();
2222
}
2223
2224
#undef SET
2225
#undef SETUC
2226
2227
void Bus::ClearHandlers(void** handlers)
2228
{
2229
for (u32 size = 0; size < 3; size++)
2230
{
2231
MemoryReadHandler* read_handlers =
2232
OffsetHandlerArray<MemoryReadHandler>(handlers, static_cast<MemoryAccessSize>(size), MemoryAccessType::Read);
2233
const MemoryReadHandler read_handler =
2234
(size == 0) ?
2235
UnmappedReadHandler<MemoryAccessSize::Byte> :
2236
((size == 1) ? UnmappedReadHandler<MemoryAccessSize::HalfWord> : UnmappedReadHandler<MemoryAccessSize::Word>);
2237
MemsetPtrs(read_handlers, read_handler, MEMORY_LUT_SIZE);
2238
2239
MemoryWriteHandler* write_handlers =
2240
OffsetHandlerArray<MemoryWriteHandler>(handlers, static_cast<MemoryAccessSize>(size), MemoryAccessType::Write);
2241
const MemoryWriteHandler write_handler =
2242
(size == 0) ?
2243
UnmappedWriteHandler<MemoryAccessSize::Byte> :
2244
((size == 1) ? UnmappedWriteHandler<MemoryAccessSize::HalfWord> : UnmappedWriteHandler<MemoryAccessSize::Word>);
2245
MemsetPtrs(write_handlers, write_handler, MEMORY_LUT_SIZE);
2246
}
2247
}
2248
2249
void Bus::SetHandlerForRegion(void** handlers, VirtualMemoryAddress address, u32 size,
2250
MemoryReadHandler read_byte_handler, MemoryReadHandler read_halfword_handler,
2251
MemoryReadHandler read_word_handler, MemoryWriteHandler write_byte_handler,
2252
MemoryWriteHandler write_halfword_handler, MemoryWriteHandler write_word_handler)
2253
{
2254
// Should be 4K aligned.
2255
DebugAssert(Common::IsAlignedPow2(size, MEMORY_LUT_PAGE_SIZE));
2256
2257
const u32 start_page = (address / MEMORY_LUT_PAGE_SIZE);
2258
const u32 num_pages = ((size + (MEMORY_LUT_PAGE_SIZE - 1)) / MEMORY_LUT_PAGE_SIZE);
2259
2260
for (u32 acc_size = 0; acc_size < 3; acc_size++)
2261
{
2262
MemoryReadHandler* read_handlers =
2263
OffsetHandlerArray<MemoryReadHandler>(handlers, static_cast<MemoryAccessSize>(acc_size), MemoryAccessType::Read) +
2264
start_page;
2265
const MemoryReadHandler read_handler =
2266
(acc_size == 0) ? read_byte_handler : ((acc_size == 1) ? read_halfword_handler : read_word_handler);
2267
#if 0
2268
for (u32 i = 0; i < num_pages; i++)
2269
{
2270
DebugAssert((acc_size == 0 && read_handlers[i] == UnmappedReadHandler<MemoryAccessSize::Byte>) ||
2271
(acc_size == 1 && read_handlers[i] == UnmappedReadHandler<MemoryAccessSize::HalfWord>) ||
2272
(acc_size == 2 && read_handlers[i] == UnmappedReadHandler<MemoryAccessSize::Word>));
2273
2274
read_handlers[i] = read_handler;
2275
}
2276
#else
2277
MemsetPtrs(read_handlers, read_handler, num_pages);
2278
#endif
2279
2280
MemoryWriteHandler* write_handlers = OffsetHandlerArray<MemoryWriteHandler>(
2281
handlers, static_cast<MemoryAccessSize>(acc_size), MemoryAccessType::Write) +
2282
start_page;
2283
const MemoryWriteHandler write_handler =
2284
(acc_size == 0) ? write_byte_handler : ((acc_size == 1) ? write_halfword_handler : write_word_handler);
2285
#if 0
2286
for (u32 i = 0; i < num_pages; i++)
2287
{
2288
DebugAssert((acc_size == 0 && write_handlers[i] == UnmappedWriteHandler<MemoryAccessSize::Byte>) ||
2289
(acc_size == 1 && write_handlers[i] == UnmappedWriteHandler<MemoryAccessSize::HalfWord>) ||
2290
(acc_size == 2 && write_handlers[i] == UnmappedWriteHandler<MemoryAccessSize::Word>));
2291
2292
write_handlers[i] = write_handler;
2293
}
2294
#else
2295
MemsetPtrs(write_handlers, write_handler, num_pages);
2296
#endif
2297
}
2298
}
2299
2300
void** Bus::GetMemoryHandlers(bool isolate_cache, bool swap_caches)
2301
{
2302
if (!isolate_cache)
2303
return g_memory_handlers;
2304
2305
#if defined(_DEBUG) || defined(_DEVEL)
2306
if (swap_caches)
2307
WARNING_LOG("Cache isolated and swapped, icache will be written instead of scratchpad?");
2308
#endif
2309
2310
return g_memory_handlers_isc;
2311
}
2312
2313