Subversion Repositories svn.mios

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
44 tk 1
; $Id: sid_se_l.inc 44 2008-01-30 21:39:30Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; Lead Engine
5
;
6
; ==========================================================================
7
;
8
;  Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
9
;  Idea for ENV Curve Parameter and OSC synchronization by Jess D. Skov-Nielsen
10
;  Licensed for personal non-commercial use only.
11
;  All other rights reserved.
12
;
13
; ==========================================================================
14
 
15
 
16
;; --------------------------------------------------------------------------
17
;;  Lead Engine handler called by SIDSE_Handler (sid_se.inc)
18
;; --------------------------------------------------------------------------
19
SIDSE_L_Handler
20
	SET_BSR	SID_BASE		; prepare BSR for SID register access
21
 
22
	;; branch depending on cycle
23
	BRA_IFSET SID_STAT, SID_STAT_SE_CYCLE, ACCESS, SIDSE_L_Handler_Cycle2
24
 
25
SIDSE_L_Handler_Cycle1
26
	bsf	SID_STAT, SID_STAT_SE_CYCLE	; on next handler call we want to process the second cycle
27
 
28
	;; clear "allocated" notification for external AOUTs - flags will be set if X2A function active
29
	clrf	SID_SE_EXT_ALLOCATED, BANKED
30
 
31
 
32
	;; ------------------------------------------------------------------
33
	;; 1st Cycle: LFOs
34
	;; ------------------------------------------------------------------
35
SIDSE_L_HANDLER_LFO_MACRO MACRO patch_base, lfo_base
36
	lfsr	FSR0, patch_base
37
	lfsr	FSR1, lfo_base
38
	call	SIDSE_L_LFO
39
	incf	SID_SE_ELEMENT_NUM, F, BANKED
40
	ENDM
41
 
42
	clrf	SID_SE_ELEMENT_NUM, BANKED
43
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO1_BASE, SID_LFO1_BASE
44
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO2_BASE, SID_LFO2_BASE
45
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO3_BASE, SID_LFO3_BASE
46
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO4_BASE, SID_LFO4_BASE
47
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO5_BASE, SID_LFO5_BASE
48
	SIDSE_L_HANDLER_LFO_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO6_BASE, SID_LFO6_BASE
49
 
50
 
51
	;; ------------------------------------------------------------------
52
	;; 1st Cycle: Envelopes
53
	;; ------------------------------------------------------------------
54
SIDSE_L_HANDLER_ENV_MACRO MACRO patch_base, env_base
55
	lfsr	FSR0, patch_base
56
	lfsr	FSR1, env_base
57
	call	SIDSE_L_ENV
58
	incf	SID_SE_ELEMENT_NUM, F, BANKED
59
	ENDM
60
 
61
	clrf	SID_SE_ELEMENT_NUM, BANKED
62
	SIDSE_L_HANDLER_ENV_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_ENV1_BASE, SID_ENV1_BASE
63
	SIDSE_L_HANDLER_ENV_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_ENV2_BASE, SID_ENV2_BASE
64
 
65
 
66
	;; ------------------------------------------------------------------
67
	;; 1st Cycle: Modulation Matrix
68
	;; ------------------------------------------------------------------
69
 
70
	;; clear modulation targets
71
	movlw	((SID_MOD_TARG_CLEAR_END-SID_MOD_TARG_CLEAR_BEGIN)+1) & 0xff
72
	movwf	IRQ_TMP1
73
	lfsr	FSR0, SID_MOD_TARG_CLEAR_BEGIN
74
SIDSE_L_Handler_ModClearLoop
75
	clrf	POSTINC0
76
	decfsz	IRQ_TMP1, F
77
	rgoto	SIDSE_L_Handler_ModClearLoop
78
 
79
 
80
SIDSE_L_HANDLER_MOD_MACRO MACRO patch_base
81
	lfsr	FSR0, patch_base
82
	call	SIDSE_L_MOD
83
	incf	SID_SE_ELEMENT_NUM, F, BANKED
84
	ENDM
85
 
86
	clrf	SID_SE_ELEMENT_NUM, BANKED
87
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD1_BASE
88
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD2_BASE
89
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD3_BASE
90
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD4_BASE
91
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD5_BASE
92
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD6_BASE
93
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD7_BASE
94
	SIDSE_L_HANDLER_MOD_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_MOD8_BASE
95
 
96
	rgoto	SIDSE_L_Handler_End
97
 
98
 
99
SIDSE_L_Handler_Cycle2
100
	bcf	SID_STAT, SID_STAT_SE_CYCLE	; on next handler call we want to process the first cycle
101
 
102
 
103
	;; ------------------------------------------------------------------
104
	;; 2nd Cycle: Clock Handler
105
	;; ------------------------------------------------------------------
106
	call	SIDSE_Clk
107
 
108
 
109
	;; ------------------------------------------------------------------
110
	;; 2nd Cycle: Wavetable Handler
111
	;; ------------------------------------------------------------------
112
SIDSE_L_HANDLER_WT_MACRO MACRO patch_base, wt_base
113
	lfsr	FSR0, patch_base
114
	lfsr	FSR2, wt_base
115
   	rcall	SIDSE_L_WT
116
	incf	SID_SE_ELEMENT_NUM, F, BANKED
117
	ENDM
118
 
119
	clrf	SID_SE_ELEMENT_NUM, BANKED
120
	SIDSE_L_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_WT1_BASE, SID_WT1_BASE
121
	SIDSE_L_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_WT2_BASE, SID_WT2_BASE
122
	SIDSE_L_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_WT3_BASE, SID_WT3_BASE
123
	SIDSE_L_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_WT4_BASE, SID_WT4_BASE
124
 
125
	;; clear all WT requests
126
	clrf	SID_SE_TRG_EVNT_U, BANKED
127
 
128
 
129
	;; ------------------------------------------------------------------
130
	;; 2nd Cycle: Arp Handler
131
	;; ------------------------------------------------------------------
132
SIDSE_L_HANDLER_ARP_MACRO MACRO patch_base, voice_base, midi_voice_base
133
	lfsr	FSR0, patch_base
134
	lfsr	FSR1, voice_base
135
	lfsr	FSR2, midi_voice_base
136
	call	SIDSE_Arp
137
	incf	SID_SE_ELEMENT_NUM, F, BANKED
138
	ENDM
139
 
140
	clrf	SID_SE_ELEMENT_NUM, BANKED
141
SIDSE_L_Handler_Arp_L
142
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE, SIDL_V1_BASE, SID_MV1_BASE
143
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V2_BASE, SIDL_V2_BASE, SID_MV2_BASE
144
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V3_BASE, SIDL_V3_BASE, SID_MV3_BASE
145
 
146
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
147
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_L_Handler_Arp_NotR
148
SIDSE_L_Handler_Arp_R
149
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V1_BASE, SIDR_V1_BASE, SID_MV4_BASE
150
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V2_BASE, SIDR_V2_BASE, SID_MV5_BASE
151
	SIDSE_L_HANDLER_ARP_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V3_BASE, SIDR_V3_BASE, SID_MV6_BASE
152
SIDSE_L_Handler_Arp_NotR
153
 
154
 
155
	;; ------------------------------------------------------------------
156
	;; 2nd Cycle: check ENV/LFO/Note Sync requests
157
	;; ------------------------------------------------------------------
158
	call	SIDSE_L_Sync
159
 
160
 
161
	;; ------------------------------------------------------------------
162
	;; 2nd Cycle: Voices
163
	;; ------------------------------------------------------------------
164
SIDSE_L_HANDLER_NOTE_MACRO MACRO patch_base, voice_base
165
	lfsr	FSR0, patch_base
166
	lfsr	FSR1, voice_base
167
	rcall	SIDSE_L_Note
168
	incf	SID_SE_ELEMENT_NUM, F, BANKED
169
	ENDM
170
 
171
	clrf	SID_SE_ELEMENT_NUM, BANKED
172
SIDSE_L_Handler_Note_L
173
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE, SIDL_V1_BASE
174
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V2_BASE, SIDL_V2_BASE
175
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V3_BASE, SIDL_V3_BASE
176
 
177
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
178
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_L_Handler_Note_NotR
179
SIDSE_L_Handler_Note_R
180
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V1_BASE, SIDR_V1_BASE
181
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V2_BASE, SIDR_V2_BASE
182
	SIDSE_L_HANDLER_NOTE_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V3_BASE, SIDR_V3_BASE
183
SIDSE_L_Handler_Note_NotR
184
 
185
	;; ------------------------------------------------------------------
186
	;; 2nd Cycle: Filter
187
	;; ------------------------------------------------------------------
188
 
189
SIDSE_L_Handler_Filter_L
190
	clrf	SID_SE_ELEMENT_NUM, BANKED
191
	lfsr	FSR0, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1F_BASE
192
	lfsr	FSR1, SID_MOD_TARG_FIL1_L
193
	lfsr	FSR2, SIDL_BASE
194
	call	SIDSE_Filter
195
 
196
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
197
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_L_Handler_Filter_NotR
198
SIDSE_L_Handler_Filter_R
199
	incf	SID_SE_ELEMENT_NUM, F, BANKED
200
	lfsr	FSR0, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2F_BASE
201
	lfsr	FSR1, SID_MOD_TARG_FIL2_L
202
	lfsr	FSR2, SIDR_BASE
203
	call	SIDSE_Filter
204
SIDSE_L_Handler_Filter_NotR
205
 
206
	;; ------------------------------------------------------------------
207
	;; 2nd Cycle: AOUTs (External/Extensions)
208
	;; ------------------------------------------------------------------
209
SIDSE_L_HANDLER_EXT_MACRO MACRO patch_base, aout_base, mod_base
210
	lfsr	FSR0, patch_base
211
	lfsr	FSR1, aout_base
212
	lfsr	FSR2, mod_base
213
	call	SIDSE_L_EXT
214
	incf	SID_SE_ELEMENT_NUM, F, BANKED
215
	ENDM
216
 
217
	clrf	SID_SE_ELEMENT_NUM, BANKED
218
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR1_L, AOUT0_L, SID_MOD_TARG_EXT1_L
219
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR2_L, AOUT1_L, SID_MOD_TARG_EXT2_L
220
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR3_L, AOUT2_L, SID_MOD_TARG_EXT3_L
221
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR4_L, AOUT3_L, SID_MOD_TARG_EXT4_L
222
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR5_L, AOUT4_L, SID_MOD_TARG_EXT5_L
223
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR6_L, AOUT5_L, SID_MOD_TARG_EXT6_L
224
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR7_L, AOUT6_L, SID_MOD_TARG_EXT7_L
225
	SIDSE_L_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR8_L, AOUT7_L, SID_MOD_TARG_EXT8_L
226
 
227
 
228
	;; ------------------------------------------------------------------
229
	;; 2nd Cycle: External Switches
230
	;; ------------------------------------------------------------------
231
	call	SIDSE_EXT_Switches
232
 
233
 
234
	;; ------------------------------------------------------------------
235
	;; call temporary routine which updates static SID registers
236
	;; ------------------------------------------------------------------
237
 
238
	rcall	SIDSE_L_UpdateStatRegs
239
 
240
 
241
	;; ------------------------------------------------------------------
242
	;; clear FA/FB and FC synch request
243
	;; ------------------------------------------------------------------
244
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED
245
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FB_REQ, BANKED
246
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FC_REQ, BANKED
247
 
248
SIDSE_L_Handler_End
249
	return
250
 
251
 
252
;; --------------------------------------------------------------------------
253
;;  Updates static SID registers
254
;;  (temporary)
255
;; --------------------------------------------------------------------------
256
SIDSE_L_UpdateStatRegs
257
#if ENABLE_SWINSID
258
	;; test for SwinSID phase modulation
259
	SET_BSR	AOUT0_L
260
	swapf	AOUT0_H, W, BANKED
261
	andlw	0xf0
262
	movwf	IRQ_TMP1
263
	swapf	AOUT0_L, W, BANKED
264
	andlw	0x0f
265
	iorwf	IRQ_TMP1, F
266
#endif
267
 
268
SIDSE_UPDATESTAT_MACRO	MACRO p_base, sid_base, swinsid_mode, swinsid_phase
269
	LOCAL	SIDSE_L_UpdateStatRegs_NoADSR
270
 
271
	lfsr	FSR0, p_base
272
 
273
	movlw	0x09
274
	andwf	sid_base + SIDx_V1_CTRL, F, BANKED
275
	movlw	SID_Ix_Vx_WAVEFORM
276
	swapf	PLUSW0, W
277
	andlw	0xf6
278
	btfsc	WREG, 7; ensure that noise will not "lock on" like described in 6581 spec
279
	andlw 0x8f
280
	iorwf	sid_base + SIDx_V1_CTRL, F, BANKED
281
 
282
	;; if ABW (ADSR bug workaround) function active, update ADSR register only when the gate is set
283
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
284
	BRA_IFSET WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_L_UpdateStatRegs_NoADSR
285
	movlw	SID_Ix_Vx_AD
