@@ -153,7 +153,125 @@ func TestAPU_SampleGeneration(t *testing.T) {
153153 t .Skip ("Sample generation not implemented yet" )
154154}
155155
156- // TODO: Add tests for trigger behavior
157- func TestAPU_TriggerBehavior (t * testing.T ) {
158- t .Skip ("Trigger behavior not implemented yet" )
156+ func TestAPU_SweepCalculation (t * testing.T ) {
157+ tests := []struct {
158+ name string
159+ shadowFreq uint16
160+ sweepStep uint8
161+ sweepDown bool
162+ wantFreq uint16
163+ wantOverflow bool
164+ }{
165+ {
166+ name : "no shift returns same frequency" ,
167+ shadowFreq : 1024 , sweepStep : 0 , sweepDown : false ,
168+ wantFreq : 1024 , wantOverflow : false ,
169+ },
170+ {
171+ name : "sweep up increases period" ,
172+ shadowFreq : 1024 , sweepStep : 1 , sweepDown : false ,
173+ wantFreq : 1536 , wantOverflow : false , // 1024 + (1024 >> 1)
174+ },
175+ {
176+ name : "sweep down decreases period" ,
177+ shadowFreq : 1024 , sweepStep : 2 , sweepDown : true ,
178+ wantFreq : 768 , wantOverflow : false , // 1024 - (1024 >> 2)
179+ },
180+ {
181+ name : "overflow detection" ,
182+ shadowFreq : 2000 , sweepStep : 3 , sweepDown : false ,
183+ wantFreq : 2250 , wantOverflow : true , // 2000 + (2000 >> 3) = 2250 > 2047
184+ },
185+ }
186+
187+ for _ , tt := range tests {
188+ t .Run (tt .name , func (t * testing.T ) {
189+ ch := & Channel {
190+ shadowFreq : tt .shadowFreq ,
191+ sweepStep : tt .sweepStep ,
192+ sweepDown : tt .sweepDown ,
193+ }
194+ gotFreq , gotOverflow := ch .calculateSweepFrequency ()
195+ assert .Equal (t , tt .wantFreq , gotFreq )
196+ assert .Equal (t , tt .wantOverflow , gotOverflow )
197+ })
198+ }
199+ }
200+
201+ func TestAPU_SweepTrigger (t * testing.T ) {
202+ apu := New ()
203+ apu .WriteRegister (addr .NR52 , 0x80 ) // Enable APU
204+ apu .WriteRegister (addr .NR10 , 0x11 ) // period=1, up, shift=1
205+ apu .WriteRegister (addr .NR13 , 0x00 )
206+ apu .WriteRegister (addr .NR14 , 0x04 ) // Frequency = 0x400
207+ apu .WriteRegister (addr .NR12 , 0xF0 ) // Enable DAC
208+ apu .WriteRegister (addr .NR14 , 0x84 ) // Trigger
209+
210+ assert .True (t , apu .ch [0 ].sweepEnabled )
211+ assert .Equal (t , uint16 (1024 ), apu .ch [0 ].shadowFreq )
212+ assert .Equal (t , uint8 (1 ), apu .ch [0 ].sweepTimer )
213+ assert .True (t , apu .ch [0 ].enabled )
214+ }
215+
216+ func TestAPU_SweepOverflow (t * testing.T ) {
217+ apu := New ()
218+ apu .WriteRegister (addr .NR52 , 0x80 )
219+ apu .WriteRegister (addr .NR10 , 0x01 ) // period=0, up, shift=1
220+ apu .WriteRegister (addr .NR13 , 0xFF )
221+ apu .WriteRegister (addr .NR14 , 0x07 ) // Frequency = 0x7FF (2047)
222+ apu .WriteRegister (addr .NR12 , 0xF0 )
223+ apu .WriteRegister (addr .NR14 , 0x87 ) // Trigger
224+
225+ assert .False (t , apu .ch [0 ].enabled , "Channel should be disabled due to overflow" )
226+ }
227+
228+ func TestAPU_SweepTimer (t * testing.T ) {
229+ apu := New ()
230+ apu .WriteRegister (addr .NR52 , 0x80 )
231+ apu .WriteRegister (addr .NR10 , 0x21 ) // period=2, up, shift=1
232+ apu .WriteRegister (addr .NR13 , 0x00 )
233+ apu .WriteRegister (addr .NR14 , 0x04 ) // Frequency = 0x400
234+ apu .WriteRegister (addr .NR12 , 0xF0 )
235+ apu .WriteRegister (addr .NR14 , 0x84 ) // Trigger
236+
237+ initialFreq := apu .ch [0 ].shadowFreq
238+
239+ apu .tickSweep ()
240+ assert .Equal (t , initialFreq , apu .ch [0 ].shadowFreq , "No change on first tick" )
241+
242+ apu .tickSweep ()
243+ expectedFreq := uint16 (1536 ) // 1024 + 512
244+ assert .Equal (t , expectedFreq , apu .ch [0 ].shadowFreq )
245+ assert .Equal (t , expectedFreq , apu .ch [0 ].period )
246+
247+ reconstructed := uint16 (apu .NR14 & 0x07 )<< 8 | uint16 (apu .NR13 )
248+ assert .Equal (t , expectedFreq , reconstructed , "NR13/NR14 should be updated" )
249+ }
250+
251+ func TestAPU_LengthTimer (t * testing.T ) {
252+ apu := New ()
253+ apu .WriteRegister (addr .NR52 , 0x80 )
254+ apu .WriteRegister (addr .NR12 , 0xF0 )
255+ apu .WriteRegister (addr .NR11 , 0x3F ) // Length timer = 63
256+ apu .WriteRegister (addr .NR14 , 0xC0 ) // Trigger with length enable
257+
258+ assert .Equal (t , uint16 (1 ), apu .ch [0 ].length ) // 64 - 63 = 1
259+ assert .True (t , apu .ch [0 ].enabled )
260+
261+ apu .tickLength ()
262+ assert .False (t , apu .ch [0 ].enabled , "Channel should be disabled after length expires" )
263+ }
264+
265+ func TestAPU_CH3LengthTimer (t * testing.T ) {
266+ apu := New ()
267+ apu .WriteRegister (addr .NR52 , 0x80 )
268+ apu .WriteRegister (addr .NR30 , 0x80 ) // Enable CH3 DAC
269+ apu .WriteRegister (addr .NR31 , 0xFF ) // Length timer = 255
270+ apu .WriteRegister (addr .NR34 , 0xC0 ) // Trigger with length enable
271+
272+ assert .Equal (t , uint16 (1 ), apu .ch [2 ].length ) // 256 - 255 = 1
273+ assert .True (t , apu .ch [2 ].enabled )
274+
275+ apu .tickLength ()
276+ assert .False (t , apu .ch [2 ].enabled , "CH3 should be disabled after length expires" )
159277}
0 commit comments