1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#include "nes/mapper.hh"
#include "nes/cartridge.hh"
#include <iostream>
namespace nes
{
mapper::mapper(
cartridge& cartridge,
read_cpu_func const read_cpu, write_cpu_func const write_cpu,
read_ppu_func const read_ppu, write_ppu_func const write_ppu)
: cartridge_{ cartridge }
, read_cpu_{ read_cpu }
, write_cpu_{ write_cpu }
, read_ppu_{ read_ppu }
, write_ppu_{ write_ppu }
{
}
auto mapper::select(cartridge& cartridge) -> mapper
{
switch (cartridge.get_mapper_number())
{
case 0x00:
return mapper{
cartridge,
&mapper::nrom_read_cpu, &mapper::nrom_write_cpu,
&mapper::nrom_read_ppu, &mapper::nrom_write_ppu };
default:
std::cerr << "Mapper not implemented: " << std::hex << cartridge.get_mapper_number() << std::endl;
std::abort();
}
}
// -----------------------------------------------------------------------------------------------------------------
// NROM
// -----------------------------------------------------------------------------------------------------------------
auto mapper::nrom_read_cpu(address const addr) -> std::uint8_t
{
if (addr <= address{ 0x5FFF })
{
return 0x0;
}
if (addr <= address{ 0x7FFF })
{
return cartridge_.get_ram()[addr.get_absolute() - 0x6000];
}
if (addr <= address{ 0xBFFF })
{
auto const rel = addr.get_absolute() - 0x8000u;
if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; }
return cartridge_.get_prg_rom()[rel];
}
if (addr <= address{ 0xFFFF })
{
auto rel = addr.get_absolute() - 0xC000u;
if (cartridge_.get_prg_rom_length() > 0x4000) { rel += 0x4000; }
if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; }
return cartridge_.get_prg_rom()[rel];
}
return 0x0;
}
auto mapper::nrom_write_cpu(address const addr, std::uint8_t const value) -> void
{
if (addr <= address{ 0x5FFF })
{
return;
}
if (addr <= address{ 0x7FFF })
{
cartridge_.get_ram_mut()[addr.get_absolute() - 0x6000] = value;
return;
}
}
auto mapper::nrom_read_ppu(address const addr, std::uint8_t const* vram) -> std::uint8_t
{
if (addr <= address{ 0x1FFF })
{
auto const rel = addr.get_absolute();
if (rel >= cartridge_.get_chr_rom_length()) { return 0x0; }
return cartridge_.get_chr_rom()[rel];
}
if (addr <= address{ 0x3EFF })
{
return vram[nrom_mirrored_vram_address(addr)];
}
return 0x0;
}
auto mapper::nrom_write_ppu(address const addr, std::uint8_t* vram, std::uint8_t const value) -> void
{
if (addr <= address{ 0x1FFF })
{
return;
}
if (addr <= address{ 0x3EFF })
{
vram[nrom_mirrored_vram_address(addr)] = value;
return;
}
}
auto mapper::nrom_mirrored_vram_address(address const addr) const -> unsigned
{
auto const rel = addr.get_absolute() % 0x1000u;
switch (cartridge_.get_name_table_arrangement())
{
case name_table_arrangement::horizontal:
// $2000 = $2400, $2800 = $2c00
if (rel <= 0x3FF) { return 0x000u + (rel % 0x400u); }
if (rel <= 0x7FF) { return 0x000u + (rel % 0x400u); }
if (rel <= 0xBFF) { return 0x400u + (rel % 0x400u); }
if (rel <= 0xFFF) { return 0x400u + (rel % 0x400u); }
break;
case name_table_arrangement::vertical:
// $2000 = $2800, $2400 = $2c00
if (rel <= 0x3FF) { return 0x000u + (rel % 0x400u); }
if (rel <= 0x7FF) { return 0x400u + (rel % 0x400u); }
if (rel <= 0xBFF) { return 0x000u + (rel % 0x400u); }
if (rel <= 0xFFF) { return 0x400u + (rel % 0x400u); }
break;
}
return 0;
}
} // namespace nes
|