Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Nes_Cpu.h
2 views
1
2
// NES 6502 CPU emulator
3
4
// Nes_Emu 0.7.0
5
6
#ifndef NES_CPU_H
7
#define NES_CPU_H
8
9
#include "blargg_common.h"
10
11
typedef long nes_time_t; // clock cycle count
12
typedef unsigned nes_addr_t; // 16-bit address
13
14
class Nes_Cpu {
15
public:
16
typedef BOOST::uint8_t uint8_t;
17
18
// Clear registers, unmap memory, and map code pages to unmapped_page.
19
void reset( void const* unmapped_page = 0 );
20
21
// Map code memory (memory accessed via the program counter). Start and size
22
// must be multiple of page_size.
23
enum { page_bits = 11 };
24
enum { page_count = 0x10000 >> page_bits };
25
enum { page_size = 1L << page_bits };
26
void map_code( nes_addr_t start, unsigned size, void const* code );
27
28
// Access memory as the emulated CPU does.
29
int read( nes_addr_t );
30
void write( nes_addr_t, int data );
31
uint8_t* get_code( nes_addr_t ); // non-const to allow debugger to modify code
32
33
// Push a byte on the stack
34
void push_byte( int );
35
36
// NES 6502 registers. *Not* kept updated during a call to run().
37
struct registers_t {
38
long pc; // more than 16 bits to allow overflow detection
39
BOOST::uint8_t a;
40
BOOST::uint8_t x;
41
BOOST::uint8_t y;
42
BOOST::uint8_t status;
43
BOOST::uint8_t sp;
44
};
45
//registers_t r;
46
47
// Reasons that run() returns
48
enum result_t {
49
result_cycles, // Requested number of cycles (or more) were executed
50
result_sei, // I flag just set and IRQ time would generate IRQ now
51
result_cli, // I flag just cleared but IRQ should occur *after* next instr
52
result_badop // unimplemented/illegal instruction
53
};
54
55
result_t run( nes_time_t end_time );
56
57
nes_time_t time() const { return clock_count; }
58
void reduce_limit( int offset );
59
void set_end_time_( nes_time_t t );
60
void set_irq_time_( nes_time_t t );
61
unsigned long error_count() const { return error_count_; }
62
63
// If PC exceeds 0xFFFF and encounters page_wrap_opcode, it will be silently wrapped.
64
enum { page_wrap_opcode = 0xF2 };
65
66
// One of the many opcodes that are undefined and stop CPU emulation.
67
enum { bad_opcode = 0xD2 };
68
69
void set_tracecb(void (*cb)(unsigned int *dest));
70
71
private:
72
uint8_t const* code_map [page_count + 1];
73
nes_time_t clock_limit;
74
nes_time_t clock_count;
75
nes_time_t irq_time_;
76
nes_time_t end_time_;
77
unsigned long error_count_;
78
79
enum { irq_inhibit = 0x04 };
80
void set_code_page( int, uint8_t const* );
81
void update_clock_limit();
82
83
void (*tracecb)(unsigned int *dest);
84
85
public:
86
registers_t r;
87
88
// low_mem is a full page size so it can be mapped with code_map
89
uint8_t low_mem [page_size > 0x800 ? page_size : 0x800];
90
};
91
92
inline BOOST::uint8_t* Nes_Cpu::get_code( nes_addr_t addr )
93
{
94
return (uint8_t*) code_map [addr >> page_bits] + addr;
95
}
96
97
inline void Nes_Cpu::update_clock_limit()
98
{
99
nes_time_t t = end_time_;
100
if ( t > irq_time_ && !(r.status & irq_inhibit) )
101
t = irq_time_;
102
clock_limit = t;
103
}
104
105
inline void Nes_Cpu::set_end_time_( nes_time_t t )
106
{
107
end_time_ = t;
108
update_clock_limit();
109
}
110
111
inline void Nes_Cpu::set_irq_time_( nes_time_t t )
112
{
113
irq_time_ = t;
114
update_clock_limit();
115
}
116
117
inline void Nes_Cpu::reduce_limit( int offset )
118
{
119
clock_limit -= offset;
120
end_time_ -= offset;
121
irq_time_ -= offset;
122
}
123
124
inline void Nes_Cpu::push_byte( int data )
125
{
126
int sp = r.sp;
127
r.sp = (sp - 1) & 0xFF;
128
low_mem [0x100 + sp] = data;
129
}
130
131
#endif
132
133
134