-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathppu.hpp
140 lines (114 loc) · 3.78 KB
/
ppu.hpp
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
135
136
137
138
139
140
#pragma once
#include <array>
#include <memory>
#include <cstdint>
#include "util.hpp"
class Ppu{
public:
class Door{
public:
virtual ~Door();
virtual std::uint8_t readPpu(std::uint16_t addr) = 0;
virtual void writePpu(std::uint16_t addr, std::uint8_t value) = 0;
virtual void triggerNmi() = 0;
};
explicit Ppu(const std::shared_ptr<Door>& door);
void hardReset();
void softReset();
bool nmiEnabled() const;
void setSprOver(bool b);
void setSpr0Hit(bool b);
void setVBlank(bool b);
void resetOamAddr();
void reloadAddr();
void startLine();
void doLine(int line, std::uint8_t* buf);
void endLine();
void oamDma(const std::uint8_t buf[0x100]);
std::uint8_t read200x();
std::uint8_t read2002();
std::uint8_t read2004();
std::uint8_t read2007();
void write2000(std::uint8_t value);
void write2001(std::uint8_t value);
void write2002(std::uint8_t value);
void write2003(std::uint8_t value);
void write2004(std::uint8_t value);
void write2005(std::uint8_t value);
void write2006(std::uint8_t value);
void write2007(std::uint8_t value);
std::uint8_t readPltram(std::uint16_t addr) const;
void writePltram(std::uint16_t addr, std::uint8_t value);
private:
std::shared_ptr<Door> door_;
std::array<std::uint8_t, 0x100> oam_;
std::array<std::uint8_t, 0x20> pltram_;
union Ctrl{
std::uint8_t raw;
explicit Ctrl(std::uint8_t value=0) : raw(value) {}
Ctrl& operator=(const Ctrl& rhs) { raw = rhs.raw; return *this; }
BitField8<0,2> nt;
BitField8<2> inc32;
BitField8<3> spr_pat;
BitField8<4> bg_pat;
BitField8<5> spr16;
BitField8<6> slave;
BitField8<7> nmi;
};
Ctrl ctrl_;
union Mask{
std::uint8_t raw;
explicit Mask(std::uint8_t value=0) : raw(value) {}
Mask& operator=(const Mask& rhs) { raw = rhs.raw; return *this; }
BitField8<0> gray;
BitField8<1> bg_noclip;
BitField8<2> spr_noclip;
BitField8<3> bg_on;
BitField8<4> spr_on;
BitField8<5> emp_r;
BitField8<6> emp_g;
BitField8<7> emp_b;
};
Mask mask_;
union Status{
std::uint8_t raw;
explicit Status(std::uint8_t value=0) : raw(value) {}
Status& operator=(const Status& rhs) { raw = rhs.raw; return *this; }
BitField8<0,5> garbage;
BitField8<5> spr_over;
BitField8<6> spr0_hit;
BitField8<7> vbl;
};
Status status_;
std::uint8_t oamAddr_;
// FCEUXの PPUSPL に相当
// http://wiki.nesdev.com/w/index.php/PPU_registers の "OAMADDR
// precautions" の項にあるバグを中途半端に再現しようとしたもの?
std::uint8_t oamAddrLo_;
// http://wiki.nesdev.com/w/index.php/PPU_scrolling
union Addr{
std::uint16_t raw;
explicit Addr(std::uint16_t value=0) : raw(value) {}
Addr& operator=(const Addr& rhs) { raw = rhs.raw; return *this; }
BitField16<0,14> addr;
//-----
BitField16<0,8> addr_lo;
BitField16<8,6> addr_hi;
BitField16<0,5> x_coarse; // タイル単位
BitField16<5,5> y_coarse; // タイル単位
BitField16<10,2> nt;
BitField16<12,3> y_fine; // ピクセル単位
};
Addr regV_;
Addr regT_;
std::uint8_t regX_; // x_fine (ピクセル単位)
bool regW_;
std::uint8_t readBuf_;
std::uint8_t genLatch_;
void renderLine(int line, std::uint8_t* buf);
void renderLineBg(int line, std::uint8_t* buf, bool* opacity);
void renderLineSpr(int line, std::uint8_t* buf, const bool* opacity);
bool checkSpr0(int line);
bool isRenderingOn() const;
std::uint8_t READPLT(int offset) const;
};