Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Nes_Ppu.h
2 views
1
2
// NES PPU emulator
3
4
// Nes_Emu 0.7.0
5
6
#ifndef NES_PPU_H
7
#define NES_PPU_H
8
9
#include "Nes_Ppu_Rendering.h"
10
class Nes_Mapper;
11
class Nes_Core;
12
13
typedef long nes_time_t;
14
typedef long ppu_time_t; // ppu_time_t = nes_time_t * ppu_overclock
15
16
ppu_time_t const ppu_overclock = 3; // PPU clocks for each CPU clock
17
18
class Nes_Ppu : public Nes_Ppu_Rendering {
19
typedef Nes_Ppu_Rendering base;
20
public:
21
Nes_Ppu( Nes_Core* );
22
23
// Begin PPU frame and return beginning CPU timestamp
24
nes_time_t begin_frame( ppu_time_t );
25
26
nes_time_t nmi_time() { return nmi_time_; }
27
void acknowledge_nmi() { nmi_time_ = LONG_MAX / 2 + 1; }
28
29
int read_2002( nes_time_t );
30
int read( unsigned addr, nes_time_t );
31
void write( nes_time_t, unsigned addr, int );
32
33
void render_bg_until( nes_time_t );
34
void render_until( nes_time_t );
35
36
// CPU time that frame will have ended by
37
int frame_length() const { return frame_length_; }
38
39
// End frame rendering and return PPU timestamp for next frame
40
ppu_time_t end_frame( nes_time_t );
41
42
// Do direct memory copy to sprite RAM
43
void dma_sprites( nes_time_t, void const* in );
44
45
int burst_phase;
46
47
private:
48
49
Nes_Core& emu;
50
51
enum { indefinite_time = LONG_MAX / 2 + 1 };
52
53
void suspend_rendering();
54
int read_( unsigned addr, nes_time_t ); // note swapped arguments!
55
56
// NES<->PPU time conversion
57
int extra_clocks;
58
ppu_time_t ppu_time( nes_time_t t ) const { return t * ppu_overclock + extra_clocks; }
59
nes_time_t nes_time( ppu_time_t t ) const { return (t - extra_clocks) / ppu_overclock; }
60
61
// frame
62
nes_time_t nmi_time_;
63
int end_vbl_mask;
64
int frame_length_;
65
int frame_length_extra;
66
bool frame_ended;
67
void end_vblank();
68
void run_end_frame( nes_time_t );
69
70
// bg rendering
71
nes_time_t next_bg_time;
72
ppu_time_t scanline_time;
73
ppu_time_t hblank_time;
74
int scanline_count;
75
int frame_phase;
76
void render_bg_until_( nes_time_t );
77
void run_scanlines( int count );
78
79
// sprite rendering
80
ppu_time_t next_sprites_time;
81
int next_sprites_scanline;
82
void render_until_( nes_time_t );
83
84
// $2002 status register
85
nes_time_t next_status_event;
86
void query_until( nes_time_t );
87
88
// sprite hit
89
nes_time_t next_sprite_hit_check;
90
void update_sprite_hit( nes_time_t );
91
92
// open bus decay
93
void update_open_bus( nes_time_t );
94
void poke_open_bus( nes_time_t, int, int mask );
95
const nes_time_t earliest_open_bus_decay() const;
96
97
// sprite max
98
nes_time_t next_sprite_max_run; // doesn't need to run until this time
99
nes_time_t sprite_max_set_time; // if 0, needs to be recalculated
100
int next_sprite_max_scanline;
101
void run_sprite_max_( nes_time_t );
102
void run_sprite_max( nes_time_t );
103
void invalidate_sprite_max_();
104
void invalidate_sprite_max( nes_time_t );
105
106
friend int nes_cpu_read_likely_ppu( class Nes_Core*, unsigned, nes_time_t );
107
};
108
109
inline void Nes_Ppu::suspend_rendering()
110
{
111
next_bg_time = indefinite_time;
112
next_sprites_time = indefinite_time;
113
extra_clocks = 0;
114
}
115
116
inline Nes_Ppu::Nes_Ppu( Nes_Core* e ) : emu( *e )
117
{
118
burst_phase = 0;
119
suspend_rendering();
120
}
121
122
inline void Nes_Ppu::render_until( nes_time_t t )
123
{
124
if ( t > next_sprites_time )
125
render_until_( t );
126
}
127
128
inline void Nes_Ppu::render_bg_until( nes_time_t t )
129
{
130
if ( t > next_bg_time )
131
render_bg_until_( t );
132
}
133
134
inline void Nes_Ppu::update_open_bus( nes_time_t time )
135
{
136
if ( time >= decay_low ) open_bus &= ~0x1F;
137
if ( time >= decay_high ) open_bus &= ~0xE0;
138
}
139
140
#endif
141
142
143