286
	movff	PLUSW0, sid_base + SIDx_V1_ENV_AD
287
	movlw	SID_Ix_Vx_SR
288
	movff	PLUSW0, sid_base + SIDx_V1_ENV_SR
289
SIDSE_L_UpdateStatRegs_NoADSR
290
#if ENABLE_SWINSID
291
	movlw	SID_Ix_Vx_SWINSID_MODE
292
	movff	PLUSW0, swinsid_mode
293
#if 0
294
	movlw	SID_Ix_Vx_SWINSID_PHASE
295
	movff	PLUSW0, swinsid_phase
296
#else
297
	;; test for SwinSID phase modulation
298
	movff	IRQ_TMP1, swinsid_phase
299
#endif
300
#endif
301
	ENDM
302
 
303
	SET_BSR	SIDL_BASE
304
 
305
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE, SIDL_BASE + SIDx_V1_FRQ_L, SIDL_BASE + SIDx_SWINSID_V1_MODE, SIDL_BASE + SIDx_SWINSID_V1_PHASE
306
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V2_BASE, SIDL_BASE + SIDx_V2_FRQ_L, SIDL_BASE + SIDx_SWINSID_V2_MODE, SIDL_BASE + SIDx_SWINSID_V2_PHASE
307
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V3_BASE, SIDL_BASE + SIDx_V3_FRQ_L, SIDL_BASE + SIDx_SWINSID_V3_MODE, SIDL_BASE + SIDx_SWINSID_V3_PHASE
308
 
309
	;; in Mono mode: copy *ALL* SID registers (not only the static ones) over to SIDR
310
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
311
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_L_UpdateStatRegs_Mono
312
SIDSE_L_UpdateStatRegs_Stereo
313
	;; stereo mode:	most SIDs registers already updated, copy over the static ones
314
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V1_BASE, SIDR_BASE + SIDx_V1_FRQ_L, SIDR_BASE + SIDx_SWINSID_V1_MODE, SIDR_BASE + SIDx_SWINSID_V1_PHASE
315
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V2_BASE, SIDR_BASE + SIDx_V2_FRQ_L, SIDR_BASE + SIDx_SWINSID_V2_MODE, SIDR_BASE + SIDx_SWINSID_V2_PHASE
316
	SIDSE_UPDATESTAT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V3_BASE, SIDR_BASE + SIDx_V3_FRQ_L, SIDR_BASE + SIDx_SWINSID_V3_MODE, SIDR_BASE + SIDx_SWINSID_V3_PHASE
317
	rgoto	SIDSE_L_UpdateStatRegs_End
318
 
319
 
320
SIDSE_L_UpdateStatRegs_Mono
321
	;; mono mode: copy over *all* SID registers of SIDL to SIDR
322
	lfsr	FSR1, SIDL_BASE
323
	lfsr	FSR2, SIDR_BASE
324
#if ENABLE_SWINSID
325
	movlw	0x20
326
#else
327
	movlw	SIDx_MODE_VOL+1
328
#endif
329
	movwf	PRODL		; (loop counter)
330
SIDSE_L_UpdateStatRegs_Mono_Loop
331
	movff	POSTINC1, POSTINC2
332
	decfsz	PRODL, F
333
	rgoto	SIDSE_L_UpdateStatRegs_Mono_Loop
334
 
335
SIDSE_L_UpdateStatRegs_End
336
	SET_BSR	SID_BASE
337
	return
338
 
339
 
340
;; --------------------------------------------------------------------------
341
;; This function handles the notes (gate/pitch/PW)
342
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
343
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
344
;;     Voice number in SID_SE_ELEMENT_NUM
345
;; --------------------------------------------------------------------------
346
SIDSE_L_Note
347
	call	SIDSE_Gate	; gate handler
348
	skpz			; returns ZERO flag cleared if pitch should not be changed
349
   	call	SIDSE_Pitch	; pitch handler
350
	goto	SIDSE_PW	; pulsewidth handler
351
 
352
 
