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