yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
apu.cc
Go to the documentation of this file.
1#include "app/emu/audio/apu.h"
2
3#include <SDL.h>
4
5#include <cstdint>
6#include <vector>
7
8#include "app/emu/audio/dsp.h"
11
12namespace yaze {
13namespace emu {
14
15static const double apuCyclesPerMaster = (32040 * 32) / (1364 * 262 * 60.0);
16static const double apuCyclesPerMasterPal = (32040 * 32) / (1364 * 312 * 50.0);
17
18static const uint8_t bootRom[0x40] = {
19 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa,
20 0xf4, 0x8f, 0xbb, 0xf5, 0x78, 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19,
21 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5, 0xcb,
22 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, 0x01, 0x10, 0xef, 0x7e,
23 0xf4, 0x10, 0xeb, 0xba, 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4,
24 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff};
25
26void Apu::Init() {
27 ram.resize(0x10000);
28 for (int i = 0; i < 0x10000; i++) {
29 ram[i] = 0;
30 }
31 // Copy the boot rom into the ram at ffc0
32 for (int i = 0; i < 0x40; i++) {
33 ram[0xffc0 + i] = bootRom[i];
34 }
35}
36
37void Apu::Reset() {
38 spc700_.Reset(true);
39 dsp_.Reset();
40 for (int i = 0; i < 0x10000; i++) {
41 ram[i] = 0;
42 }
43 // Copy the boot rom into the ram at ffc0
44 for (int i = 0; i < 0x40; i++) {
45 ram[0xffc0 + i] = bootRom[i];
46 }
47 rom_readable_ = true;
48 dsp_adr_ = 0;
49 cycles_ = 0;
50 std::fill(in_ports_.begin(), in_ports_.end(), 0);
51 std::fill(out_ports_.begin(), out_ports_.end(), 0);
52 for (int i = 0; i < 3; i++) {
53 timer_[i].cycles = 0;
54 timer_[i].divider = 0;
55 timer_[i].target = 0;
56 timer_[i].counter = 0;
57 timer_[i].enabled = false;
58 }
59}
60
61void Apu::RunCycles(uint64_t cycles) {
62 uint64_t sync_to =
63 (uint64_t)cycles *
64 (memory_.pal_timing() ? apuCyclesPerMasterPal : apuCyclesPerMaster);
65
66 while (cycles_ < sync_to) {
67 spc700_.RunOpcode();
68 }
69}
70
71void Apu::Cycle() {
72 if ((cycles_ & 0x1f) == 0) {
73 // every 32 cycles
74 dsp_.Cycle();
75 }
76
77 // handle timers
78 for (int i = 0; i < 3; i++) {
79 if (timer_[i].cycles == 0) {
80 timer_[i].cycles = i == 2 ? 16 : 128;
81 if (timer_[i].enabled) {
82 timer_[i].divider++;
83 if (timer_[i].divider == timer_[i].target) {
84 timer_[i].divider = 0;
85 timer_[i].counter++;
86 timer_[i].counter &= 0xf;
87 }
88 }
89 }
90 timer_[i].cycles--;
91 }
92
93 cycles_++;
94}
95
96uint8_t Apu::Read(uint16_t adr) {
97 switch (adr) {
98 case 0xf0:
99 case 0xf1:
100 case 0xfa:
101 case 0xfb:
102 case 0xfc: {
103 return 0;
104 }
105 case 0xf2: {
106 return dsp_adr_;
107 }
108 case 0xf3: {
109 return dsp_.Read(dsp_adr_ & 0x7f);
110 }
111 case 0xf4:
112 case 0xf5:
113 case 0xf6:
114 case 0xf7:
115 case 0xf8:
116 case 0xf9: {
117 return in_ports_[adr - 0xf4];
118 }
119 case 0xfd:
120 case 0xfe:
121 case 0xff: {
122 uint8_t ret = timer_[adr - 0xfd].counter;
123 timer_[adr - 0xfd].counter = 0;
124 return ret;
125 }
126 }
127 if (rom_readable_ && adr >= 0xffc0) {
128 return bootRom[adr - 0xffc0];
129 }
130 return ram[adr];
131}
132
133void Apu::Write(uint16_t adr, uint8_t val) {
134 switch (adr) {
135 case 0xf0: {
136 break; // test register
137 }
138 case 0xf1: {
139 for (int i = 0; i < 3; i++) {
140 if (!timer_[i].enabled && (val & (1 << i))) {
141 timer_[i].divider = 0;
142 timer_[i].counter = 0;
143 }
144 timer_[i].enabled = val & (1 << i);
145 }
146 if (val & 0x10) {
147 in_ports_[0] = 0;
148 in_ports_[1] = 0;
149 }
150 if (val & 0x20) {
151 in_ports_[2] = 0;
152 in_ports_[3] = 0;
153 }
154 rom_readable_ = val & 0x80;
155 break;
156 }
157 case 0xf2: {
158 dsp_adr_ = val;
159 break;
160 }
161 case 0xf3: {
162 if (dsp_adr_ < 0x80) dsp_.Write(dsp_adr_, val);
163 break;
164 }
165 case 0xf4:
166 case 0xf5:
167 case 0xf6:
168 case 0xf7: {
169 out_ports_[adr - 0xf4] = val;
170 break;
171 }
172 case 0xf8:
173 case 0xf9: {
174 in_ports_[adr - 0xf4] = val;
175 break;
176 }
177 case 0xfa:
178 case 0xfb:
179 case 0xfc: {
180 timer_[adr - 0xfa].target = val;
181 break;
182 }
183 }
184 ram[adr] = val;
185}
186
187uint8_t Apu::SpcRead(uint16_t adr) {
188 Cycle();
189 return Read(adr);
190}
191
192void Apu::SpcWrite(uint16_t adr, uint8_t val) {
193 Cycle();
194 Write(adr, val);
195}
196
197void Apu::SpcIdle(bool waiting) { Cycle(); }
198
199} // namespace emu
200} // namespace yaze
std::array< Timer, 3 > timer_
Definition apu.h:80
uint8_t SpcRead(uint16_t address)
Definition apu.cc:187
uint8_t Read(uint16_t address)
Definition apu.cc:96
uint32_t cycles_
Definition apu.h:77
MemoryImpl & memory_
Definition apu.h:79
void Write(uint16_t address, uint8_t data)
Definition apu.cc:133
void SpcIdle(bool waiting)
Definition apu.cc:197
uint8_t dsp_adr_
Definition apu.h:76
void Init()
Definition apu.cc:26
void Reset()
Definition apu.cc:37
void RunCycles(uint64_t cycles)
Definition apu.cc:61
Spc700 spc700_
Definition apu.h:88
void SpcWrite(uint16_t address, uint8_t data)
Definition apu.cc:192
Dsp dsp_
Definition apu.h:87
std::vector< uint8_t > ram
Definition apu.h:71
std::array< uint8_t, 4 > out_ports_
Definition apu.h:70
bool rom_readable_
Definition apu.h:74
std::array< uint8_t, 6 > in_ports_
Definition apu.h:69
void Cycle()
Definition apu.cc:71
SNES Emulation and debugging tools.
Definition apu.cc:13
Main namespace for the application.
Definition controller.cc:18