353
;; --------------------------------------------------------------------------
354
;; This function handles the wavetables
355
;; IN: pointer to SID_Ix_WTx_BASE in FSR0 (patch record)
356
;;     pointer to SID_WTx_BASE in FSR2 (wt record)
357
;;     WT number in SID_SE_ELEMENT_NUM
358
;; --------------------------------------------------------------------------
359
SIDSE_L_WT
360
	;; if MOD control flag (START[7] set, control position from modulation matrix
361
	movlw	SID_Ix_WTx_BEGIN
362
	BRA_IFCLR PLUSW0, 7, ACCESS, SIDSE_L_WT_NoMOD
363
SIDSE_L_WT_MOD
364
	;; determine range: END-BEGIN+1 -> IRQ_TMP5
365
	;; start value -> IRQ_TMP4 (either END or BEGIN, depending on polarity)
366
	movlw	SID_Ix_WTx_END
367
	movf	PLUSW0, W
368
	andlw	0x7f
369
	movwf	IRQ_TMP5
370
	bcf	IRQ_TMP5, 7
371
	movlw	SID_Ix_WTx_BEGIN
372
	movf	PLUSW0, W
373
	andlw	0x7f
374
	movwf	IRQ_TMP4
375
	subwf	IRQ_TMP5, F
376
	;; n+1 complement if begin greater than end
377
	BRA_IFCLR IRQ_TMP5, 7, ACCESS, SIDSE_L_WT_MOD_NoRngInv
378
SIDSE_L_WT_MOD_RngInv
379
	comf	IRQ_TMP5, F
380
	incf	IRQ_TMP5, F
381
	movlw	SID_Ix_WTx_END
382
	movf	PLUSW0, W
383
	andlw	0x7f
384
	movwf	IRQ_TMP4
385
SIDSE_L_WT_MOD_NoRngInv
386
	incf	IRQ_TMP5, F
387
 
388
	;; determine pointer to modulation target value -> FSR1
389
	movf	SID_SE_ELEMENT_NUM, W, BANKED
390
	addlw	(SID_MOD_TARG_WT1_L-SID_MOD_TARG_BASE)/3
391
	mullw	3
392
	lfsr	FSR1, SID_MOD_TARG_BASE
393
	movf	PRODL, W
394
	addwf	FSR1L, F
395
 
396
	;; convert modulation target value to 8bit absolute value
397
	movff	POSTINC1, IRQ_TMP1
398
	movff	POSTINC1, IRQ_TMP2
399
	movff	POSTINC1, IRQ_TMP3
400
 
401
	movlw	0x80
402
	addwf	IRQ_TMP2, F
403
 
404
	;; saturate
405
	BRA_IFSET IRQ_TMP3, 7, ACCESS, SIDSE_L_WT_MOD_SatNeg
406
SIDSE_L_WT_MOD_SatPos
407
	movf	IRQ_TMP3, W
408
	bnz	SIDSE_L_WT_MOD_SatPos_Sat
409
	bnc	SIDSE_L_WT_MOD_NoSat
410
SIDSE_L_WT_MOD_SatPos_Sat
411
	setf	IRQ_TMP2
412
	rgoto	SIDSE_L_WT_MOD_Sat_Cont
413
SIDSE_L_WT_MOD_SatNeg
414
	comf	IRQ_TMP3, W
415
	bnz	SIDSE_L_WT_MOD_SatNeg_Sat
416
	bc	SIDSE_L_WT_MOD_NoSat
417
SIDSE_L_WT_MOD_SatNeg_Sat
418
	clrf	IRQ_TMP2
419
	;; 	rgoto	SIDSE_L_WT_MOD_Sat_Cont
420
SIDSE_L_WT_MOD_NoSat
421
SIDSE_L_WT_MOD_Sat_Cont
422
 
423
	;; determine position
424
	movf	IRQ_TMP5, W		; range
425
	mulwf	IRQ_TMP2, ACCESS	; modulation value
426
	movf	PRODH, W		; scaled value
427
 	addwf	IRQ_TMP4, F		; add to begin position
428
 
429
	;; play new step if position has been changed
430
	movlw	SID_WTx_POS
431
	movf	PLUSW2, W
432
	xorwf	IRQ_TMP4, W
433
	bz	SIDSE_L_WT_End
434
 
435
	movlw	SID_WTx_POS
436
	movff	IRQ_TMP4, PLUSW2
437
	rgoto	SIDSE_L_WT_PlayStep
438
 
439
 
440
 
441
	;; normal WT mode
442
SIDSE_L_WT_NoMOD
443
	;; clear temporary WT flags
444
	bcf	SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED
445
 
446
	;; check if WT reset requested
447
	movf	SID_SE_ELEMENT_NUM, W, BANKED
448
	addlw	SID_TRG_TARGET_U_W1R
449
	call	MIOS_HLP_GetBitORMask
450
	andwf	SID_SE_TRG_EVNT_U, W, BANKED
451
	bz	SIDSE_L_WT_NoDivReset
452
SIDSE_L_WT_DivReset
453
	;; next clock event will increment div to 0
454
	movlw	SID_WTx_DIV_CTR
455
	setf	PLUSW2
456
	;; next step will increment to start position
457
	movlw	SID_Ix_WTx_BEGIN
458
	movf	PLUSW0, W
459
	andlw	0x7f
460
	addlw	-1
461
	movwf	PRODL
462
	movlw	SID_WTx_POS
463
	movff	PRODL, PLUSW2
464
SIDSE_L_WT_NoDivReset
465
 
466
	;; check for clock sync event
467
	movf	SID_SE_ELEMENT_NUM, W, BANKED
468
	addlw	SID_TRG_TARGET_U_W1S
469
	call	MIOS_HLP_GetBitORMask
470
	andwf	SID_SE_TRG_EVNT_U, W, BANKED
471
	bz	SIDSE_L_WT_NoClk
472
SIDSE_L_WT_Clk
473
	;; increment clock divider
474
	;; reset divider if it already has reached the target value
475
	movlw	SID_WTx_DIV_CTR
476
	incf	PLUSW2, W
477
	movwf	PRODL
478
	bz	SIDSE_L_WT_Clk_Ov
479
 
480
	;; reset once max value is reached
481
	movlw	SID_Ix_WTx_SPEED
482
	movf	PLUSW0, W
483
	andlw	0x3f
484
	cpfsgt	PRODL, ACCESS
485
	rgoto SIDSE_L_WT_Clk_NoOv
486
SIDSE_L_WT_Clk_Ov
487
	clrf	PRODL
488
	;; request next step
489
	bsf	SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED
490
SIDSE_L_WT_Clk_NoOv
491
	;; transfer new divider value into WTx register
492
	movlw	SID_WTx_DIV_CTR
493
	movff	PRODL, PLUSW2
494
SIDSE_L_WT_NoClk
495
 
496
	;; skip if no new step requested
497
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED, SIDSE_L_WT_End
498
 
499
	;; skip if position is 0xaa (notifies oneshot -> WT stopped)
500
	movlw	SID_WTx_POS
501
	movf	PLUSW2, W
502
	xorlw	0xaa
503
	bz	SIDSE_L_WT_End
504
 
505
SIDSE_L_WT_NextStep
506
	;; increment position counter, reset at end position
507
	movlw	SID_WTx_POS
508
	incf	PLUSW2, W
509
	movwf	PRODL
510
	movlw	SID_Ix_WTx_END
511
	movf	PLUSW0, W
512
	andlw	0x7f
513
	cpfsgt	PRODL, ACCESS
514
	rgoto SIDSE_L_WT_NextStep_NoOv
515
SIDSE_L_WT_NextStep_Ov
516
	;; if one-shot mode: set position to 0xaa, WT is stopped now!
517
	movlw	SID_Ix_WTx_LOOP
518
	BRA_IFCLR PLUSW0, 7, ACCESS, SIDSE_L_WT_NextStep_Ov_NoOneShot
519
SIDSE_L_WT_NextStep_Ov_OneShot
520
	movlw	0xaa
521
	movwf	PRODL
522
	movlw	SID_WTx_POS
523
	movff	PRODL, PLUSW2
524
	rgoto	SIDSE_L_WT_End
525
 
526
SIDSE_L_WT_NextStep_Ov_NoOneShot
527
	movlw	SID_Ix_WTx_LOOP
528
	movf	PLUSW0, W
529
	andlw	0x7f
530
	movwf	PRODL
531
SIDSE_L_WT_NextStep_NoOv
532
	;; transfer back to position counter
533
	movlw	SID_WTx_POS
534
	movff	PRODL, PLUSW2
535
 
536
	;; "play" the step
537
	;; (entry point for SIDSE_L_WT_MOD_...)
538
SIDSE_L_WT_PlayStep
539
	;; get pointer to WT value
540
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_WAVETABLE
541
	movlw	SID_WTx_POS
542
	movf	PLUSW2, W
543
	andlw	0x7f
544
	addwf	FSR1L, F
545
 
546
	;; store value in MIOS_PARAMETER1
547
	movff	INDF1, MIOS_PARAMETER1
548
 
549
 
550
	;; forward to MOD matrix
551
	lfsr	FSR2, SID_MOD_SRC_L_WT1_L
552
	clrc
553
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
554
	addwf	FSR2L, F
555
	;; branch depending on absolute (+0000..+7F00) and relative (-8000..+7FFF)
556
	BRA_IFSET MIOS_PARAMETER1, 7, ACCESS, SIDSE_L_WT_PlayStep_ModAbs
557
SIDSE_L_WT_PlayStep_ModRel
558
	;; convert to 15bit signed
559
	clrf	POSTINC2	; SID_MOD_SRC_L_WTx_VALUE_L
560
	clrc
561
	rlf	MIOS_PARAMETER1, W
562
	addlw	-0x80
563
	movwf	POSTDEC2	; SID_MOD_SRC_L_WTx_VALUE_H
564
	rgoto	SIDSE_L_WT_PlayStep_Mod_Cont
565
 
566
SIDSE_L_WT_PlayStep_ModAbs
567
	clrf	POSTINC2	; SID_MOD_SRC_L_WTx_VALUE_L
568
	movf	MIOS_PARAMETER1, W
569
	andlw	0x7f
570
	movwf	POSTDEC2	; SID_MOD_SRC_L_WTx_VALUE_H
571
	;; 	rgoto	SIDSE_L_WT_PlayStep_Mod_Cont
572
SIDSE_L_WT_PlayStep_Mod_Cont
573
 
574
 
575
	;; store SIDs which should be modified in MIOS_PARAMETER3[1:0]
576
	clrf	MIOS_PARAMETER3
577
	movlw	SID_Ix_WTx_SPEED
578
	btfsc	PLUSW0, 6
579
	bsf	MIOS_PARAMETER3, 0
580
	btfsc	PLUSW0, 7
581
	bsf	MIOS_PARAMETER3, 1
582
	;; call WT Parameter Handler
583
	movlw	SID_Ix_WTx_ASSGN
584
	movf	PLUSW0, W
585
	call	SID_PARIN_SetWT
586
 
587
SIDSE_L_WT_End
588
	return
589
 
590
 
591
 
592
;; --------------------------------------------------------------------------
593
;; This function syncs the LFOs/ENVs and Notes
594
;; IN: -
595
;; --------------------------------------------------------------------------
596
SIDSE_L_Sync
597
SIDSE_L_SYNC_ENV_MACRO	MACRO	evnt_a, evnt_a_flag, evnt_r, evnt_r_flag, patch_base, env_base
598
	lfsr	FSR0, patch_base
599
	lfsr	FSR1, env_base
600
	CALL_IFSET evnt_r, evnt_r_flag, BANKED, SIDSE_L_ENV_TrgRelease
601
	bcf	evnt_r, evnt_r_flag, BANKED
602
	CALL_IFSET evnt_a, evnt_a_flag, BANKED, SIDSE_L_ENV_Restart
603
	bcf	evnt_a, evnt_a_flag, BANKED
604
	ENDM
605
 
606
	SIDSE_L_SYNC_ENV_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_E1A, SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_E1R, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_ENV1_BASE, SID_ENV1_BASE
607
	SIDSE_L_SYNC_ENV_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_E2A, SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_E2R, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_ENV2_BASE, SID_ENV2_BASE
608
 
609
 
610
SIDSE_L_SYNC_LFO_MACRO	MACRO	evnt, evnt_flag, patch_base, lfo_base
611
	LOCAL	SIDSE_L_SYNC_LFO_Skip
612
 
613
	BRA_IFCLR evnt, evnt_flag, BANKED, SIDSE_L_SYNC_LFO_Skip
614
	lfsr	FSR0, patch_base
615
	lfsr	FSR1, lfo_base
616
	call	SIDSE_L_LFO_Restart
617
	bcf	evnt, evnt_flag, BANKED
618
SIDSE_L_SYNC_LFO_Skip
619
	incf	SID_SE_ELEMENT_NUM, F, BANKED
620
	ENDM
621
 
622
	clrf	SID_SE_ELEMENT_NUM, BANKED
623
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO1_BASE, SID_LFO1_BASE
624
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L2, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO2_BASE, SID_LFO2_BASE
625
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L3, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO3_BASE, SID_LFO3_BASE
626
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L4, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO4_BASE, SID_LFO4_BASE
627
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L5, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO5_BASE, SID_LFO5_BASE
628
	SIDSE_L_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L6, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_LFO6_BASE, SID_LFO6_BASE
629
 
630
 
631
SIDSE_L_SYNC_NOTE_MACRO	MACRO	evnt, evnt_flag, patch_base, voice_base
632
	LOCAL	SIDSE_L_SYNC_NOTE_Skip
633
 
634
	BRA_IFCLR evnt, evnt_flag, BANKED, SIDSE_L_SYNC_NOTE_Skip
635
	lfsr	FSR0, patch_base
636
	lfsr	FSR1, voice_base
637
	call	SIDSE_L_NOTE_Restart
638
	bcf	evnt, evnt_flag, BANKED
639
SIDSE_L_SYNC_NOTE_Skip
640
	incf	SID_SE_ELEMENT_NUM, F, BANKED
641
	ENDM
642
 
643
	clrf	SID_SE_ELEMENT_NUM, BANKED
644
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O1L, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE, SIDL_V1_BASE
645
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O2L, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V2_BASE, SIDL_V2_BASE
646
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O3L, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V3_BASE, SIDL_V3_BASE
647
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O1R, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V1_BASE, SIDR_V1_BASE
648
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O2R, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V2_BASE, SIDR_V2_BASE
649
	SIDSE_L_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O3R, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S2V3_BASE, SIDR_V3_BASE
650
 
651
	return
652
 
653
 
654
;; --------------------------------------------------------------------------
655
;; This function handles the AOUTs
656
;; IN: pointer to SID_Ix_EXT_PARx_L in FSR0 (patch record)
657
;;     pointer to AOUTx_L in FSR1 (aout target)
658
;;     pointer to SID_MOD_TARG_EXTx_L in FSR2 (modulation value)
659
;;     EXT number in SID_SE_ELEMENT_NUM
660
;; --------------------------------------------------------------------------
661
SIDSE_L_EXT
662
	;; skip if any F2X function has already updated the AOUTx register
663
	movf	SID_SE_ELEMENT_NUM, W, BANKED
664
	call	MIOS_HLP_GetBitORMask
665
	andwf	SID_SE_EXT_ALLOCATED, W, BANKED
666
	bnz	SIDSE_L_EXT_End
667
 
668
	;; store 16bit offset in IRQ_TMP[12]
669
	movff	POSTINC0, IRQ_TMP1
670
	movff	POSTDEC0, IRQ_TMP2
671
 
672
	;; pointer to SID_MOD_TARG_EXTx_L already in FSR2
673
	;; add modulation value to offset
674
	movf	POSTINC2, W
675
	addwf	IRQ_TMP1, F
676
	movf	POSTINC2, W
677
	addwfc	IRQ_TMP2, F
678
 
679
	;; saturate
680
	BRA_IFSET INDF2, 7, ACCESS, SIDSE_L_EXT_Mod_SatNeg
681
SIDSE_L_EXT_Mod_SatPos
682
	movf	INDF2, W
683
	bnz	SIDSE_L_EXT_Mod_SatPos_Sat
684
	bnc	SIDSE_L_EXT_Mod_Sat_NoSat
685
SIDSE_L_EXT_Mod_SatPos_Sat
686
	setf	IRQ_TMP1
687
	setf	IRQ_TMP2
688
	rgoto	SIDSE_L_EXT_Mod_Sat_Cont
689
SIDSE_L_EXT_Mod_SatNeg
690
	comf	INDF2, W
691
	bnz	SIDSE_L_EXT_Mod_SatNeg_Sat
692
	bc	SIDSE_L_EXT_Mod_Sat_NoSat
693
SIDSE_L_EXT_Mod_SatNeg_Sat
694
	clrf	IRQ_TMP1
695
	clrf	IRQ_TMP2
696
	;; 	rgoto	SIDSE_L_EXT_Mod_Sat_Cont
697
SIDSE_L_EXT_Mod_Sat_Cont
698
SIDSE_L_EXT_Mod_Sat_NoSat
699
 
700
	call	SIDSE_Hlp_EXT_AOUT_Transfer
701
 
702
SIDSE_L_EXT_End
703
	return
704
 
705
 
706
 
707
;; --------------------------------------------------------------------------
708
;; This function handles the LFOs (the SIDSE_L_LFO_Restart function restarts a LFO)
709
;; IN: pointer to SID_Ix_LFOx_BASE in FSR0 (patch record)
710
;;     pointer to SID_LFOx_BASE in FSR1
711
;;     LFO number in SID_SE_ELEMENT_NUM
712
;; --------------------------------------------------------------------------
713
SIDSE_L_LFO_Restart
714
	;; if oneshot mode: don't take sync mode into account if we already had a overrun condition
715
	movlw	SID_Ix_LFOx_MODE
716
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_L_LFO_Restart_NoOneShot
717
SIDSE_L_LFO_Restart_OneShot
718
	movf	SID_SE_ELEMENT_NUM, W, BANKED
719
	call	MIOS_HLP_GetBitORMask
720
	andwf	SID_SE_LFO_OVERRUN, W, BANKED
721
	bnz	SIDSE_L_LFO_Restart_OneShot_Cont
722
	;; no overrun occured yet - check for sync
723
SIDSE_L_LFO_Restart_NoOneShot
724
 
725
SIDSE_L_LFO_Restart_OneShot_Cont
726
	;; reset counter (take phase into account)
727
	movlw	0x00
728
	movwf	POSTINC1	; SID_LFOx_CTR_L
729
	movlw	SID_Ix_LFOx_PHASE
730
	movff	PLUSW0, POSTDEC1; SID_LFOx_CTR_H
731
 
732
	;; clear overrun flag (for oneshot mode)
733
	movf	SID_SE_ELEMENT_NUM, W, BANKED
734
	call	MIOS_HLP_GetBitANDMask
735
	andwf	SID_SE_LFO_OVERRUN, F, BANKED
736
 
737
	;; check if LFO should be delayed - set delay counter to 0x0001 in this case, else to 0x0000
738
	movlw	SID_LFOx_DELAY_CTR_H	; high byte always reset to 0
739
	clrf	PLUSW1
740
 
741
	movlw	SID_Ix_LFOx_DELAY
742
	clrf	PRODL			; low byte set to 1 if delay != 0
743
	movf	PLUSW0, W
744
	skpz
745
	incf	PRODL, F
746
	movlw	SID_LFOx_DELAY_CTR_L
747
	movff	PRODL, PLUSW1
748
 
749
	;; continue at waveform calculation
750
	rgoto	SIDSE_L_LFO_Restart_Cont
751
 
752
;; --------------------------------------------------------------------------
753
SIDSE_L_LFO			; normal LFO entry
754
	;; set wave register to initial value and skip LFO if not enabled
755
	movlw	SID_Ix_LFOx_MODE
756
	BRA_IFSET PLUSW0, SID_I_LFO_MODE_ENABLE, ACCESS, SIDSE_L_LFO_Enabled
757
SIDSE_L_LFO_Disabled
758
	lfsr	FSR2, SID_MOD_SRC_L_LFO1_L
759
	clrc
760
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
761
	addwf	FSR2L, F
762
	clrf	POSTINC2	; SID_MOD_SRC_L_LFOx_VALUE_L
763
	clrf	POSTDEC2	; SID_MOD_SRC_L_LFOx_VALUE_H
764
	rgoto	SIDSE_L_LFO_End
765
SIDSE_L_LFO_Enabled
766
 
767
	;; temporary shift FSR1 to SID_LFOx_DELAY_CTR_L for easier handling
768
	movlw	SID_LFOx_DELAY_CTR_L
769
	addwf	FSR1L, F
770
 
771
	;; delay LFO so long 16bit delay counter != 0
772
	movf	POSTINC1, W
773
	iorwf	POSTDEC1, W
774
	bz	SIDSE_L_LFO_NoDelay
775
SIDSE_L_LFO_Delay
776
	;; increment counter, set it to zero on overrun (no delay anymore)
777
	movlw	SID_Ix_LFOx_DELAY
778
	movff	PLUSW0, IRQ_TMP3; incrementer is the same like used for envelopes
779
	movlw	0x80		; curve *must* be disabled!
780
	call	SIDSE_Hlp_ENV_GetBendedValue	; incrementer in MIOS_PARAMETER[12]
781
	movf	MIOS_PARAMETER1, W
782
	addwf	POSTINC1, F
783
	movf	MIOS_PARAMETER2, W
784
	addwfc	POSTDEC1, F
785
	bc	SIDSE_L_LFO_DelayOv
786
	rgoto	SIDSE_L_LFO_End
787
SIDSE_L_LFO_DelayOv
788
	;; overrun: clear counter to disable delay
789
	clrf	POSTINC1
790
	clrf	POSTDEC1
791
SIDSE_L_LFO_NoDelay
792
	movlw	-SID_LFOx_DELAY_CTR_L	; switch back to SID_LFOx_CTR_L
793
	addwf	FSR1L, F
794
 
795
	;; implementation: a LFO is just a 16bit ramp which is mapped to a waveform
796
 
797
	;; clear LFO overrun flag
798
	bcf	SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED
799
 
800
	;; in oneshot mode: check if overrun already occured
801
	movlw	SID_Ix_LFOx_MODE
802
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_L_LFO_NoOneShotChk
803
SIDSE_L_LFO_OneShotChk
804
	movf	SID_SE_ELEMENT_NUM, W, BANKED
805
	call	MIOS_HLP_GetBitORMask
806
	andwf	SID_SE_LFO_OVERRUN, W, BANKED
807
	bz	SIDSE_L_LFO_NoOneShotChk
808
	;; set counter to maximum value and continue at waveform calculation
809
	setf	POSTINC1
810
	setf	POSTDEC1
811
	rgoto	SIDSE_L_LFO_OneShot_Cont
812
SIDSE_L_LFO_NoOneShotChk
813
 
814
	;; if clock sync enabled: only increment on clock events
815
	movlw	SID_Ix_LFOx_MODE
816
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_CLKSYNC, ACCESS, SIDSE_L_LFO_NoClkSync
817
SIDSE_L_LFO_ClkSync
818
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_L_LFO_NoClk_Cont
819
SIDSE_L_LFO_NoClkSync
820
 
821
	;; increment 16bit counter by given rate
822
	movlw	SID_Ix_LFOx_RATE
823
	movff	PLUSW0, IRQ_TMP1
824
 
825
	;; rate can be modulated
826
 
827
	;; calculate pointer to MOD target array -> FSR2
828
	movf	SID_SE_ELEMENT_NUM, W, BANKED
829
	addlw	(SID_MOD_TARG_LR1_L-SID_MOD_TARG_BASE)/3
830
	mullw	3
831
	lfsr	FSR2, SID_MOD_TARG_BASE
832
	movf	PRODL, W
833
	addlw	1		; select SID_MOD_TARG_LRx_H
834
	addwf	FSR2L, F
835
	movf	POSTINC2, W
836
	addwf	IRQ_TMP1, F
837
 
838
	;; saturate
839
	BRA_IFSET INDF2, 7, ACCESS, SIDSE_L_LFO_Rate_SatNeg
840
SIDSE_L_LFO_RateNeg_SatPos
841
	movf	INDF2, W
842
	bnz	SIDSE_L_LFO_RateNeg_SatPos_Sat
843
	bnc	SIDSE_L_LFO_RateNeg_NoSat
844
SIDSE_L_LFO_RateNeg_SatPos_Sat
845
	setf	IRQ_TMP1
846
	rgoto	SIDSE_L_LFO_RateNeg_Sat_Cont
847
SIDSE_L_LFO_Rate_SatNeg
848
	comf	INDF2, W
849
	bnz	SIDSE_L_LFO_Rate_SatNeg_Sat
850
	bc	SIDSE_L_LFO_RateNeg_NoSat
851
SIDSE_L_LFO_Rate_SatNeg_Sat
852
	clrf	IRQ_TMP1
853
	;; 	rgoto	SIDSE_L_LFO_RateNeg_Sat_Cont
854
SIDSE_L_LFO_RateNeg_Sat_Cont
855
SIDSE_L_LFO_RateNeg_NoSat
856
 
857
	;; if LFO synched via clock, replace 245-255 by MIDI clock optimized incrementers
858
	movlw	SID_Ix_LFOx_MODE
859
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_CLKSYNC, ACCESS, SIDSE_L_LFO_Rate_NoClkSync
860
SIDSE_L_LFO_Rate_ClkSync
861
	movf	IRQ_TMP1, W
862
	addlw	-245
863
	bnc	SIDSE_L_LFO_Rate_NoClkSyncValues
864
	TABLE_ADDR_MUL_W SID_LFO_TABLE_MCLK, 2
865
	rgoto	SIDSE_L_LFO_Rate_ClkSync_Cont
866
SIDSE_L_LFO_Rate_NoClkSyncValues
867
SIDSE_L_LFO_Rate_NoClkSync
868
 
869
	movf	IRQ_TMP1, W
870
	TABLE_ADDR_MUL_W SID_LFO_TABLE, 2
871
SIDSE_L_LFO_Rate_ClkSync_Cont
872
	tblrd*+
873
	movf	TABLAT, W
874
	addwf	POSTINC1, F	; SID_LFOx_CTR_L
875
	tblrd*+
876
	movf	TABLAT, W
877
	addwfc	POSTDEC1, F	; SID_LFOx_CTR_H
878
	bnc	SIDSE_L_LFO_NoOverrun
879
 
880
SIDSE_L_LFO_Overrun
881
	;; required for S&H function below, will be cleared with each run
882
	bsf	SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED
883
 
884
	;; propagate overrun to trigger matrix (using FSR2 as working pointer)
885
	movf	SID_SE_ELEMENT_NUM, W, BANKED
886
	mullw	3
887
	lfsr	FSR2, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_L1P_BASE
888
	movf	PRODL, W
889
	addwf	FSR2L, F
890
	movf	POSTINC2, W
891
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
892
	movf	POSTINC2, W
893
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
894
	movf	POSTINC2, W
895
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
896
 
897
	;; required for one-shot mode, will be cleared with next gate trigger
898
	movf	SID_SE_ELEMENT_NUM, W, BANKED
899
	call	MIOS_HLP_GetBitORMask
900
	iorwf	SID_SE_LFO_OVERRUN, F, BANKED
901
 
902
	;; in oneshot mode: ensure that counter is set to maximum value
903
	movlw	SID_Ix_LFOx_MODE
904
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_L_LFO_OverrunNoOneShot
905
SIDSE_L_LFO_OverrunOneShot
906
	setf	POSTINC1
907
	setf	POSTDEC1
908
SIDSE_L_LFO_OverrunNoOneShot
909
SIDSE_L_LFO_NoOverrun
910
 
911
SIDSE_L_LFO_OneShot_Cont		; entry point for oneshot function (if overrun already occured)
912
SIDSE_L_LFO_NoClk_Cont		; entry point for clock sync function (no clock event)
913
SIDSE_L_LFO_Restart_Cont		; entry point for restart function
914
 
915
#if 0
916
	;; DISABLED - for the case that depth is modulated we need to calculate the whole waveform
917
 
918
	;; skip the rest if depth is 0 (no waveform calculation required)
919
	movlw	SID_Ix_LFOx_DEPTH
920
	movf	PLUSW0, W
921
	xorlw	0x80
922
	skpnz
923
	rgoto	SIDSE_L_LFO_Zero
924
#endif
925
 
926
	;; temporary store SID_LFOx_CTR_[LH] in IRQ_TMP[12]
927
	movff	POSTINC1, IRQ_TMP1
928
	movff	POSTDEC1, IRQ_TMP2
929
 
930
	;; map to waveform
931
	;; result in MUL_A_[LH]
932
	movlw	SID_Ix_LFOx_MODE ; waveform selection in bit [6:4]
933
	swapf	PLUSW0, W
934
	BRA_IFSET WREG, 3, ACCESS, SIDSE_L_LFO_Wav89ABCDEF
935
SIDSE_L_LFO_Wav01234567
936
	BRA_IFSET WREG, 2, ACCESS, SIDSE_L_LFO_Wav4567
937
SIDSE_L_LFO_Wav0123
938
	BRA_IFSET WREG, 1, ACCESS, SIDSE_L_LFO_Wav23
939
SIDSE_L_LFO_Wav01
940
	BRA_IFSET WREG, 0, ACCESS, SIDSE_L_LFO_Wav1
941
 
942
	;; ------------------------------------------------------------------
943
SIDSE_L_LFO_Wav0	; Sine
944
	;; sine table contains a quarter of a sine,
945
	;; we have to negate/mirror it depending on the mapped counter value
946
	rlf	IRQ_TMP1, W
947
	rlf	IRQ_TMP2, W
948
	btfsc	IRQ_TMP2, 6
949
	xorlw 0x7f
950
	andlw	0x7f
951
	TABLE_ADDR_MUL_W SID_SIN_TABLE, 2
952
	tblrd*+
953
	movff	TABLAT, MUL_A_L
954
	tblrd*+
955
	movff	TABLAT, MUL_A_H
956
 
957
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_L_LFO_Wav0_NoNeg
958
SIDSE_L_LFO_Wav0_Neg
959
	comf	MUL_A_L, F, BANKED
960
	comf	MUL_A_H, F, BANKED
961
	incf	MUL_A_L, F, BANKED
962
	skpnz
963
	incf	MUL_A_H, F, BANKED
964
SIDSE_L_LFO_Wav0_NoNeg
965
 
966
	rgoto	SIDSE_L_LFO_Wav_Cont
967
 
968
	;; ------------------------------------------------------------------
969
SIDSE_L_LFO_Wav1	; Triangle
970
	;; similar to sine, but linear waveform
971
	clrc
972
	rlf	IRQ_TMP1, W
973
	movwf	MUL_A_L, BANKED
974
	rlf	IRQ_TMP2, W
975
	andlw	0x7f
976
	movwf	MUL_A_H, BANKED
977
 
978
	BRA_IFCLR IRQ_TMP2, 6, ACCESS, SIDSE_L_LFO_Wav1_NoNeg1
979
SIDSE_L_LFO_Wav1_Neg1
980
	comf	MUL_A_L, BANKED
981
	comf	MUL_A_H, BANKED
982
	incf	MUL_A_L, F, BANKED
983
	skpnz
984
	incf	MUL_A_H, F, BANKED
985
	bcf	MUL_A_H, 7, BANKED
986
SIDSE_L_LFO_Wav1_NoNeg1
987
 
988
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_L_LFO_Wav1_NoNeg2
989
SIDSE_L_LFO_Wav1_Neg2
990
	comf	MUL_A_L, F, BANKED
991
	comf	MUL_A_H, F, BANKED
992
	incf	MUL_A_L, F, BANKED
993
	skpnz
994
	incf	MUL_A_H, F, BANKED
995
SIDSE_L_LFO_Wav1_NoNeg2
996
 
997
	rgoto	SIDSE_L_LFO_Wav_Cont
998
 
999
SIDSE_L_LFO_Wav23
1000
	BRA_IFSET WREG, 0, ACCESS, SIDSE_L_LFO_Wav3
1001
	;; ------------------------------------------------------------------
1002
SIDSE_L_LFO_Wav2	; Saw
1003
	;; this one is simple - it's "counter-0x8000"
1004
	movlw	0x00
1005
	subwf	IRQ_TMP1, W
1006
	movwf	MUL_A_L, BANKED
1007
	movlw	0x80
1008
	subwfb	IRQ_TMP2, W
1009
	movwf	MUL_A_H, BANKED
1010
 
1011
	rgoto	SIDSE_L_LFO_Wav_Cont
1012
 
1013
	;; ------------------------------------------------------------------
1014
SIDSE_L_LFO_Wav3	; Pulse
1015
	;; this one is even more simple
1016
	movlw	0x00
1017
	btfsc	IRQ_TMP2, 7
1018
	movlw 0xff
1019
	movwf	MUL_A_L, BANKED
1020
	movlw	0x80
1021
	btfsc	IRQ_TMP2, 7
1022
	movlw 0x7f
1023
	movwf	MUL_A_H, BANKED
1024
 
1025
	rgoto	SIDSE_L_LFO_Wav_Cont
1026
 
1027
SIDSE_L_LFO_Wav4567
1028
	BRA_IFSET WREG, 1, ACCESS, SIDSE_L_LFO_Wav67
1029
SIDSE_L_LFO_Wav45
1030
	BRA_IFSET WREG, 0, ACCESS, SIDSE_L_LFO_Wav5
1031
 
1032
	;; ------------------------------------------------------------------
1033
SIDSE_L_LFO_Wav4	; Random
1034
	;; only on LFO overrun:
1035
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED, SIDSE_L_LFO_End
1036
 
1037
	;; generate new random number and copy it to MUL_A_[LH]
1038
	call	SID_RND_GenRandomNumber
1039
	movff	SID_RANDOM_SEED_L, MUL_A_L
1040
	movff	SID_RANDOM_SEED_L, MUL_A_H
1041
 
1042
	rgoto	SIDSE_L_LFO_Wav_Cont
1043
 
1044
	;; ------------------------------------------------------------------
1045
SIDSE_L_LFO_Wav5	; positive sine
1046
	;; sine table contains a quarter of a sine,
1047
	;; we have to negate/mirror it depending on the mapped counter value
1048
	movf	IRQ_TMP2, W
1049
	btfsc	IRQ_TMP2, 7
1050
	xorlw 0x7f
1051
	andlw	0x7f
1052
	TABLE_ADDR_MUL_W SID_SIN_TABLE, 2
1053
	tblrd*+
1054
	movff	TABLAT, MUL_A_L
1055
	tblrd*+
1056
	movff	TABLAT, MUL_A_H
1057
 
1058
	rgoto	SIDSE_L_LFO_Wav_Cont
1059
 
1060
 
1061
SIDSE_L_LFO_Wav67
1062
	BRA_IFSET WREG, 0, ACCESS, SIDSE_L_LFO_Wav7
1063
 
1064
	;; ------------------------------------------------------------------
1065
SIDSE_L_LFO_Wav6	; positive triangle
1066
	movff	IRQ_TMP1, MUL_A_L
1067
	movff	IRQ_TMP2, MUL_A_H
1068
 
1069
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_L_LFO_Wav6_NoNeg
1070
SIDSE_L_LFO_Wav6_Neg
1071
	comf	MUL_A_L, BANKED
1072
	comf	MUL_A_H, BANKED
1073
	incf	MUL_A_L, F, BANKED
1074
	skpnz
1075
	incf	MUL_A_H, F, BANKED
1076
	bcf	MUL_A_H, 7, BANKED
1077
SIDSE_L_LFO_Wav6_NoNeg
1078
 
1079
	rgoto	SIDSE_L_LFO_Wav_Cont
1080
 
1081
	;; ------------------------------------------------------------------
1082
SIDSE_L_LFO_Wav7	; positive saw
1083
	clrc
1084
	rrf	IRQ_TMP2, W
1085
	movwf	MUL_A_H, BANKED
1086
	rrf	IRQ_TMP1, W
1087
	movwf	MUL_A_L, BANKED
1088
 
1089
	rgoto	SIDSE_L_LFO_Wav_Cont
1090
 
1091
	;; ------------------------------------------------------------------
1092
SIDSE_L_LFO_Wav89ABCDEF	; positive pulse
1093
	movlw	0x00
1094
	btfsc	IRQ_TMP2, 7
1095
	movlw 0xff
1096
	movwf	MUL_A_L, BANKED
1097
	movlw	0x00
1098
	btfsc	IRQ_TMP2, 7
1099
	movlw 0x7f
1100
	movwf	MUL_A_H, BANKED
1101
 
1102
	rgoto	SIDSE_L_LFO_Wav_Cont
1103
 
1104
SIDSE_L_LFO_Wav_Cont
1105
 
1106
	;; scale by LFO depth
1107
	movlw	SID_Ix_LFOx_DEPTH
1108
	movff	PLUSW0, IRQ_TMP1
1109
 
1110
	;; depth can be modulated
1111
	;; calculate pointer to MOD target array -> FSR2
1112
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1113
	addlw	(SID_MOD_TARG_LD1_L-SID_MOD_TARG_BASE)/3
1114
	mullw	3
1115
	lfsr	FSR1, SID_MOD_TARG_BASE
1116
	movf	PRODL, W
1117
	addlw	1		; select SID_MOD_TARG_LDx_H
1118
	addwf	FSR1L, F
1119
	movf	POSTINC1, W
1120
	addwf	IRQ_TMP1, F
1121
 
1122
	;; saturate
1123
	BRA_IFSET INDF1, 7, ACCESS, SIDSE_L_LFO_Depth_SatNeg
1124
SIDSE_L_LFO_DepthNeg_SatPos
1125
	movf	INDF1, W
1126
	bnz	SIDSE_L_LFO_DepthNeg_SatPos_Sat
1127
	bnc	SIDSE_L_LFO_DepthNeg_NoSat
1128
SIDSE_L_LFO_DepthNeg_SatPos_Sat
1129
	setf	IRQ_TMP1
1130
	rgoto	SIDSE_L_LFO_DepthNeg_Sat_Cont
1131
SIDSE_L_LFO_Depth_SatNeg
1132
	comf	INDF1, W
1133
	bnz	SIDSE_L_LFO_Depth_SatNeg_Sat
1134
	bc	SIDSE_L_LFO_DepthNeg_NoSat
1135
SIDSE_L_LFO_Depth_SatNeg_Sat
1136
	clrf	IRQ_TMP1
1137
	;; 	rgoto	SIDSE_L_LFO_DepthNeg_Sat_Cont
1138
SIDSE_L_LFO_DepthNeg_Sat_Cont
1139
SIDSE_L_LFO_DepthNeg_NoSat
1140
	movf	IRQ_TMP1, W
1141
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[12], uses IRQ_TMP1
1142
	rgoto	SIDSE_L_LFO_NotZero
1143
 
1144
SIDSE_L_LFO_Zero
1145
	clrf	MUL_R_1, BANKED
1146
	clrf	MUL_R_2, BANKED
1147
 
1148
SIDSE_L_LFO_NotZero
1149
	;; finally transfer result to SID_MOD_SRC_L_LFO1_[LH]
1150
	;; range: +/- 0x7fff
1151
	lfsr	FSR2, SID_MOD_SRC_L_LFO1_L
1152
	clrc
1153
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
1154
	addwf	FSR2L, F
1155
	movff	MUL_R_1, POSTINC2
1156
	movff	MUL_R_2, POSTDEC2
1157
 
1158
SIDSE_L_LFO_End
1159
	return
1160
 
1161
 
1162
;; --------------------------------------------------------------------------
1163
;; This function handles the Envelopes
1164
;; IN: pointer to SID_Ix_L_ENVx_BASE in FSR0 (patch record)
1165
;;     pointer to SID_ENVx_BASE in FSR1
1166
;;     ENV number in SID_SE_ELEMENT_NUM
1167
;; --------------------------------------------------------------------------
1168
SIDSE_L_ENV
1169
	;; if clock sync enabled: only increment on clock events
1170
	movlw	SID_Ix_L_ENVx_MODE
1171
	BRA_IFCLR PLUSW0, SID_I_ENV_MODE_CLKSYNC, ACCESS, SIDSE_L_ENV_NoClkSync
1172
SIDSE_L_ENV_ClkSync
1173
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_L_ENV_ClkSync_Cont
1174
	;; transfer current ENV counter into MIOS_PARAMETER[12]
1175
	movff	POSTINC1, MIOS_PARAMETER1
1176
	movff	POSTDEC1, MIOS_PARAMETER2
1177
	rgoto	SIDSE_L_ENV_Cont
1178
SIDSE_L_ENV_NoClkSync
1179
SIDSE_L_ENV_ClkSync_Cont
1180
 
1181
	;; branch depending on EG state
1182
	movlw	SID_ENVx_STATE
1183
	BRA_IFSET PLUSW1, SID_ENV_STATE_RELEASE2, ACCESS, SIDSE_L_ENV_Release2
1184
	BRA_IFSET PLUSW1, SID_ENV_STATE_RELEASE1, ACCESS, SIDSE_L_ENV_Release1
1185
	BRA_IFCLR PLUSW1, SID_ENV_STATE_ATTACK1, ACCESS, SIDSE_L_ENV_End
1186
	BRA_IFSET PLUSW1, SID_ENV_STATE_SUSTAIN, ACCESS, SIDSE_L_ENV_Sustain
1187
	BRA_IFSET PLUSW1, SID_ENV_STATE_DECAY2, ACCESS, SIDSE_L_ENV_Decay2
1188
	BRA_IFSET PLUSW1, SID_ENV_STATE_DECAY1, ACCESS, SIDSE_L_ENV_Decay1
1189
	BRA_IFSET PLUSW1, SID_ENV_STATE_ATTACK2, ACCESS, SIDSE_L_ENV_Attack2
1190
 
1191
SIDSE_L_ENV_Attack1
1192
 
1193
	;; temporary shift FSR1 to SID_ENVx_DELAY_CTR_L for easier handling
1194
	movlw	SID_ENVx_DELAY_CTR_L
1195
	addwf	FSR1L, F
1196
 
1197
	;; delay ENV so long 16bit delay counter != 0
1198
	movf	POSTINC1, W
1199
	iorwf	POSTDEC1, W
1200
	bz	SIDSE_L_ENV_Attack1_NoDelay
1201
SIDSE_L_ENV_Attack1_Delay
1202
	;; increment counter, set it to zero on overrun (no delay anymore)
1203
	movlw	SID_Ix_L_ENVx_DELAY
1204
	movff	PLUSW0, IRQ_TMP3; incrementer is the same like used for envelopes
1205
	movlw	0x80		; curve *must* be disabled!
1206
	call	SIDSE_Hlp_ENV_GetBendedValue	; incrementer in MIOS_PARAMETER[12]
1207
	movf	MIOS_PARAMETER1, W
1208
	addwf	POSTINC1, F
1209
	movf	MIOS_PARAMETER2, W
1210
	addwfc	POSTDEC1, F
1211
	bc	SIDSE_L_ENV_Attack1_DelayOv
1212
	rgoto	SIDSE_L_ENV_End
1213
SIDSE_L_ENV_Attack1_DelayOv
1214
	;; overrun: clear counter to disable delay
1215
	clrf	POSTINC1
1216
	clrf	POSTDEC1
1217
SIDSE_L_ENV_Attack1_NoDelay
1218
	movlw	-SID_ENVx_DELAY_CTR_L	; switch back to SID_ENVx_CTR_L
1219
	addwf	FSR1L, F
1220
 
1221
 
1222
	;; in attack1 phase we have to increase the EG counter
1223
	;; attack rate in IRQ_TMP3
1224
	movlw	SID_Ix_L_ENVx_ATTACK1
1225
	movf	PLUSW0, W
1226
	movwf	IRQ_TMP3
1227
	;; get final rate depending on curve setting
1228
	movlw	SID_Ix_L_ENVx_ATT_CURVE
1229
	movf	PLUSW0, W
1230
	call	SIDSE_Hlp_ENV_GetBendedValue
1231
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1232
	;; store final attack level in IRQ_TMP1
1233
	movlw	SID_Ix_L_ENVx_ATTLVL
1234
	movff	PLUSW0, IRQ_TMP1
1235
	;; increment counter
1236
	call	SIDSE_Hlp_ENV_IncrCtr
1237
	;; we've reached the level once the zero bit set
1238
	bnz	SIDSE_L_ENV_Cont
1239
 
1240
	;; switch to next phase
1241
	movlw	SID_ENV_STATE_ATTACK1
1242
	rcall	SIDSE_L_ENV_SetPhase
1243
 
1244
	rgoto	SIDSE_L_ENV_Cont
1245
 
1246
 
1247
SIDSE_L_ENV_Attack2
1248
	;; in attack1 phase we have to increase the EG counter
1249
	;; attack rate in IRQ_TMP3
1250
	movlw	SID_Ix_L_ENVx_ATTACK2
1251
	movff	PLUSW0, IRQ_TMP3
1252
	;; get final rate depending on curve setting
1253
	movlw	SID_Ix_L_ENVx_ATT_CURVE
1254
	movf	PLUSW0, W
1255
	call	SIDSE_Hlp_ENV_GetBendedValue
1256
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1257
	;; final attack level is 0xff
1258
	movlw	0xff
1259
	movwf	IRQ_TMP1
1260
	;; increment counter
1261
	call	SIDSE_Hlp_ENV_IncrCtr
1262
	;; we've reached the level once the zero bit set
1263
	bnz	SIDSE_L_ENV_Cont
1264
 
1265
	;; switch to next phase
1266
	movlw	SID_ENV_STATE_ATTACK2
1267
	rcall	SIDSE_L_ENV_SetPhase
1268
 
1269
	rgoto	SIDSE_L_ENV_Cont
1270
 
1271
 
1272
SIDSE_L_ENV_Decay1
1273
	;; in decay1 phase we have to increase/decrease the EG counter depending on the current level
1274
	;; decay1 rate in IRQ_TMP3
1275
	movlw	SID_Ix_L_ENVx_DECAY1
1276
	movff	PLUSW0, IRQ_TMP3
1277
	;; get final rate depending on curve setting
1278
	movlw	SID_Ix_L_ENVx_DEC_CURVE
1279
	movf	PLUSW0, W
1280
	call	SIDSE_Hlp_ENV_GetBendedValue
1281
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1282
	;; store final decay level in IRQ_TMP1
1283
	movlw	SID_Ix_L_ENVx_DECLVL
1284
	movff	PLUSW0, IRQ_TMP1
1285
	;; incr/decr counter
1286
	call	SIDSE_Hlp_ENV_IncrDecrCtr
1287
	;; we've reached the level once the zero bit set
1288
	bnz	SIDSE_L_ENV_Cont
1289
 
1290
	;; switch to next phase
1291
	movlw	SID_ENV_STATE_DECAY1
1292
	rcall	SIDSE_L_ENV_SetPhase
1293
 
1294
	rgoto	SIDSE_L_ENV_Cont
1295
 
1296
 
1297
SIDSE_L_ENV_Decay2
1298
	;; in decay2 phase we have to increase/decrease the EG counter depending on the current level
1299
	;; decay2 rate in WREG
1300
	movlw	SID_Ix_L_ENVx_DECAY2
1301
	movff	PLUSW0, IRQ_TMP3
1302
	;; get final rate depending on curve setting
1303
	movlw	SID_Ix_L_ENVx_DEC_CURVE
1304
	movf	PLUSW0, W
1305
	call	SIDSE_Hlp_ENV_GetBendedValue
1306
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1307
	;; store final sustain in IRQ_TMP1
1308
	movlw	SID_Ix_L_ENVx_SUSTAIN
1309
	movff	PLUSW0, IRQ_TMP1
1310
	;; incr/decr counter
1311
	call	SIDSE_Hlp_ENV_IncrDecrCtr
1312
	;; we've reached the level once the zero bit set
1313
	bnz	SIDSE_L_ENV_Cont
1314
 
1315
	;; propagate sustain phase to trigger matrix (using FSR2 as working pointer)
1316
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1317
	mullw	3
1318
	lfsr	FSR2, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_E1S_BASE
1319
	movf	PRODL, W
1320
	addwf	FSR2L, F
1321
	movf	POSTINC2, W
1322
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
1323
	movf	POSTINC2, W
1324
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
1325
	movf	POSTINC2, W
1326
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
1327
 
1328
	;; switch to next phase
1329
	movlw	SID_ENV_STATE_DECAY2
1330
	rcall	SIDSE_L_ENV_SetPhase
1331
 
1332
	movlw	SID_ENVx_STATE
1333
	BRA_IFCLR PLUSW1, SID_ENV_STATE_SUSTAIN, ACCESS, SIDSE_L_ENV_Cont
1334
 
1335
SIDSE_L_ENV_Sustain
1336
	;; write sustain value into counter (again)
1337
	movlw	SID_Ix_L_ENVx_SUSTAIN
1338
	movff	PLUSW0, MIOS_PARAMETER2
1339
	clrf	MIOS_PARAMETER1
1340
 
1341
	;; loop in this phase
1342
	movlw	SID_ENV_STATE_SUSTAIN
1343
	rcall	SIDSE_L_ENV_SetPhase
1344
 
1345
	rgoto	SIDSE_L_ENV_Cont
1346
 
1347
 
1348
SIDSE_L_ENV_Release1
1349
	;; in release phase we have to decrease the EG counter until it reaches the sustain level
1350
	;; release rate in WREG
1351
	movlw	SID_Ix_L_ENVx_RELEASE1
1352
	movff	PLUSW0, IRQ_TMP3
1353
	;; get release rate depending on curve setting
1354
	movlw	SID_Ix_L_ENVx_REL_CURVE
1355
	movf	PLUSW0, W
1356
	call	SIDSE_Hlp_ENV_GetBendedValue
1357
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1358
	;; store release level in IRQ_TMP1
1359
	movlw	SID_Ix_L_ENVx_RELLVL
1360
	movff	PLUSW0, IRQ_TMP1
1361
	;; incr/decr counter
1362
	call	SIDSE_Hlp_ENV_IncrDecrCtr
1363
 
1364
	;; we've reached the level once the zero bit set
1365
	bnz	SIDSE_L_ENV_Cont
1366
 
1367
	;; switch to next phase
1368
	movlw	SID_ENV_STATE_RELEASE1
1369
	rcall	SIDSE_L_ENV_SetPhase
1370
 
1371
	rgoto	SIDSE_L_ENV_Cont
1372
 
1373
SIDSE_L_ENV_Release2
1374
	;; in the final release phase we have to decrease the EG counter until it reaches 0
1375
	;; release rate in WREG
1376
	movlw	SID_Ix_L_ENVx_RELEASE2
1377
	movff	PLUSW0, IRQ_TMP3
1378
	;; get release rate depending on curve setting
1379
	movlw	SID_Ix_L_ENVx_REL_CURVE
1380
	movf	PLUSW0, W
1381
	call	SIDSE_Hlp_ENV_GetBendedValue
1382
	;; target level: 0
1383
	clrf	IRQ_TMP1
1384
	;; decr counter
1385
	call	SIDSE_Hlp_ENV_DecrCtr
1386
 
1387
	;; switch to next phase (if required)
1388
	movlw	SID_ENV_STATE_RELEASE2
1389
	rcall	SIDSE_L_ENV_SetPhase
1390
 
1391
	;; 	rgoto	SIDSE_L_ENV_Cont
1392
 
1393
SIDSE_L_ENV_Cont
1394
	;; copy MIOS_PARAMETER[12] to SID_ENVx_CTR_[LH]
1395
	movff	MIOS_PARAMETER1, POSTINC1
1396
	movff	MIOS_PARAMETER2, POSTDEC1
1397
 
1398
	clrc
1399
	rrf	MIOS_PARAMETER2, W
1400
	movwf	MUL_A_H, BANKED
1401
	rrf	MIOS_PARAMETER1, W
1402
	movwf	MUL_A_L, BANKED
1403
 
1404
	;; skip ENV mapping if result is zero (write zero directly into registers)
1405
	movf	MIOS_PARAMETER1, W
1406
	iorwf	MIOS_PARAMETER2, W
1407
	bz	SIDSE_L_ENV_Cont_Zero
1408
 
1409
	;; scale by ENV depth (skip if depth is zero)
1410
	movlw	SID_Ix_L_ENVx_DEPTH
1411
	movf	PLUSW0, W
1412
	xorlw	0x80
1413
	bz	SIDSE_L_ENV_Cont_Zero
1414
	xorlw	0x80
1415
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[12], uses IRQ_TMP1
1416
	rgoto	SIDSE_L_ENV_Cont_NotZero
1417
 
1418
SIDSE_L_ENV_Cont_Zero
1419
	clrf	MUL_R_1, BANKED	; result is zero - optimized
1420
	clrf	MUL_R_2, BANKED
1421
 
1422
SIDSE_L_ENV_Cont_NotZero
1423
	;; finally transfer result to SID_MOD_SRC_L_ENVx_VALUE_[LH]
1424
	;; range: +/- 0x7fff
1425
	lfsr	FSR2, SID_MOD_SRC_L_ENV1_L
1426
	clrc
1427
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
1428
	addwf	FSR2L, F
1429
	movff	MUL_R_1, POSTINC2
1430
	movff	MUL_R_2, POSTDEC2
1431
 
1432
SIDSE_L_ENV_End
1433
	return
1434
 
1435
 
1436
;; --------------------------------------------------------------------------
1437
;; This function handles the Modulation Matrix
1438
;; IN: pointer to SID_Ix_MODx_BASE in FSR0 (patch record)
1439
;;     MOD number in SID_SE_ELEMENT_NUM
1440
;; --------------------------------------------------------------------------
1441
SIDSE_L_MOD
1442
	;; skip if depth is zero
1443
	movlw	SID_Ix_MODx_DEPTH
1444
	movf	PLUSW0, W
1445
	xorlw	0x80
1446
	skpnz
1447
	rgoto	SIDSE_L_MOD_End
1448
 
1449
	;; copy first source to SID_SE_MOD_SRC1_[LH]
1450
	movlw	SID_Ix_MODx_SRC1
1451
	movf	PLUSW0, W
1452
	bz	SIDSE_L_MOD_Src1_Disabled
1453
	BRA_IFSET WREG, 7, ACCESS, SIDSE_L_MOD_Src1_Const
1454
SIDSE_L_MOD_Src1
1455
	lfsr	FSR2, SID_MOD_SRC_BASE
1456
	addlw	-1
1457
	rlf	WREG, W
1458
	andlw	0xfe
1459
	addlw	1
1460
	addwf	FSR2L, F
1461
	clrc
1462
	rrf	POSTDEC2, W
1463
	movwf	SID_SE_MOD_SRC1_H, BANKED
1464
	rrf	INDF2, W
1465
	movwf	SID_SE_MOD_SRC1_L, BANKED
1466
	btfsc	SID_SE_MOD_SRC1_H, 6, BANKED
1467
	bsf	SID_SE_MOD_SRC1_H, 7, BANKED
1468
	;; range: +/- 0x3fff
1469
	rgoto	SIDSE_L_MOD_Src1_Cont
1470
 
1471
SIDSE_L_MOD_Src1_Const
1472
	;; range 0x00..0x7f -> +0x0000..0x03f80
1473
	rrf	WREG, W
1474
	andlw	0x3f
1475
	movwf	SID_SE_MOD_SRC1_H, BANKED
1476
	clrf	SID_SE_MOD_SRC1_L, BANKED
1477
	rrf	SID_SE_MOD_SRC1_L, F, BANKED
1478
	rgoto	SIDSE_L_MOD_Src1_Cont
1479
 
1480
SIDSE_L_MOD_Src1_Disabled
1481
	clrf	SID_SE_MOD_SRC1_L, BANKED
1482
	clrf	SID_SE_MOD_SRC1_H, BANKED
1483
	;; 	rgoto	SIDSE_L_MOD_Src1_Cont
1484
SIDSE_L_MOD_Src1_Cont
1485
 
1486
	;; copy second source to SID_SE_MOD_SRC2_[LH]
1487
	movlw	SID_Ix_MODx_SRC2
1488
	movf	PLUSW0, W
1489
	bz	SIDSE_L_MOD_Src2_Disabled
1490
	BRA_IFSET WREG, 7, ACCESS, SIDSE_L_MOD_Src2_Const
1491
SIDSE_L_MOD_Src2
1492
	lfsr	FSR2, SID_MOD_SRC_BASE
1493
	addlw	-1
1494
	rlf	WREG, W
1495
	andlw	0xfe
1496
	addlw	1
1497
	addwf	FSR2L, F
1498
	clrc
1499
	rrf	POSTDEC2, W
1500
	movwf	SID_SE_MOD_SRC2_H, BANKED
1501
	rrf	INDF2, W
1502
	movwf	SID_SE_MOD_SRC2_L, BANKED
1503
	btfsc	SID_SE_MOD_SRC2_H, 6, BANKED
1504
	bsf	SID_SE_MOD_SRC2_H, 7, BANKED
1505
	;; range: +/- 0x3fff
1506
	rgoto	SIDSE_L_MOD_Src2_Cont
1507
 
1508
SIDSE_L_MOD_Src2_Const
1509
	;; range 0x00..0x7f -> +0x0000..0x03f80
1510
	rrf	WREG, W
1511
	andlw	0x3f
1512
	movwf	SID_SE_MOD_SRC2_H, BANKED
1513
	clrf	SID_SE_MOD_SRC2_L, BANKED
1514
	rrf	SID_SE_MOD_SRC2_L, F, BANKED
1515
	rgoto	SIDSE_L_MOD_Src2_Cont
1516
 
1517
SIDSE_L_MOD_Src2_Disabled
1518
	clrf	SID_SE_MOD_SRC2_L, BANKED
1519
	clrf	SID_SE_MOD_SRC2_H, BANKED
1520
	;; 	rgoto	SIDSE_L_MOD_Src2_Cont
1521
SIDSE_L_MOD_Src2_Cont
1522
 
1523
	;; apply selected operation
1524
	movlw	SID_Ix_MODx_OP
1525
	movf	PLUSW0, W
1526
	andlw	0x0f
1527
	JUMPTABLE_2BYTES_UNSECURE
1528
	rgoto	SIDSE_L_MOD_OP_0
1529
	rgoto	SIDSE_L_MOD_OP_1
1530
	rgoto	SIDSE_L_MOD_OP_2
1531
	rgoto	SIDSE_L_MOD_OP_3
1532
	rgoto	SIDSE_L_MOD_OP_4
1533
	rgoto	SIDSE_L_MOD_OP_5
1534
	rgoto	SIDSE_L_MOD_OP_6
1535
	rgoto	SIDSE_L_MOD_OP_7
1536
	rgoto	SIDSE_L_MOD_OP_8
1537
	rgoto	SIDSE_L_MOD_OP_9
1538
	rgoto	SIDSE_L_MOD_OP_10
1539
	rgoto	SIDSE_L_MOD_OP_11
1540
	rgoto	SIDSE_L_MOD_OP_12
1541
	rgoto	SIDSE_L_MOD_OP_13
1542
	rgoto	SIDSE_L_MOD_OP_14
1543
	rgoto	SIDSE_L_MOD_OP_15
1544
 
1545
SIDSE_L_MOD_OP_0	; disabled
1546
	clrf	MUL_A_L, BANKED
1547
	clrf	MUL_A_H, BANKED
1548
	rgoto	SIDSE_L_MOD_OP_Cont
1549
 
1550
SIDSE_L_MOD_OP_1	; SRC1 only
1551
	movff	SID_SE_MOD_SRC1_L, MUL_A_L
1552
	movff	SID_SE_MOD_SRC1_H, MUL_A_H
1553
	rgoto	SIDSE_L_MOD_OP_Cont
1554
 
1555
SIDSE_L_MOD_OP_2	; SRC2 only
1556
	movff	SID_SE_MOD_SRC2_L, MUL_A_L
1557
	movff	SID_SE_MOD_SRC2_H, MUL_A_H
1558
	rgoto	SIDSE_L_MOD_OP_Cont
1559
 
1560
SIDSE_L_MOD_OP_3	; SRC1+SRC2
1561
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1562
	addwf	SID_SE_MOD_SRC2_L, W, BANKED
1563
	movwf	MUL_A_L, BANKED
1564
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1565
	addwfc	SID_SE_MOD_SRC2_H, W, BANKED
1566
	movwf	MUL_A_H, BANKED
1567
	rgoto	SIDSE_L_MOD_OP_Cont
1568
 
1569
SIDSE_L_MOD_OP_4	; SRC1-SRC2
1570
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1571
	subwf	SID_SE_MOD_SRC2_L, W, BANKED
1572
	movwf	MUL_A_L, BANKED
1573
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1574
	subwfb	SID_SE_MOD_SRC2_H, W, BANKED
1575
	movwf	MUL_A_H, BANKED
1576
	rgoto	SIDSE_L_MOD_OP_Cont
1577
 
1578
SIDSE_L_MOD_OP_5	; SRC1*SRC2
1579
	clrc
1580
	rlf	SID_SE_MOD_SRC1_L, W, BANKED
1581
	movwf	MUL_A_L, BANKED
1582
	rlf	SID_SE_MOD_SRC1_H, W, BANKED
1583
	movwf	MUL_A_H, BANKED
1584
 
1585
	clrc
1586
	rlf	SID_SE_MOD_SRC2_L, W, BANKED
1587
	movwf	MUL_B_L, BANKED
1588
	rlf	SID_SE_MOD_SRC2_H, W, BANKED
1589
	movwf	MUL_B_H, BANKED
1590
 
1591
	call	MATH_MUL16_16_SIGNED
1592
 
1593
	movff	MUL_R_2, MUL_A_L
1594
	movff	MUL_R_3, MUL_A_H
1595
	rgoto	SIDSE_L_MOD_OP_Cont
1596
 
1597
SIDSE_L_MOD_OP_6	; XOR
1598
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1599
	xorwf	SID_SE_MOD_SRC2_L, W, BANKED
1600
	movwf	MUL_A_L, BANKED
1601
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1602
	xorwf	SID_SE_MOD_SRC2_H, W, BANKED
1603
	movwf	MUL_A_H, BANKED
1604
	rgoto	SIDSE_L_MOD_OP_Cont
1605
 
1606
SIDSE_L_MOD_OP_7	; OR
1607
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1608
	iorwf	SID_SE_MOD_SRC2_L, W, BANKED
1609
	movwf	MUL_A_L, BANKED
1610
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1611
	iorwf	SID_SE_MOD_SRC2_H, W, BANKED
1612
	movwf	MUL_A_H, BANKED
1613
	rgoto	SIDSE_L_MOD_OP_Cont
1614
 
1615
SIDSE_L_MOD_OP_8	; AND
1616
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1617
	andwf	SID_SE_MOD_SRC2_L, W, BANKED
1618
	movwf	MUL_A_L, BANKED
1619
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1620
	andwf	SID_SE_MOD_SRC2_H, W, BANKED
1621
	movwf	MUL_A_H, BANKED
1622
	rgoto	SIDSE_L_MOD_OP_Cont
1623
 
1624
SIDSE_L_MOD_OP_9	; Min
1625
	;; check if SRC1 < SRC2
1626
SIDSE_L_MOD_OP_9_CmpH
1627
	movf	SID_SE_MOD_SRC2_H, W, BANKED	; signed value comparison
1628
	xorlw	0x80
1629
	movwf	IRQ_TMP1
1630
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1631
	xorlw	0x80
1632
	subwf	IRQ_TMP1, W
1633
	bnz	SIDSE_L_MOD_OP_9_SkipCmpL
1634
SIDSE_L_MOD_OP_9_CmpL
1635
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1636
	subwf	SID_SE_MOD_SRC2_L, W, BANKED
1637
SIDSE_L_MOD_OP_9_SkipCmpL
1638
	bc	SIDSE_L_MOD_OP_1	; SRC1 is less -> SRC1 only
1639
	rgoto	SIDSE_L_MOD_OP_2	; SRC2 is less -> SRC2 only
1640
 
1641
SIDSE_L_MOD_OP_10	; Max
1642
	;; check if SRC1 > SRC2
1643
SIDSE_L_MOD_OP_10_CmpH
1644
	movf	SID_SE_MOD_SRC2_H, W, BANKED	; signed value comparison
1645
	xorlw	0x80
1646
	movwf	IRQ_TMP1
1647
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1648
	xorlw	0x80
1649
	subwf	IRQ_TMP1, W
1650
	bnz	SIDSE_L_MOD_OP_10_SkipCmpL
1651
SIDSE_L_MOD_OP_10_CmpL
1652
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1653
	subwf	SID_SE_MOD_SRC2_L, W, BANKED
1654
SIDSE_L_MOD_OP_10_SkipCmpL
1655
	bc	SIDSE_L_MOD_OP_2	; SRC2 is greater -> SRC2 only
1656
	rgoto	SIDSE_L_MOD_OP_1	; SRC1 is greater -> SRC1 only
1657
 
1658
SIDSE_L_MOD_OP_11
1659
	;; check if SRC1 < SRC2
1660
SIDSE_L_MOD_OP_11_CmpH
1661
	movf	SID_SE_MOD_SRC2_H, W, BANKED	; signed value comparison
1662
	xorlw	0x80
1663
	movwf	IRQ_TMP1
1664
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1665
	xorlw	0x80
1666
	subwf	IRQ_TMP1, W
1667
	bnz	SIDSE_L_MOD_OP_11_SkipCmpL
1668
SIDSE_L_MOD_OP_11_CmpL
1669
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1670
	subwf	SID_SE_MOD_SRC2_L, W, BANKED
1671
SIDSE_L_MOD_OP_11_SkipCmpL
1672
	bc	SIDSE_L_MOD_OP_Cont_High	; SRC1 is less -> high value
1673
	rgoto	SIDSE_L_MOD_OP_Cont_Low	; SRC2 is less -> low value
1674
 
1675
SIDSE_L_MOD_OP_12
1676
	;; check if SRC1 > SRC2
1677
SIDSE_L_MOD_OP_12_CmpH
1678
	movf	SID_SE_MOD_SRC2_H, W, BANKED	; signed value comparison
1679
	xorlw	0x80
1680
	movwf	IRQ_TMP1
1681
	movf	SID_SE_MOD_SRC1_H, W, BANKED
1682
	xorlw	0x80
1683
	subwf	IRQ_TMP1, W
1684
	bnz	SIDSE_L_MOD_OP_12_SkipCmpL
1685
SIDSE_L_MOD_OP_12_CmpL
1686
	movf	SID_SE_MOD_SRC1_L, W, BANKED
1687
	subwf	SID_SE_MOD_SRC2_L, W, BANKED
1688
SIDSE_L_MOD_OP_12_SkipCmpL
1689
	bc	SIDSE_L_MOD_OP_Cont_Low	; SRC1 is less -> low value
1690
	rgoto	SIDSE_L_MOD_OP_Cont_High	; SRC2 is less -> high value
1691
 
1692
SIDSE_L_MOD_OP_13
1693
	;; check if SRC1 = SRC2
1694
	;; (only high bytes are checked for lower granularity)
1695
	movf	SID_SE_MOD_SRC2_H, W, BANKED
1696
	xorwf	SID_SE_MOD_SRC1_H, W, BANKED
1697
	bz	SIDSE_L_MOD_OP_Cont_High	; high bytes equal -> high value
1698
	rgoto	SIDSE_L_MOD_OP_Cont_Low	; high bytes not equal -> low value
1699
 
1700
SIDSE_L_MOD_OP_14
1701
	;; S&H - SRC1 will be sampled whenever SRC2 changes from a negative to a positive value
1702
 
1703
	;; determine OR/AND mask for MOD element -> IRQ_TMP1
1704
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1705
	call	MIOS_HLP_GetBitORMask
1706
	movwf	IRQ_TMP1
1707
 
1708
	;; determine if SRC2 is negative or positive - store NEG flag at correct bit position in IRQ_TMP2
1709
	btfss	SID_SE_MOD_SRC2_H, 7, BANKED
1710
	movlw	0x00
1711
	movwf	IRQ_TMP2
1712
 
1713
	;; check for 0 transition, if not: forward old value (HOLD)
1714
	movf	SID_SE_MOD_TRANSITION, W, BANKED
1715
	andwf	IRQ_TMP1, W
1716
	xorwf	IRQ_TMP2, W
1717
	bz	SIDSE_L_MOD_OP_14_Hold
1718
 
1719
SIDSE_L_MOD_OP_14_Sample
1720
	;; store new NEG flag
1721
	comf	IRQ_TMP1, W
1722
	andwf	SID_SE_MOD_TRANSITION, F, BANKED
1723
	movf	IRQ_TMP2, W
1724
	iorwf	SID_SE_MOD_TRANSITION, F, BANKED
1725
 
1726
	;; still hold when we are in negative range now
1727
	;; (only sample on negative->positive transition)
1728
	movf	IRQ_TMP2, W
1729
	bnz	SIDSE_L_MOD_OP_14_Hold
1730
 
1731
	;; take new SRC1 value
1732
	rgoto	SIDSE_L_MOD_OP_1
1733
 
1734
SIDSE_L_MOD_OP_14_Hold
1735
	;; take old MOD value
1736
	lfsr	FSR2, SID_MOD_SRC_BASE
1737
	clrc
1738
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
1739
	addlw	SID_MOD_SRC_L_MOD1_L-SID_MOD_SRC_BASE
1740
	addwf	FSR2L, F
1741
	movff	POSTINC2, MUL_A_L
1742
	movff	POSTINC2, MUL_A_H
1743
 
1744
	rgoto	SIDSE_L_MOD_OP_Cont
1745
 
1746
SIDSE_L_MOD_OP_15	; reserved
1747
	rgoto	SIDSE_L_MOD_OP_0
1748
 
1749
 
1750
SIDSE_L_MOD_OP_Cont_High		; constant high value
1751
	setf	MUL_A_L, BANKED
1752
	movlw	0x7f
1753
	movwf	MUL_A_H, BANKED
1754
	rgoto	SIDSE_L_MOD_OP_Cont
1755
 
1756
SIDSE_L_MOD_OP_Cont_Low		; constant low value
1757
	clrf	MUL_A_L, BANKED
1758
	movlw	0x80
1759
	movwf	MUL_A_H, BANKED
1760
	;; 	rgoto	SIDSE_L_MOD_OP_Cont
1761
 
1762
SIDSE_L_MOD_OP_Cont
1763
 
1764
	;; store in modulator source array for feedbacks
1765
	;; use value w/o depth, this has two advantages:
1766
	;; - maximum resolution when forwarding the data value
1767
	;; - original MOD value can be taken for sample&hold feature
1768
	;; but it has also a disadvantage:
1769
	;; - the user could think it is a bug when depth doesn't affect the feedback MOD value...
1770
	lfsr	FSR2, SID_MOD_SRC_BASE
1771
	clrc
1772
	rlf	SID_SE_ELEMENT_NUM, W, BANKED
1773
	addlw	SID_MOD_SRC_L_MOD1_L-SID_MOD_SRC_BASE
1774
	addwf	FSR2L, F
1775
	movff	MUL_A_L, POSTINC2
1776
	movff	MUL_A_H, POSTINC2
1777
 
1778
	;; skip if modulation result is zero
1779
	movf	MUL_A_L, W, BANKED
1780
	iorwf	MUL_A_H, W, BANKED
1781
	skpnz
1782
	rgoto	SIDSE_L_MOD_End
1783
 
1784
	;; scale by MOD depth		; (zero check already at top of MOD function)
1785
	movlw	SID_Ix_MODx_DEPTH
1786
	movf	PLUSW0, W
1787
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[12], uses IRQ_TMP1
1788
 
1789
	;; store in METER_VALUES array for optional visualisation on the modulation matrix
1790
	movff	MUL_R_2, MIOS_PARAMETER1
1791
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1792
	call	CS_MENU_MATRIX_MeterSet
1793
	;; uses FSR1 !!!
1794
 
1795
	;; multiply by two (to allow full range sweeps)
1796
	rlf	MUL_R_1, F, BANKED
1797
	rlf	MUL_R_2, F, BANKED
1798
	rlf	MUL_R_3, F, BANKED
1799
 
1800
	;; copy to MOD result registers
1801
	movff	MUL_R_1, SID_SE_MOD_RES1_L
1802
	movff	MUL_R_2, SID_SE_MOD_RES1_H
1803
	movff	MUL_R_3, SID_SE_MOD_RES1_U
1804
	movff	MUL_R_1, SID_SE_MOD_RES2_L
1805
	movff	MUL_R_2, SID_SE_MOD_RES2_H
1806
	movff	MUL_R_3, SID_SE_MOD_RES2_U
1807
 
1808
	;; invert result1 if requested
1809
	movlw	SID_Ix_MODx_OP
1810
	BRA_IFCLR PLUSW0, 6, ACCESS, SIDSE_L_MOD_OP_Res1_NoInv
1811
SIDSE_L_MOD_OP_Res1_Inv
1812
	comf	SID_SE_MOD_RES1_L, F, BANKED
1813
	comf	SID_SE_MOD_RES1_H, F, BANKED
1814
	comf	SID_SE_MOD_RES1_U, F, BANKED
1815
	incf	SID_SE_MOD_RES1_L, F, BANKED
1816
	skpnz
1817
	incf	SID_SE_MOD_RES1_H, F, BANKED
1818
	skpnz
1819
	incf	SID_SE_MOD_RES1_U, F, BANKED
1820
SIDSE_L_MOD_OP_Res1_NoInv
1821
 
1822
	;; invert result2 if requested
1823
	movlw	SID_Ix_MODx_OP
1824
	BRA_IFCLR PLUSW0, 7, ACCESS, SIDSE_L_MOD_OP_Res2_NoInv
1825
SIDSE_L_MOD_OP_Res2_Inv
1826
	comf	SID_SE_MOD_RES2_L, F, BANKED
1827
	comf	SID_SE_MOD_RES2_H, F, BANKED
1828
	comf	SID_SE_MOD_RES2_U, F, BANKED
1829
	incf	SID_SE_MOD_RES2_L, F, BANKED
1830
	skpnz
1831
	incf	SID_SE_MOD_RES2_H, F, BANKED
1832
	skpnz
1833
	incf	SID_SE_MOD_RES2_U, F, BANKED
1834
SIDSE_L_MOD_OP_Res2_NoInv
1835
 
1836
	;; add result to modulation target array
1837
	movlw	SID_Ix_MODx_TARG_X1
1838
	movf	PLUSW0, W
1839
	bz	SIDSE_L_MOD_Targ1_Disabled
1840
SIDSE_L_MOD_Targ1
1841
	lfsr	FSR2, SID_MOD_TARG_BASE
1842
	addlw	-1
1843
	mullw	3
1844
	lfsr	FSR2, SID_MOD_TARG_BASE
1845
	movf	PRODL, W
1846
	andlw	0x7f		; avoid access outside target array!
1847
	addwf	FSR2L, F
1848
	rcall	SIDSE_L_MOD_Hlp_AddTarget1
1849
SIDSE_L_MOD_Targ1_Disabled
1850
 
1851
	;; add result to modulation target array
1852
	movlw	SID_Ix_MODx_TARG_X2
1853
	movf	PLUSW0, W
1854
	bz	SIDSE_L_MOD_Targ2_Disabled
1855
SIDSE_L_MOD_Targ2
1856
	addlw	-1
1857
	mullw	3
1858
	lfsr	FSR2, SID_MOD_TARG_BASE
1859
	movf	PRODL, W
1860
	andlw	0x7f		; avoid access outside target array!
1861
	addwf	FSR2L, F
1862
	rcall	SIDSE_L_MOD_Hlp_AddTarget2
1863
SIDSE_L_MOD_Targ2_Disabled
1864
 
1865
	;; add to additional SIDL/R targets
1866
 
1867
SIDSE_L_MOD_COPYTARG_MACRO MACRO func, SID_MOD_TARG_x, flag
1868
	LOCAL	SIDSE_L_MOD_COPYTARG_MACRO_Skip
1869
	BRA_IFCLR IRQ_TMP1, flag, ACCESS, SIDSE_L_MOD_COPYTARG_MACRO_Skip
1870
	lfsr	FSR2, SID_MOD_TARG_x
1871
	rcall	func
1872
SIDSE_L_MOD_COPYTARG_MACRO_Skip
1873
	ENDM
1874
 
1875
 
1876
	movlw	SID_Ix_MODx_TARG_L
1877
	movff	PLUSW0, IRQ_TMP1
1878
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PITCH1_L, 0
1879
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PITCH2_L, 1
1880
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PITCH3_L, 2
1881
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PW1_L, 3
1882
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PW2_L, 4
1883
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_PW3_L, 5
1884
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_FIL1_L, 6
1885
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget1, SID_MOD_TARG_VOL1_L, 7
1886
 
1887
	movlw	SID_Ix_MODx_TARG_R
1888
	movff	PLUSW0, IRQ_TMP1
1889
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PITCH4_L, 0
1890
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PITCH5_L, 1
1891
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PITCH6_L, 2
1892
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PW4_L, 3
1893
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PW5_L, 4
1894
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_PW6_L, 5
1895
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_FIL2_L, 6
1896
	SIDSE_L_MOD_COPYTARG_MACRO SIDSE_L_MOD_Hlp_AddTarget2, SID_MOD_TARG_VOL2_L, 7
1897
 
1898
SIDSE_L_MOD_End
1899
	return
1900
 
1901
;; help function which is used to add the result to a specific target (pointer in FSR2)
1902
SIDSE_L_MOD_Hlp_AddTarget1
1903
	movf	SID_SE_MOD_RES1_L, W, BANKED
1904
	addwf	POSTINC2, F
1905
	movf	SID_SE_MOD_RES1_H, W, BANKED
1906
	addwfc	POSTINC2, F
1907
	movf	SID_SE_MOD_RES1_U, W, BANKED
1908
	addwfc	POSTINC2, F
1909
	return
1910
 
1911
SIDSE_L_MOD_Hlp_AddTarget2
1912
	movf	SID_SE_MOD_RES2_L, W, BANKED
1913
	addwf	POSTINC2, F
1914
	movf	SID_SE_MOD_RES2_H, W, BANKED
1915
	addwfc	POSTINC2, F
1916
	movf	SID_SE_MOD_RES2_U, W, BANKED
1917
	addwfc	POSTINC2, F
1918
	return
1919
 
1920
 
1921
;; --------------------------------------------------------------------------
1922
;; Help Function for SIDSE_L_ENV for switching to a new phase
1923
;; Takes also the loop point into account
1924
;; IN:  pointer to SID_Ix_L_ENVx_BASE in FSR0 (patch record)
1925
;;      pointer to SID_ENVx_BASE in FSR1
1926
;;      current loop point in WREG (corresponds to SID_ENV_STATE_XXX flag)
1927
;; OUT:	changed SID_ENVx_STATE
1928
;; --------------------------------------------------------------------------
1929
SIDSE_L_ENV_SetPhase
1930
	movwf	PRODL		; temporary store phase number in PRODL and PRODH
1931
	movwf	PRODH		; (for sustain check)
1932
 
1933
	;; check for loop point
1934
	movlw	SID_Ix_L_ENVx_MODE
1935
	swapf	PLUSW0, W
1936
	andlw	0x07
1937
	addlw	-1
1938
	xorwf	PRODL, W	; check with current phase
1939
	bnz	SIDSE_L_ENV_SetPhase_NoLoop
1940
SIDSE_L_ENV_SetPhase_Loop
1941
	movlw	SID_Ix_L_ENVx_MODE
1942
	movf	PLUSW0, W
1943
	andlw	0x07
1944
	bz	SIDSE_L_ENV_SetPhase_NoLoop
1945
	addlw	-2
1946
	movwf	PRODL
1947
SIDSE_L_ENV_SetPhase_NoLoop
1948
 
1949
	;; if we are in sustain, and there is no loop point in the sustain phase, don't switch to next phase
1950
	movf	PRODH, W
1951
	xorlw	SID_ENV_STATE_SUSTAIN
1952
	bnz	SIDSE_L_ENV_SetPhase_NoSustain
1953
	movf	PRODL, W
1954
	xorlw	SID_ENV_STATE_SUSTAIN
1955
	bz	SIDSE_L_ENV_SetPhase_Sustain
1956
SIDSE_L_ENV_SetPhase_NoSustain
1957
	;; switch to next phase
1958
	incf	PRODL, F
1959
SIDSE_L_ENV_SetPhase_Sustain
1960
 
1961
	;; branch depending on new phase
1962
	BRA_IFSET PRODL, 2, ACCESS, SIDSE_L_ENV_SetPhase_4567
1963
SIDSE_L_ENV_SetPhase_0123
1964
	BRA_IFSET PRODL, 1, ACCESS, SIDSE_L_ENV_SetPhase_23
1965
SIDSE_L_ENV_SetPhase_01
1966
	movlw	0x01
1967
	btfsc	PRODL, 0
1968
	movlw 0x03
1969
	rgoto	SIDSE_L_ENV_SetPhase_Cont
1970
SIDSE_L_ENV_SetPhase_23
1971
	movlw	0x07
1972
	btfsc	PRODL, 0
1973
	movlw 0x0f
1974
	rgoto	SIDSE_L_ENV_SetPhase_Cont
1975
 
1976
SIDSE_L_ENV_SetPhase_4567
1977
	BRA_IFSET PRODL, 1, ACCESS, SIDSE_L_ENV_SetPhase_67
1978
SIDSE_L_ENV_SetPhase_45
1979
	movlw	0x1f
1980
	btfsc	PRODL, 0
1981
	movlw 0x3f
1982
	rgoto	SIDSE_L_ENV_SetPhase_Cont
1983
SIDSE_L_ENV_SetPhase_67
1984
	movlw	0x7f
1985
	;; 	rgoto	SIDSE_L_ENV_SetPhase_Cont
1986
SIDSE_L_ENV_SetPhase_Cont
1987
	movwf	PRODL
1988
	movlw	SID_ENVx_STATE
1989
	movff	PRODL, PLUSW1
1990
	return
1991
 
1992
;; --------------------------------------------------------------------------
1993
;;  FUNCTION: SIDSE_L_ENV_Restart
1994
;;  DESCRIPTION: help function which restarts a single ENV
1995
;;  IN: SID_PATCH_BUFFER_SHADOW + SID_Ix_ENV[123456]_BASE in FSR0
1996
;;      SID_ENV[123456]_BASE in FSR1
1997
;; --------------------------------------------------------------------------
1998
SIDSE_L_ENV_Restart
1999
	movlw	(1 << SID_ENV_STATE_ATTACK1)	; start at attack phase
2000
	movwf	PRODL
2001
	movlw	SID_ENVx_STATE
2002
	movff	PRODL, PLUSW1
2003
 
2004
	;; check if ENV should be delayed - set delay counter to 0x0001 in this case, else to 0x0000
2005
	movlw	SID_ENVx_DELAY_CTR_H	; high byte always reset to 0
2006
	clrf	PLUSW1
2007
 
2008
	movlw	SID_Ix_L_ENVx_DELAY
2009
	clrf	PRODL			; low byte set to 1 if delay != 0
2010
	movf	PLUSW0, W
2011
	skpz
2012
	incf	PRODL, F
2013
	movlw	SID_ENVx_DELAY_CTR_L
2014
	movff	PRODL, PLUSW1
2015
	return
2016
 
2017
;; --------------------------------------------------------------------------
2018
;;  FUNCTION: SIDSE_L_ENV_TrgRelease
2019
;;  DESCRIPTION: help function which starts release phase of a single ENV
2020
;;  IN: SID_ENV[123456]_BASE in FSR1
2021
;; --------------------------------------------------------------------------
2022
SIDSE_L_ENV_TrgRelease
2023
	movlw	SID_ENVx_STATE
2024
	bsf	PLUSW1, SID_ENV_STATE_RELEASE1
2025
	return
2026
 
2027
;; --------------------------------------------------------------------------
2028
;;  FUNCTION: SIDSE_L_Note_Restart
2029
;;  DESCRIPTION: help function which restarts the delay counter for voices
2030
;;               and requests an active gate
2031
;;  IN: patch base in FSR0, voice base in FSR1, osc number in SID_SE_ELEMENT_NUM
2032
;; --------------------------------------------------------------------------
2033
SIDSE_L_NOTE_Restart
2034
	;; request gate if voice is active (and request clear for proper ADSR handling)
2035
	;; set gate only if voice is active!
2036
	movlw	SID_Vx_STATE
2037
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
2038
	btfsc	PLUSW1, SID_V_STATE_VOICE_ACTIVE
2039
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
2040
 
2041
	;; check if voice should be delayed - set delay counter to 0x0001 in this case, else to 0x0000
2042
	movlw	SID_Vx_SET_DELAY_CTR_H	; high byte always reset to 0
2043
	clrf	PLUSW1
2044
 
2045
	movlw	SID_Ix_Vx_DELAY
2046
	clrf	PRODL			; low byte set to 1 if delay != 0
2047
	movf	PLUSW0, W
2048
	skpz
2049
	incf	PRODL, F
2050
 
2051
	;; delay also if ABW (ADSR bug workaround) option active
2052
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
2053
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_L_NOTE_Restart_NoABW
2054
SIDSE_L_NOTE_Restart_ABW
2055
	movlw	0x01
2056
	movwf	PRODL
2057
 
2058
	;; clear ADSR registers, so that the envelope gets completely released
2059
	call	SIDSE_Hlp_GetSIDFrqPtr
2060
	movlw	SIDx_V1_ENV_AD
2061
	clrf	PLUSW2
2062
	movlw	SIDx_V1_ENV_SR
2063
	clrf	PLUSW2
2064
SIDSE_L_NOTE_Restart_NoABW
2065
 
2066
	movlw	SID_Vx_SET_DELAY_CTR_L
2067
	movff	PRODL, PLUSW1
2068
	return
2069