1 //
2 // Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License version 2 for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // version 2 along with this program; if not, write to the
15 // Free Software Foundation, Inc.,
16 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18
19 #include "channel4.h"
20 #include "../savestate.h"
21 #include <algorithm>
22
toPeriod(unsigned const nr3)23 static unsigned long toPeriod(unsigned const nr3) {
24 unsigned s = (nr3 >> 4) + 3;
25 unsigned r = nr3 & 7;
26
27 if (!r) {
28 r = 1;
29 --s;
30 }
31
32 return r << s;
33 }
34
35 namespace gambatte {
36
Lfsr()37 Channel4::Lfsr::Lfsr()
38 : backupCounter_(counter_disabled)
39 , reg_(0x7FFF)
40 , nr3_(0)
41 , master_(false)
42 {
43 }
44
updateBackupCounter(unsigned long const cc)45 void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
46 if (backupCounter_ <= cc) {
47 unsigned long const period = toPeriod(nr3_);
48 unsigned long periods = (cc - backupCounter_) / period + 1;
49 backupCounter_ += periods * period;
50
51 if (master_ && nr3_ < 0xE0) {
52 if (nr3_ & 8) {
53 while (periods > 6) {
54 unsigned const xored = (reg_ << 1 ^ reg_) & 0x7E;
55 reg_ = (reg_ >> 6 & ~0x7E) | xored | xored << 8;
56 periods -= 6;
57 }
58
59 unsigned const xored = ((reg_ ^ reg_ >> 1) << (7 - periods)) & 0x7F;
60 reg_ = (reg_ >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
61 } else {
62 while (periods > 15) {
63 reg_ = reg_ ^ reg_ >> 1;
64 periods -= 15;
65 }
66
67 reg_ = reg_ >> periods | (((reg_ ^ reg_ >> 1) << (15 - periods)) & 0x7FFF);
68 }
69 }
70 }
71 }
72
reviveCounter(unsigned long cc)73 void Channel4::Lfsr::reviveCounter(unsigned long cc) {
74 updateBackupCounter(cc);
75 counter_ = backupCounter_;
76 }
77
event()78 inline void Channel4::Lfsr::event() {
79 if (nr3_ < 0xE0) {
80 unsigned const shifted = reg_ >> 1;
81 unsigned const xored = (reg_ ^ shifted) & 1;
82 reg_ = shifted | xored << 14;
83
84 if (nr3_ & 8)
85 reg_ = (reg_ & ~0x40) | xored << 6;
86 }
87
88 counter_ += toPeriod(nr3_);
89 backupCounter_ = counter_;
90 }
91
nr3Change(unsigned newNr3,unsigned long cc)92 void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) {
93 updateBackupCounter(cc);
94 nr3_ = newNr3;
95 }
96
nr4Init(unsigned long cc)97 void Channel4::Lfsr::nr4Init(unsigned long cc) {
98 disableMaster();
99 updateBackupCounter(cc);
100 master_ = true;
101 backupCounter_ += 4;
102 counter_ = backupCounter_;
103 }
104
reset(unsigned long cc)105 void Channel4::Lfsr::reset(unsigned long cc) {
106 nr3_ = 0;
107 disableMaster();
108 backupCounter_ = cc + toPeriod(nr3_);
109 }
110
resetCounters(unsigned long oldCc)111 void Channel4::Lfsr::resetCounters(unsigned long oldCc) {
112 updateBackupCounter(oldCc);
113 backupCounter_ -= counter_max;
114 SoundUnit::resetCounters(oldCc);
115 }
116
saveState(SaveState & state,unsigned long cc)117 void Channel4::Lfsr::saveState(SaveState &state, unsigned long cc) {
118 updateBackupCounter(cc);
119 state.spu.ch4.lfsr.counter = backupCounter_;
120 state.spu.ch4.lfsr.reg = reg_;
121 }
122
loadState(SaveState const & state)123 void Channel4::Lfsr::loadState(SaveState const &state) {
124 counter_ = backupCounter_ = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter);
125 reg_ = state.spu.ch4.lfsr.reg;
126 master_ = state.spu.ch4.master;
127 nr3_ = state.mem.ioamhram.get()[0x122];
128 }
129
Channel4()130 Channel4::Channel4()
131 : staticOutputTest_(*this, lfsr_)
132 , disableMaster_(master_, lfsr_)
133 , lengthCounter_(disableMaster_, 0x3F)
134 , envelopeUnit_(staticOutputTest_)
135 , nextEventUnit_(0)
136 , cycleCounter_(0)
137 , soMask_(0)
138 , prevOut_(0)
139 , nr4_(0)
140 , master_(false)
141 {
142 setEvent();
143 }
144
setEvent()145 void Channel4::setEvent() {
146 nextEventUnit_ = &envelopeUnit_;
147 if (lengthCounter_.counter() < nextEventUnit_->counter())
148 nextEventUnit_ = &lengthCounter_;
149 }
150
setNr1(unsigned data)151 void Channel4::setNr1(unsigned data) {
152 lengthCounter_.nr1Change(data, nr4_, cycleCounter_);
153 setEvent();
154 }
155
setNr2(unsigned data)156 void Channel4::setNr2(unsigned data) {
157 if (envelopeUnit_.nr2Change(data))
158 disableMaster_();
159 else
160 staticOutputTest_(cycleCounter_);
161
162 setEvent();
163 }
164
setNr4(unsigned const data)165 void Channel4::setNr4(unsigned const data) {
166 lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
167 nr4_ = data;
168
169 if (data & 0x80) { // init-bit
170 nr4_ &= 0x7F;
171 master_ = !envelopeUnit_.nr4Init(cycleCounter_);
172
173 if (master_)
174 lfsr_.nr4Init(cycleCounter_);
175
176 staticOutputTest_(cycleCounter_);
177 }
178
179 setEvent();
180 }
181
setSo(unsigned long soMask)182 void Channel4::setSo(unsigned long soMask) {
183 soMask_ = soMask;
184 staticOutputTest_(cycleCounter_);
185 setEvent();
186 }
187
reset()188 void Channel4::reset() {
189 // cycleCounter >> 12 & 7 represents the frame sequencer position.
190 cycleCounter_ &= 0xFFF;
191 cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
192
193 lfsr_.reset(cycleCounter_);
194 envelopeUnit_.reset();
195 setEvent();
196 }
197
saveState(SaveState & state)198 void Channel4::saveState(SaveState &state) {
199 lfsr_.saveState(state, cycleCounter_);
200 envelopeUnit_.saveState(state.spu.ch4.env);
201 lengthCounter_.saveState(state.spu.ch4.lcounter);
202
203 state.spu.ch4.nr4 = nr4_;
204 state.spu.ch4.master = master_;
205 }
206
loadState(SaveState const & state)207 void Channel4::loadState(SaveState const &state) {
208 lfsr_.loadState(state);
209 envelopeUnit_.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121],
210 state.spu.cycleCounter);
211 lengthCounter_.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
212
213 cycleCounter_ = state.spu.cycleCounter;
214 nr4_ = state.spu.ch4.nr4;
215 master_ = state.spu.ch4.master;
216 }
217
update(uint_least32_t * buf,unsigned long const soBaseVol,unsigned long cycles)218 void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
219 unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
220 unsigned long const outLow = outBase * (0 - 15ul);
221 unsigned long const endCycles = cycleCounter_ + cycles;
222
223 for (;;) {
224 unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
225 unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
226 unsigned long out = lfsr_.isHighState() ? outHigh : outLow;
227
228 while (lfsr_.counter() <= nextMajorEvent) {
229 *buf += out - prevOut_;
230 prevOut_ = out;
231 buf += lfsr_.counter() - cycleCounter_;
232 cycleCounter_ = lfsr_.counter();
233
234 lfsr_.event();
235 out = lfsr_.isHighState() ? outHigh : outLow;
236 }
237
238 if (cycleCounter_ < nextMajorEvent) {
239 *buf += out - prevOut_;
240 prevOut_ = out;
241 buf += nextMajorEvent - cycleCounter_;
242 cycleCounter_ = nextMajorEvent;
243 }
244
245 if (nextEventUnit_->counter() == nextMajorEvent) {
246 nextEventUnit_->event();
247 setEvent();
248 } else
249 break;
250 }
251
252 if (cycleCounter_ >= SoundUnit::counter_max) {
253 lengthCounter_.resetCounters(cycleCounter_);
254 lfsr_.resetCounters(cycleCounter_);
255 envelopeUnit_.resetCounters(cycleCounter_);
256 cycleCounter_ -= SoundUnit::counter_max;
257 }
258 }
259
260 }
261