Subversion Repositories svn.mios

Rev

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

Rev Author Line No. Line
44 tk 1
; $Id: sid_se.inc 1189 2014-12-19 20:00:14Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; Software Synthesizer Engine
5
;
6
; Activate this #define to measure the performance with a scope
7
; the used port has to be specified here - comment out for no measuring
8
;#define SID_SE_MEASURE_PERFORMANCE_PORT   LATC, 3
9
;
10
; ==========================================================================
11
;
12
;  Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
13
;  Idea for ENV Curve Parameter and OSC synchronization by Jess D. Skov-Nielsen
1189 tk 14
;  SuperSaw detune mode created by Lis0r
1 tk 15
;  Licensed for personal non-commercial use only.
16
;  All other rights reserved.
17
;
18
; ==========================================================================
19
 
391 tk 20
 
1 tk 21
;; ==========================================================================
22
;;  SID Flags
23
;; ==========================================================================
24
 
748 tk 25
;; general SID status flags
26
SID_STAT_ENGINE_DISABLE		EQU	0 ; if set, SID tick and SID interrupt will not be processed
27
SID_STAT_ENGINE_DISABLE_LEVEL0	EQU	1 ; same as flag 0, but used during startup to overcome a wdt timeout issue when no LCD is connected
28
SID_STAT_MBNET_ACCESS		EQU	2 ; exclusive access for MBNet
29
SID_STAT_SIDPLAYER		EQU	3 ; exclusive access for SID player
30
SID_STAT_SIDPLAYER_CS_DISABLE	EQU	4 ; set if CS buttons/encoders should be ignored
31
SID_STAT_CLK_SLAVE		EQU	5 ; if set, clock generator in slave mode (flag should be outside erasable SID_BASE structure)
32
SID_STAT_SE_CYCLE		EQU	6 ; switches between first and second engine cycle
33
 
34
 
1 tk 35
;; MIDI Voice Control Flags
36
SID_MV_ARP_STATE_ARP_ACTIVE	EQU	0 ; set if at least one arp is active
37
SID_MV_ARP_STATE_ARP_UP		EQU	1 ; arp order is incremented
38
SID_MV_ARP_STATE_SYNC_ARP	EQU	2 ; syncs the arpeggiator when a new note is played
39
SID_MV_ARP_STATE_HOLD_SAVED	EQU	3 ; notifies if hold mode was active (notes should be disabled on 1->0 transition)
40
 
41
SID_V_STATE_VOICE_ACTIVE	EQU	0
42
SID_V_STATE_VOICE_DISABLED	EQU	1
43
SID_V_STATE_GATE_ACTIVE		EQU	2
44
SID_V_STATE_GATE_SET_REQ	EQU	3
45
SID_V_STATE_GATE_CLR_REQ	EQU	4
46
SID_V_STATE_PORTA_ACTIVE	EQU	5
47
SID_V_STATE_ACCENT		EQU	6
48
SID_V_STATE_SLIDE		EQU	7
49
 
248 tk 50
SID_V_STATE2_PORTA_INITIALIZED	EQU	0	; portamento omitted when first key played
399 tk 51
SID_V_STATE2_FORCE_FRQ_RECALC	EQU	1	; forces SID frequency re-calculation (used by multi-engine to takeover portamento)
248 tk 52
 
1 tk 53
SID_I_OPT1_FLAGS_ABW		EQU	0	; ADSR bug workaround
54
 
55
SID_I_L_FLAGS1_LEGATO		EQU	0	; switches between mono/legato mode
56
SID_I_L_FLAGS1_WT_ONLY		EQU	1	; notes played by WT only
57
SID_I_L_FLAGS1_SUS_KEY		EQU	2	; enables SusKey
58
 
59
SID_I_M_V_FLAGS2_LEGATO		EQU	0	; multi engine only: switches between mono/legato mode when poly not enabled
60
SID_I_M_V_FLAGS2_WT_ONLY	EQU	1	; multi engine only: notes played by WT only
61
SID_I_M_V_FLAGS2_SUS_KEY	EQU	2	; multi engine only: enables SusKey
62
SID_I_M_V_FLAGS2_POLY		EQU	3	; multi engine only: enables Poly mode
63
SID_I_M_V_FLAGS2_PHASE		EQU	4	; multi engine only: oscillator phase synchronisation
64
 
65
SID_I_B_V_FLAGS2_LEGATO		EQU	0	; bassline engine only: switches between mono/legato mode when poly not enabled
66
SID_I_B_V_FLAGS2_WT_ONLY	EQU	1	; bassline engine only: notes played by WT only
67
SID_I_B_V_FLAGS2_SUS_KEY	EQU	2	; bassline engine only: enables SusKey
68
SID_I_B_V_FLAGS2_PHASE		EQU	4	; bassline engine only: oscillator phase synchronisation
69
 
70
SID_I_V_FLAGS1_PORTA_CTG	EQU	0	; constant time glide
71
SID_I_V_FLAGS1_PORTA_GLISSANDO	EQU	1	; glissando
72
SID_I_V_FLAGS1_GSA		EQU	2	; gate stays active
73
SID_I_V_FLAGS1_VASG_0		EQU	4	; only relevant for drum engine: voice assignment, bit 0
74
SID_I_V_FLAGS1_VASG_1		EQU	5	; only relevant for drum engine: voice assignment, bit 1
75
SID_I_V_FLAGS1_VASG_2		EQU	6	; only relevant for drum engine: voice assignment, bit 2
76
SID_I_V_FLAGS1_VASG_3		EQU	7	; only relevant for drum engine: voice assignment, bit 3
77
 
78
SID_I_V_ARP_MODE_ENABLE		EQU	0	; enables arp
79
SID_I_V_ARP_MODE_DIR_DOWN	EQU	1	; arp dir Up/Down
80
SID_I_V_ARP_MODE_DIR_ALT	EQU	2	; arp dir U&D/D&U
81
SID_I_V_ARP_MODE_DIR_ALT2	EQU	3	; arp dir U&D/D&U second option (border notes played twice) - dir mode 6 and 7 will select random
82
SID_I_V_ARP_MODE_SORTED		EQU	4	; select sorted stack
83
SID_I_V_ARP_MODE_HOLD		EQU	5	; select hold stack
84
SID_I_V_ARP_MODE_DIV_SYNC	EQU	6	; disables divider reset on new notes
85
SID_I_V_ARP_MODE_CAC		EQU	7	; constant arp cycle
86
 
679 tk 87
SID_I_V_ARP_SPEED_DIV_EASY_CHORD EQU	6	; easy chord mode
1 tk 88
SID_I_V_ARP_SPEED_DIV_ONESHOT	EQU	7	; oneshot mode
89
 
90
SID_I_V_SEQ_ON			EQU	6	; drum engine only: sequencer on/off flag
91
SID_I_V_SEQ_SYNC16		EQU	7	; bassline/drum engine only: 16step sync function
92
 
93
SID_SEQ_MISC_SUBCTR		EQU	0	; [2:0] counts from 0 to 6
94
SID_SEQ_MISC_SEQ_ON		EQU	3	; stores sequencer on flag
95
SID_SEQ_MISC_SEQ_RUNNING	EQU	4	; stores sequencer running flag (only used in drum mode)
96
 
97
SID_I_F_FIP_ON			EQU	7	; located in high byte of cutoff frequency: filter interpolation flag
98
 
99
SID_I_LFO_MODE_ENABLE		EQU	0
100
SID_I_LFO_MODE_SYNC_M		EQU	1	; sync LFO (only for multi and bassline engine - lead engine uses trigger matrix!)
101
SID_I_LFO_MODE_CLKSYNC		EQU	2
102
SID_I_LFO_MODE_ONESHOT		EQU	3
103
SID_I_LFO_MODE_WAVEFORM0	EQU	4
104
SID_I_LFO_MODE_WAVEFORM1	EQU	5
105
SID_I_LFO_MODE_WAVEFORM2	EQU	6
106
SID_I_LFO_MODE_WAVEFORM3	EQU	7
107
 
108
SID_I_ENV_MODE_LOOP_B0		EQU	0	; loop begin (3 bit)
109
SID_I_ENV_MODE_LOOP_B1		EQU	1
110
SID_I_ENV_MODE_LOOP_B2		EQU	2
111
SID_I_ENV_MODE_LOOP_E0		EQU	4	; loop end (3 bit)
112
SID_I_ENV_MODE_LOOP_E1		EQU	5
113
SID_I_ENV_MODE_LOOP_E2		EQU	6
114
SID_I_ENV_MODE_CLKSYNC		EQU	7
115
 
228 tk 116
SID_I_ENV_MODE_CURVE_ATT	EQU	4	; only used by Multi/Bassline engine: curve assigned to attack
117
SID_I_ENV_MODE_CURVE_DEC	EQU	5	; only used by Multi/Bassline engine: curve assigned to sustain
118
SID_I_ENV_MODE_CURVE_REL	EQU	6	; only used by Multi/Bassline engine: curve assigned to release
119
 
1 tk 120
SID_SE_STATE_LFO_OVERRUN	EQU	0	; used by LFO handler to notify an overrun
121
SID_SE_STATE_WT_NEW_STEP_REQ	EQU	0	; used by WT handler to request new step (shared flag with LFO)
122
SID_SE_STATE_ARP_NEW_NOTE_REQ	EQU	0	; used by ARP handler to request new note (shared flag with LFO)
123
SID_SE_STATE_ARP_FIRST_NOTE_REQ	EQU	1	; used by ARP handler to request the first note (oneshot function)
124
SID_SE_STATE_ARP_GATE_CLR_REQ	EQU	2	; used by ARP handler to request a gate clear
125
SID_SE_STATE_GLOBAL_CLK_EVENT	EQU	3	; temporary "global clock event" flag
126
SID_SE_STATE_MIDI_CLK_FA_REQ	EQU	4	; "MIDI clock start" request flag
127
SID_SE_STATE_MIDI_CLK_FB_REQ	EQU	5	; "MIDI clock continue" request flag
128
SID_SE_STATE_MIDI_CLK_FC_REQ	EQU	6	; "MIDI clock stop" request flag
129
SID_SE_STATE_ACCENT		EQU	7	; used by multi/bassline ENV handler to increase depth on accent
130
 
131
SID_ENV_STATE_ATTACK1		EQU	0
132
SID_ENV_STATE_ATTACK2		EQU	1
133
SID_ENV_STATE_DECAY1		EQU	2
134
SID_ENV_STATE_DECAY2		EQU	3
135
SID_ENV_STATE_SUSTAIN		EQU	4
136
SID_ENV_STATE_RELEASE1		EQU	5
137
SID_ENV_STATE_RELEASE2		EQU	6
138
 
139
SID_ENS_CTRL1_CLK_SLAVE		EQU	0	; switch between MIDI clock master/slave
140
SID_ENS_CTRL1_CLK_AUTO		EQU	1	; automatic switching between master/slave
1102 tk 141
SID_ENS_CTRL1_CLK_OUT		EQU	3	; enable clock output
340 tk 142
SID_ENS_CTRL1_FIL_LOG		EQU	4	; Select logarithmic scale for filter
1 tk 143
SID_ENS_CTRL1_MONO		EQU	6	; SIDs are played mono
340 tk 144
SID_ENS_CTRL1_DOR		EQU	7	; Disable automatic Oscillator Reset during patch change (could also be called DAORDPC flag ;)
1 tk 145
 
146
SID_ENS_CTRL2_F2A		EQU	0	; forward Filter CutOff/Resonance to AOUTs
147
SID_ENS_CTRL2_V2A		EQU	1	; forward Volume to AOUTs
148
SID_ENS_CTRL2_P2A		EQU	2	; forward Pulsewidth to AOUTs
149
SID_ENS_CTRL2_K2A		EQU	3	; forward Key Values to AOUTs and Gates to Digital Out
150
SID_ENS_CTRL2_O2A		EQU	4	; forward Oscillator Values to AOUTs and Gates to Digital Out
151
 
152
SID_TRG_TARGET_L_O1L		EQU	0	; OSC1 Left
153
SID_TRG_TARGET_L_O2L		EQU	1	; OSC2 Left
154
SID_TRG_TARGET_L_O3L		EQU	2	; OSC3 Left
155
SID_TRG_TARGET_L_O1R		EQU	3	; OSC1 Right
156
SID_TRG_TARGET_L_O2R		EQU	4	; OSC2 Right
157
SID_TRG_TARGET_L_O3R		EQU	5	; OSC3 Right
158
SID_TRG_TARGET_L_E1A		EQU	6	; ENV1 Attack
159
SID_TRG_TARGET_L_E2A		EQU	7	; ENV2 Attack
160
SID_TRG_TARGET_H_E1R		EQU	0	; ENV1 Release
161
SID_TRG_TARGET_H_E2R		EQU	1	; ENV2 Release
162
SID_TRG_TARGET_H_L1		EQU	2	; LFO1 sync
163
SID_TRG_TARGET_H_L2		EQU	3	; LFO2 sync
164
SID_TRG_TARGET_H_L3		EQU	4	; LFO3 sync
165
SID_TRG_TARGET_H_L4		EQU	5	; LFO4 sync
166
SID_TRG_TARGET_H_L5		EQU	6	; LFO5 sync
167
SID_TRG_TARGET_H_L6		EQU	7	; LFO6 sync
168
SID_TRG_TARGET_U_W1R		EQU	0	; WT1 reset
169
SID_TRG_TARGET_U_W2R		EQU	1	; WT2 reset
170
SID_TRG_TARGET_U_W3R		EQU	2	; WT3 reset
171
SID_TRG_TARGET_U_W4R		EQU	3	; WT4 reset
172
SID_TRG_TARGET_U_W1S		EQU	4	; WT1 step
173
SID_TRG_TARGET_U_W2S		EQU	5	; WT2 step
174
SID_TRG_TARGET_U_W3S		EQU	6	; WT3 step
175
SID_TRG_TARGET_U_W4S		EQU	7	; WT4 step
176
 
177
;; ==========================================================================
178
 
179
 
180
;; --------------------------------------------------------------------------
181
;;  SID Sound Engine Handler: Software Synthesizer part for the SID
182
;;  called by User Timer every 1 mS
183
;; --------------------------------------------------------------------------
184
SIDSE_Handler
185
	SET_BSR	SID_BASE		; prepare BSR for SID register access
186
 
748 tk 187
	;; return immediately if engine has been disabled or direct MBNet access
188
	movf	SID_STAT, W
189
	andlw	(1 << SID_STAT_ENGINE_DISABLE) | (1 << SID_STAT_ENGINE_DISABLE_LEVEL0) | (1 << SID_STAT_MBNET_ACCESS)
190
	skpz
1 tk 191
	return
192
 
193
#ifdef SID_SE_MEASURE_PERFORMANCE_PORT
194
	bsf	SID_SE_MEASURE_PERFORMANCE_PORT
195
#endif
196
 
197
	;; save FSR0[LH] and PROD[LH] - we are in an interrupt routine
198
	movff	FSR0L, SAVED_FSR0L
199
	movff	FSR0H, SAVED_FSR0H
200
	movff	PRODL, SAVED_PRODL
201
	movff	PRODH, SAVED_PRODH
202
 
203
	;; branch depending on engine
204
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
205
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Handler_23
206
SIDSE_Handler_01
207
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Handler_1
208
SIDSE_Handler_0
209
	call	SIDSE_L_Handler
210
	rgoto	SIDSE_Handler_Cont
211
SIDSE_Handler_1
212
	call	SIDSE_B_Handler
213
	rgoto	SIDSE_Handler_Cont
214
 
215
SIDSE_Handler_23
216
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Handler_3
217
SIDSE_Handler_2
218
	call	SIDSE_D_Handler
219
	rgoto	SIDSE_Handler_Cont
220
SIDSE_Handler_3
221
	call	SIDSE_M_Handler
222
	rgoto	SIDSE_Handler_Cont
223
 
224
SIDSE_Handler_Cont
225
 
226
	;; thats all
227
	movff	SAVED_FSR0L, FSR0L		; copy back saved FSR0[LH]
228
	movff	SAVED_FSR0H, FSR0H
229
	movff	SAVED_PRODL, PRODL		; copy back saved PROD[LH]
230
	movff	SAVED_PRODH, PRODH
231
 
232
#ifdef SID_SE_MEASURE_PERFORMANCE_PORT
233
	bcf	SID_SE_MEASURE_PERFORMANCE_PORT
234
#endif
235
 
236
	return
237
 
238
 
239
 
240
 
241
;; --------------------------------------------------------------------------
242
;; This function handles the global clock
243
;; --------------------------------------------------------------------------
244
SIDSE_Clk
245
	;; by default no clock event
246
	bcf	SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED
247
 
248
	;; increment the clock counter, used to measure the delay between two F8 events
249
	;; see also USER_MIDI_NotifyRx
250
	;; ensure that it doesn't overrun
251
	incf	SID_INCOMING_CLK_CTR, W, BANKED
252
	skpz
253
	incf	SID_INCOMING_CLK_CTR, F, BANKED
254
 
255
#if 0
256
	;; try: if no slave clock is received, increment sent clock counter slowly
257
	;; (disabled by default - works fine, but is inconsistent)
258
	movf	SID_INCOMING_CLK_CTR, W, BANKED
259
	andlw	0x3f
260
	skpnz
261
	incf	SID_CLK_REQ_CTR, F, BANKED
262
#endif
263
 
878 tk 264
	;; now determine master/slave flag depending on ensemble setup
1 tk 265
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
266
	BRA_IFSET WREG, SID_ENS_CTRL1_CLK_AUTO, ACCESS, SIDSE_Clk_ModeAuto
267
	BRA_IFSET WREG, SID_ENS_CTRL1_CLK_SLAVE, ACCESS, SIDSE_Clk_ModeSlave
268
SIDSE_Clk_ModeMaster
269
	bcf	SID_STAT, SID_STAT_CLK_SLAVE
270
	rgoto	SIDSE_Clk_Mode_Cont
271
SIDSE_Clk_ModeSlave
272
	bsf	SID_STAT, SID_STAT_CLK_SLAVE
273
	rgoto	SIDSE_Clk_Mode_Cont
274
SIDSE_Clk_ModeAuto
275
	;; slave mode so long INCOMING_CLK_CTR != 0xff
276
	bcf	SID_STAT, SID_STAT_CLK_SLAVE
277
	incf	SID_INCOMING_CLK_CTR, W, BANKED
278
	skpz
279
	bsf	SID_STAT, SID_STAT_CLK_SLAVE
280
	;; 	rgoto	SIDSE_Clk_Mode_Cont
281
SIDSE_Clk_Mode_Cont
282
 
283
	;; decrement sent clock delay, send interpolated clock events 3 times
284
	decf	SID_SENT_CLK_DELAY, F, BANKED
285
	bnz	SIDSE_Clk_NoSlaveTrigger
286
SIDSE_Clk_SlaveTrigger
287
	movf	SID_SENT_CLK_CTR, W, BANKED
288
	xorlw	0x03
289
	bz	SIDSE_Clk_NoSlaveTrigger
290
	incf	SID_SENT_CLK_CTR, F, BANKED
291
	incf	SID_CLK_REQ_CTR, F, BANKED
292
	rrf	SID_INCOMING_CLK_DELAY, W, BANKED
293
	rrf	WREG, W
294
	andlw	0x3f
295
	movwf	SID_SENT_CLK_DELAY, BANKED
296
SIDSE_Clk_NoSlaveTrigger
297
 
298
	;; handle FA event (MIDI clock start)
299
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Clk_NoFA
300
SIDSE_Clk_FA
1102 tk 301
	;; send to MIDI OUT?
302
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
303
	BRA_IFCLR WREG, SID_ENS_CTRL1_CLK_OUT, ACCESS, SIDSE_Clk_FA_NoOut
304
SIDSE_Clk_FA_Out
305
	;; handled in USER_Tick
306
	SET_BSR	SID_CLK_SEND_FA
307
	bsf	SID_CLK_SEND_FA, 0, BANKED
308
	SET_BSR	SID_BASE
309
SIDSE_Clk_FA_NoOut
310
 
1 tk 311
	;; request not cleared here, because it's also used by Arp and sequencer
312
	;; must be cleared at end of update cycle
313
	;; 	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED
314
	;; reset counters
315
	clrf	SID_SE_GLOBAL_CLK_CTR, BANKED
316
	;; propagate LFO/Env/WT sync via trigger matrix
317
	;; (static for Multi Engine)
318
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
319
	andlw	0x03
320
	bz	SIDSE_Clk_FA_Lead
321
SIDSE_Clk_FA_Multi
322
	;; no reset - this disturbs sequence recordings
323
#if 0
324
	movlw	0xfc		; LFO reset
325
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
326
	movlw	0x3f		; WT reset for all 6 instruments
327
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
328
#endif
329
	rgoto	SIDSE_Clk_FA_Multi_Cont
330
 
331
SIDSE_Clk_FA_Lead
332
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 0, WREG
333
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
334
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 1, WREG
335
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
336
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 2, WREG
337
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
338
SIDSE_Clk_FA_Multi_Cont
339
SIDSE_Clk_NoFA
340
 
341
	;; handle F8 event (MIDI clock)
342
	movf	SID_CLK_REQ_CTR, W, BANKED
343
	bz	SIDSE_Clk_NoF8
344
SIDSE_Clk_F8
345
	;; decrement counter by one (if there are more requests, they will be handled on next handler invocation
346
	decf	SID_CLK_REQ_CTR, F, BANKED
347
	;; if slave: continue at inc routine
348
	BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SIDSE_Clk_Inc
349
SIDSE_Clk_NoF8
350
 
351
	;; if slave: no Inc (only on F8 event)
352
	BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SIDSE_Clk_NoInc
353
 
354
	;; check timer0 overrun flag
355
	BRA_IFCLR INTCON, TMR0IF, ACCESS, SIDSE_Clk_NoInc
356
	bcf	INTCON, TMR0IF			; clear overrun flag
357
	SET_BSR	TIMER0_RELOAD_L
358
	bcf	T0CON, TMR0ON
359
	movf	TIMER0_RELOAD_L, W, BANKED	; (dummy add to update TMR0H, and to get carry flag of addition)
360
	addwf	TMR0L, W			; (update TMR0H)
361
	movf	TIMER0_RELOAD_H, W, BANKED
362
	addwfc	TMR0H, F
363
	movf	TIMER0_RELOAD_L, W, BANKED
364
	addwf	TMR0L, F			; 16bit register update takes place with this write
365
	bsf	T0CON, TMR0ON
366
	SET_BSR	SID_BASE
367
SIDSE_Clk_Inc
368
 
248 tk 369
	;; increment global clock counter (for Clk/6 and Clk/24 divider)
1 tk 370
	incf	SID_SE_GLOBAL_CLK_CTR, F, BANKED
371
 
1102 tk 372
	;; send to MIDI OUT?
373
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
374
	andlw	0x03
375
	bnz	SIDSE_Clk_F8_NoOut
376
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
377
	BRA_IFCLR WREG, SID_ENS_CTRL1_CLK_OUT, ACCESS, SIDSE_Clk_F8_NoOut
378
SIDSE_Clk_F8_Out
379
	;; handled in USER_Tick
380
	SET_BSR	SID_CLK_SEND_F8_CTR
381
	incf	SID_CLK_SEND_F8_CTR, W, BANKED
382
	bz	SIDSE_Clk_F8_NoOut  ; counter is 0xff - not serviced...?
383
	incf	SID_CLK_SEND_F8_CTR, F, BANKED
384
SIDSE_Clk_F8_NoOut
385
	SET_BSR	SID_BASE
386
 
248 tk 387
	;; reset lower nibble on each 6th clock, increment high nibble
388
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
389
	andlw	0x0f
390
	xorlw	0x06
1102 tk 391
	bz	SIDSE_Clk_Inc_6th
392
 
393
	;; if 12 is reached, we also reset the subcounter
394
	;; previously it was at 6, but we need a value dividable by 4 for the SID_CLK_SEND_F8 function
395
	xorlw	0x0c ^ 0x06	; reset at 12
248 tk 396
	bnz	SIDSE_Clk_Inc_Not6th
1102 tk 397
	movlw	0xf0
398
	andwf	SID_SE_GLOBAL_CLK_CTR, F, BANKED
248 tk 399
SIDSE_Clk_Inc_6th
400
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
401
	addlw	0x10
402
	movwf	SID_SE_GLOBAL_CLK_CTR, BANKED
403
SIDSE_Clk_Inc_Not6th
404
 
1 tk 405
	;; notify clock event
406
	bsf	SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED
407
 
408
	;; clock propagation
409
	;; (static for Multi Engine)
410
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
411
	andlw	0x03
412
	bz	SIDSE_Clk_Reset_Lead
413
SIDSE_Clk_Reset_Multi
414
	movlw	0x80		; only step WTs (global flag bit #7 in multi mode)
415
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
416
	rgoto	SIDSE_Clk_Reset_Multi_Cont
248 tk 417
 
1 tk 418
SIDSE_Clk_Reset_Lead
419
 
420
	;; propagate clock event to trigger matrix
421
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_Clk_BASE
422
	rcall	SIDSE_Clk_Hlp_PropClkEvent
423
 
248 tk 424
	;; propagate clock/4 event to trigger matrix on each 6th clock
425
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_Cl6_BASE
1 tk 426
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
248 tk 427
	andlw	0x0f
1102 tk 428
	bnz	SIDSE_Clk_Reset_NoClk4
429
SIDSE_Clk_Reset_Clk4
1 tk 430
	rcall	SIDSE_Clk_Hlp_PropClkEvent
1102 tk 431
SIDSE_Clk_Reset_NoClk4
1 tk 432
 
248 tk 433
	;; propagate clock/16 event to trigger matrix on each 24th clock
434
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_C24_BASE
1 tk 435
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
248 tk 436
	andlw	0x30
1 tk 437
	skpnz
438
	rcall	SIDSE_Clk_Hlp_PropClkEvent
439
 
440
SIDSE_Clk_Reset_Multi_Cont
441
SIDSE_Clk_NoReset
442
SIDSE_Clk_NoInc
443
 
444
SIDSE_Clk_End
445
	return
446
 
447
 
448
;; expecting pointer to SID_Ix_L_TRG_Clk*_BASE in FSR1
449
SIDSE_Clk_Hlp_PropClkEvent
450
	movf	POSTINC1, W
451
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
452
	movf	POSTINC1, W
453
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
454
	movf	POSTINC1, W
455
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
456
	return
457
 
458
 
459
 
460
;; --------------------------------------------------------------------------
461
;; This function handles the arpeggiators
462
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
463
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
464
;;     pointer to SIDx_MVx_BASE in FSR2 (MIDI voice record)
465
;;     Voice number in SID_SE_ELEMENT_NUM
466
;; --------------------------------------------------------------------------
467
SIDSE_Arp
468
	;; TODO: portamento handling on note overlaps
469
 
470
	;; clear temporary arp flags
471
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
472
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED
473
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
474
 
475
	;; check if arp sync requested
476
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Arp_Sync
477
	movlw	SID_MVx_ARP_STATE
478
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_SYNC_ARP, ACCESS, SIDSE_Arp_NoSync
479
SIDSE_Arp_Sync
480
	;; set arp counters to max value (forces proper reset)
481
	movlw	SID_MVx_ARP_NOTE_CTR
482
	setf	PLUSW2
483
	movlw	SID_MVx_ARP_OCT_CTR
484
	setf	PLUSW2
485
 
486
	;; reset ARP up flag (will be set to 1 with first note)
487
	movlw	SID_MVx_ARP_STATE
488
	bcf	PLUSW2, SID_MV_ARP_STATE_ARP_UP
489
 
490
	;; request first note (for oneshot function)
491
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED
492
 
493
	;; reset divider if not disabled or if arp synch on MIDI clock start event
494
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Arp_DivReset
495
	movlw	SID_Ix_Vx_ARP_MODE
496
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIV_SYNC, ACCESS, SIDSE_Arp_NoDivReset
497
SIDSE_Arp_DivReset
498
	movlw	SID_MVx_ARP_DIV_CTR
499
	setf	PLUSW2
500
	movlw	SID_MVx_ARP_GL_CTR
501
	setf	PLUSW2
502
	;; request new note
503
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
504
SIDSE_Arp_NoDivReset
505
SIDSE_Arp_NoSync
506
 
507
	;; if clock sync event:
508
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_Arp_NoClk
509
SIDSE_Arp_Clk
510
	;; increment clock divider
511
	;; reset divider if it already has reached the target value
512
 
513
	movlw	SID_Ix_Vx_ARP_MODE
514
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_CAC, ACCESS, SIDSE_Arp_Clk_NoCAC
515
SIDSE_Arp_Clk_CAC
516
	;; in CAC mode: increment depending on number of pressed keys
517
	movlw	SID_MVx_NOTE_STACK_PTR	; using note of MV1 note stack
518
	movf	PLUSW2, W
519
	skpnz
520
	movlw	1
521
	movwf	PRODL
522
	rgoto	SIDSE_Arp_Clk_CAC_Cont
523
 
524
SIDSE_Arp_Clk_NoCAC
525
	;; if CAC disabled: increment only by one
526
	movlw	1
527
	movwf	PRODL
528
 
529
SIDSE_Arp_Clk_CAC_Cont
530
	;; add to div counter, temp. store result in PRODL
531
	movlw	SID_MVx_ARP_DIV_CTR
532
	movf	PLUSW2, W
533
	addwf	PRODL, F
534
 
535
	;; max value -> PRODH
536
	movlw	SID_Ix_Vx_ARP_SPEED_DIV
537
	movf	PLUSW0, W
538
	andlw	0x3f
539
	addlw	1
540
	movwf	PRODH
541
 
542
	;; now subtract PRODH from PRODL until PRODL is < PRODH
543
SIDSE_Arp_Clk_FixLoop
544
	decf	PRODH, W
545
	cpfsgt	PRODL, ACCESS
546
	rgoto SIDSE_Arp_Clk_FixLoop_Break
547
	movf	PRODH, W
548
	subwf	PRODL, F	; F-WREG
549
 
550
	;; request new note
551
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
552
 
553
	;; request gate clear if voice not active anymore (required if Gln>=Speed)
554
	movlw	SID_Vx_STATE
555
	btfss	PLUSW1, SID_V_STATE_VOICE_ACTIVE
556
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
557
 
558
	rgoto	SIDSE_Arp_Clk_FixLoop
559
 
560
SIDSE_Arp_Clk_FixLoop_Break
561
 
302 tk 562
	;; transfer new divider value into MVx register
1 tk 563
	movlw	SID_MVx_ARP_DIV_CTR
564
	movff	PRODL, PLUSW2
565
 
566
 
567
	;; increment gatelength counter
568
	;; reset counter if it already has reached the target value
569
	movlw	SID_MVx_ARP_GL_CTR
570
	incf	PLUSW2, F
571
	decf	PLUSW2, W
572
	movwf	PRODL
573
	movlw	SID_Ix_Vx_ARP_GL_RNG
574
	movf	PLUSW0, W
575
	andlw	0x1f
576
	addlw	1
577
	cpfslt	PRODL, ACCESS
302 tk 578
	rgoto	SIDSE_Arp_Clk_GlReset
1 tk 579
	rgoto	SIDSE_Arp_Clk_NoGlReset
580
SIDSE_Arp_Clk_GlReset
581
	;; reset counter
582
	movlw	SID_MVx_ARP_GL_CTR
583
	clrf	PLUSW2
584
 
585
	;; request gate clear
586
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
587
SIDSE_Arp_Clk_NoGlReset
588
 
589
SIDSE_Arp_NoClk
590
 
591
 
592
	;; check if HOLD mode has been deactivated - disable notes in this case
593
	movlw	SID_Ix_Vx_ARP_MODE
594
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_HOLD, ACCESS, SIDSE_Arp_Hold_Active
595
SIDSE_Arp_Hold_NotActive
596
	;; check if HOLD flag was active before
597
	movlw	SID_MVx_ARP_STATE
598
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED, ACCESS, SIDSE_Arp_Hold_Cont
599
	;; clear HOLD flag and disable all notes
600
	bcf	PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED
601
	rgoto	SIDSE_Arp_NotActive
602
 
603
SIDSE_Arp_Hold_Active
604
	;; store HOLD flag in MIDI voice record
605
	movlw	SID_MVx_ARP_STATE
606
	bsf	PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED
607
SIDSE_Arp_Hold_Cont
608
 
609
 
610
	;; skip the rest if arp is disabled
611
	movlw	SID_Ix_Vx_ARP_MODE
612
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_ENABLE, ACCESS, SIDSE_Arp_Active
613
SIDSE_Arp_NotActive
614
	;; check if arp was active before (for proper 1->0 transition when ARP is disabled)
615
	movlw	SID_MVx_ARP_STATE
616
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE, ACCESS, SIDSE_Arp_End
617
 
618
	;; notify that arp is not active anymore
619
	bcf	PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE
620
 
621
	;; clear note stack (especially important in HOLD mode!)
622
	movlw	SID_MVx_NOTE_STACK_PTR
623
	movwf	PRODL
624
SIDSE_Arp_NotActive_ClrLoop
625
	movf	PRODL, W
626
	clrf	PLUSW2
627
	incf	PRODL, F
628
	movlw	SID_MVx_NOTE_STACK_0 + SID_MVx_NOTE_STACK_LEN - 1
629
	cpfsgt	PRODL, ACCESS
630
	rgoto SIDSE_Arp_NotActive_ClrLoop
631
 
632
	;; propagate Note Off through trigger matrix
633
	;; (static for Multi Engine)
634
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
635
	andlw	0x03
636
	bz	SIDSE_Arp_NotActive_ClrLoop_L
637
SIDSE_Arp_NotActive_ClrLoop_M
638
	;; only ENV release phase
639
	movf	SID_SE_ELEMENT_NUM, W, BANKED
640
	call	MIOS_HLP_GetBitORMask
641
	iorwf	SID_SE_TRG_EVNT_ENVR, F, BANKED
642
	rgoto	SIDSE_Arp_NotActive_ClrLoop_C
643
SIDSE_Arp_NotActive_ClrLoop_L
644
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, WREG
379 tk 645
	andlw	0xc0		; (Gates handled separately by Arp)
1 tk 646
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
647
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 1, WREG
648
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
649
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 2, WREG
650
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
651
SIDSE_Arp_NotActive_ClrLoop_C
652
 
653
	;; request gate clear
654
	movlw	SID_Vx_STATE
655
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
656
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
657
 
658
	rgoto	SIDSE_Arp_End
659
 
660
 
661
SIDSE_Arp_Active
662
	;; notify that arp is active (for proper 1->0 transition when ARP is disabled)
663
	movlw	SID_MVx_ARP_STATE
664
	bsf	PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE
665
 
666
	;; check if voice not active anymore (not valid in HOLD mode) or gate clear has been requested
667
	;; skip voice active check in hold mode
668
	movlw	SID_Ix_Vx_ARP_MODE
669
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_HOLD, ACCESS, SIDSE_Arp_GateClr_Hold
670
	;; skip voice active check in voice sync mode
671
	movlw	SID_Ix_Vx_ARP_MODE
672
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIV_SYNC, ACCESS, SIDSE_Arp_GateClr_Sync
673
	movlw	SID_Vx_STATE
674
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SIDSE_Arp_GateClr
675
SIDSE_Arp_GateClr_Sync
676
SIDSE_Arp_GateClr_Hold
677
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED, SIDSE_Arp_NoGateClr
678
SIDSE_Arp_GateClr
679
	;; forward this to note handler if gate is not already deactivated
680
	movlw	SID_Vx_STATE
681
	BRA_IFCLR PLUSW1, SID_V_STATE_GATE_ACTIVE, ACCESS, SIDSE_Arp_NoGateClr
682
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
683
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
684
	;; Note Off ENV/LFO/... synchronisation via trigger matrix
685
	;; (static for Multi Engine)
686
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
687
	andlw	0x03
688
	bz	SIDSE_Arp_GateClr_Lead
689
SIDSE_Arp_GateClr_Multi
690
	;; only ENV release phase
691
	movf	SID_SE_ELEMENT_NUM, W, BANKED
692
	call	MIOS_HLP_GetBitORMask
693
	iorwf	SID_SE_TRG_EVNT_ENVR, F, BANKED
694
	rgoto	SIDSE_Arp_GateClr_Multi_Cont
695
SIDSE_Arp_GateClr_Lead
696
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, WREG
379 tk 697
	andlw	0xc0		; (Gates handled separately by Arp)
1 tk 698
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
699
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 1, WREG
700
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
701
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 2, WREG
702
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
703
SIDSE_Arp_GateClr_Multi_Cont
704
SIDSE_Arp_NoGateClr
705
 
706
	;; check if a new arp note has been requested
707
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED, SIDSE_Arp_NoNewNote
708
SIDSE_Arp_NewNote
709
	;; skip if note counter is 0xaa (oneshot mode)
710
	movlw	SID_MVx_ARP_NOTE_CTR
711
	movf	PLUSW2, W
712
	xorlw	0xaa
713
	skpnz
714
	rgoto	SIDSE_Arp_NoNewNote
715
 
716
	;; increment arp counter
717
	movlw	SID_MVx_ARP_NOTE_CTR
718
	incf	PLUSW2, F
719
 
720
	;; reset gatelength counter
721
	movlw	SID_MVx_ARP_GL_CTR
722
	clrf	PLUSW2
723
 
724
	;; if max value of arp note counter reached, reset it
725
	movlw	SID_MVx_ARP_NOTE_CTR
726
	movff	PLUSW2, PRODL
727
	movlw	SID_MVx_NOTE_STACK_LEN
728
	cpfslt	PRODL, ACCESS
729
	clrf PRODL
730
 
731
	;; if note is zero, reset arp note counter
732
	movf	PRODL, W
733
	addlw	SID_MVx_NOTE_STACK_0
734
	movf	PLUSW2, W
735
	skpnz
736
	clrf	PRODL
737
 
738
	;; don't play if note still zero
739
	movf	PRODL, W
740
	addlw	SID_MVx_NOTE_STACK_0
741
	movf	PLUSW2, W
742
	skpnz
743
	rgoto	SIDSE_Arp_NoNewNote
744
 
745
	;; store new arp note counter
746
	movlw	SID_MVx_ARP_NOTE_CTR
747
	movff	PRODL, PLUSW2
748
 
749
	;; dir mode 6 (and 7) selects random direction
750
	movlw	SID_Ix_Vx_ARP_MODE
751
	rrf	PLUSW0, W
752
	andlw	0x06
753
	xorlw	0x06
754
	bz	SIDSE_Arp_NewNote_Rnd
755
 
756
	;; in DIR_ALT mode: branch depending on Up/Down flag
757
	movlw	SID_Ix_Vx_ARP_MODE
758
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_ALT2, ACCESS, SIDSE_Arp_NewNote_AltDir
759
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_DIR_ALT, ACCESS, SIDSE_Arp_NewNote_NoAltDir
760
SIDSE_Arp_NewNote_AltDir
761
	;; toggle ARP_UP flag each time the arp note counter is zero
762
	movf	PRODL, W
763
	bnz	SIDSE_Arp_NewNote_AltDir_NoTog
764
SIDSE_Arp_NewNote_AltDir_Tog
765
	movlw	SID_MVx_ARP_STATE
766
	btg	PLUSW2, SID_MV_ARP_STATE_ARP_UP
767
 
768
	;; if not ALT2 mode: increment PRODL to prevent double played notes
769
	movlw	SID_Ix_Vx_ARP_MODE
770
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_ALT2, ACCESS, SIDSE_Arp_NewNote_AltDir_Alt2
771
SIDSE_Arp_NewNote_AltDirNoAlt2
772
	incf	PRODL, F
773
SIDSE_Arp_NewNote_AltDir_Alt2
774
 
775
	;; reset PRODL again if note is zero (only one note played)
776
	movf	PRODL, W
777
	addlw	SID_MVx_NOTE_STACK_0
778
	movf	PLUSW2, W
779
	skpnz
780
	clrf	PRODL
781
 
782
	;; store updated arp note counter
783
	movlw	SID_MVx_ARP_NOTE_CTR
784
	movff	PRODL, PLUSW2
785
SIDSE_Arp_NewNote_AltDir_NoTog
786
 
787
	;; branch depending on Arp Up/Down and Alt Up/Down flag
788
	movlw	SID_Ix_Vx_ARP_MODE
789
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_DOWN, ACCESS, SIDSE_Arp_NewNote_AltDir_D
790
SIDSE_Arp_NewNote_AltDir_U
791
	movlw	SID_MVx_ARP_STATE
792
	BRA_IFSET PLUSW2, SID_MV_ARP_STATE_ARP_UP, ACCESS, SIDSE_Arp_NewNote_Up
793
	rgoto	SIDSE_Arp_NewNote_Down
794
SIDSE_Arp_NewNote_AltDir_D
795
	movlw	SID_MVx_ARP_STATE
796
	BRA_IFSET PLUSW2, SID_MV_ARP_STATE_ARP_UP, ACCESS, SIDSE_Arp_NewNote_Down
797
	rgoto	SIDSE_Arp_NewNote_Up
798
 
799
SIDSE_Arp_NewNote_NoAltDir
800
 
801
	;; branch depending on direction
802
	movlw	SID_Ix_Vx_ARP_MODE
803
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_DIR_DOWN, ACCESS, SIDSE_Arp_NewNote_Up
804
SIDSE_Arp_NewNote_Down
805
	;; offset to last note stack entry: PTR-1-PRODL
806
	movlw	SID_MVx_NOTE_STACK_PTR
807
	movf	PLUSW2, W
808
	bz	SIDSE_Arp_NewNote_Down_NoNote
809
	addlw	-1
810
	movwf	PRODH
811
	movf	PRODL, W
812
	subwf	PRODH, W
813
	movwf	PRODL
814
SIDSE_Arp_NewNote_Down_NoNote
815
	rgoto	SIDSE_Arp_NewNote_Down_Cont
816
 
817
SIDSE_Arp_NewNote_Rnd
818
	;; generate new random number
819
	call	SID_RND_GenRandomNumber
820
	;; scale between 0 and SID_MVx_NOTE_STACK_PTR-1
821
	movlw	SID_MVx_NOTE_STACK_PTR
822
	movf	PLUSW2, W	; (ok, no dec!)
823
	mulwf	SID_RANDOM_SEED_L, BANKED
824
	movff	PRODH, PRODL	; new pointer in PRODL
825
 
826
SIDSE_Arp_NewNote_Down_Cont
827
SIDSE_Arp_NewNote_Up
828
 
878 tk 829
	;; now check for oneshot mode: if note is 0, or if note counter and oct counter is 0, stop here
1 tk 830
	movlw	SID_Ix_Vx_ARP_SPEED_DIV
831
	BRA_IFCLR PLUSW0, SID_I_V_ARP_SPEED_DIV_ONESHOT, ACCESS, SIDSE_Arp_NewNote_NoOneShot
832
SIDSE_Arp_NewNote_OneShot
833
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED, SIDSE_Arp_NewNote_NoOneShot
834
	movf	PRODL, W
835
	addlw	SID_MVx_NOTE_STACK_0
836
	movf	PLUSW2, W
837
	bz	SIDSE_Arp_NewNote_OneShot_Ok
838
	movf	PRODL, W
839
	movlw	SID_MVx_ARP_NOTE_CTR
840
	movf	PLUSW2, W
841
	bnz	SIDSE_Arp_NewNote_NoOneShot
842
	movlw	SID_MVx_ARP_OCT_CTR
843
	movf	PLUSW2, W
844
	bnz	SIDSE_Arp_NewNote_NoOneShot
845
 
846
SIDSE_Arp_NewNote_OneShot_Ok
847
	;; set note counter to 0xaa to stop ARP until next reset
848
	movlw	0xaa
849
	movwf	PRODL
850
	movlw	SID_MVx_ARP_NOTE_CTR
851
	movff	PRODL, PLUSW2
852
	rgoto	SIDSE_Arp_NoNewNote
853
SIDSE_Arp_NewNote_NoOneShot
854
 
855
	;; store new arp note if != 0
856
	movf	PRODL, W
857
	addlw	SID_MVx_NOTE_STACK_0
858
	movf	PLUSW2, W
859
	andlw	0x7f
860
	movwf	PRODH
861
	movlw	SID_Vx_ARP_NOTE
862
	skpz
863
	movff	PRODH, PLUSW1
864
 
865
	;; if counter is 0, increase octave until max value is reached
866
	movf	PRODL, W
867
	bnz	SIDSE_Arp_NewNote_NoOctInc
868
SIDSE_Arp_NewNote_OctInc
869
	movlw	SID_MVx_ARP_OCT_CTR
870
	incf	PLUSW2, F
871
	decf	PLUSW2, W
872
	movwf	PRODL
873
	movlw	SID_Ix_Vx_ARP_GL_RNG
874
	swapf	PLUSW0, W
875
	rrf	WREG, W
876
	andlw	0x07
877
	cpfslt	PRODL, ACCESS
878
	rgoto SIDSE_Arp_NewNote_OctReset
879
	rgoto	SIDSE_Arp_NewNote_NoOctReset
880
SIDSE_Arp_NewNote_OctReset
881
	;; reset octave counter
882
	movlw	SID_MVx_ARP_OCT_CTR
883
	clrf	PLUSW2
884
SIDSE_Arp_NewNote_NoOctReset
885
 
886
SIDSE_Arp_NewNote_NoOctInc
887
	;; transpose note by 12*octave counter
888
	movlw	SID_MVx_ARP_OCT_CTR
889
	movf	PLUSW2, W
890
	bz	SIDSE_Arp_NewNote_OctNoTrans
891
	mullw	12
892
SIDSE_Arp_NewNote_OctTrans
893
	movlw	SID_Vx_ARP_NOTE
894
	movf	PLUSW1, W
895
	addwf	PRODL, W
896
	movwf	PRODH
897
 
898
	;; if >0x6b, decrement by 12 until we are in 0x00..0x6b range again
899
	;; (range 0x6c..0x7f sets frequency to 0xffff...)
900
SIDSE_Arp_NewNote_OctTransSat
901
	movlw	0x6b
902
	cpfsgt	PRODH, ACCESS
903
	rgoto SIDSE_Arp_NewNote_OctTransOk
904
	movlw	-12
905
	addwf	PRODH, F
906
	rgoto	SIDSE_Arp_NewNote_OctTransSat
907
SIDSE_Arp_NewNote_OctTransOk
908
	movlw	SID_Vx_ARP_NOTE
909
	movff	PRODH, PLUSW1
910
SIDSE_Arp_NewNote_OctNoTrans
911
 
912
	;; forward gate set request if voice is active and gate not active
913
	movlw	SID_Vx_STATE
914
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SIDSE_Arp_NewNote_NoOn
915
SIDSE_Arp_NewNote_NoVAChk
916
	movlw	SID_Vx_STATE
917
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ	; ensure that gate won't be cleared by previous CLR_REQ
918
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_ACTIVE, ACCESS, SIDSE_Arp_NewNote_NoOn
919
SIDSE_Arp_NewNote_On
920
	;; set gate
921
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
922
 
923
	;; Note On ENV/LFO/... synchronisation via trigger matrix
924
	;; (static for Multi Engine)
925
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
926
	andlw	0x03
927
	bz	SIDSE_Arp_NewNote_Lead
928
SIDSE_Arp_NewNote_Multi
929
	;; only ENV attack, LFO sync and WT reset
930
	movf	SID_SE_ELEMENT_NUM, W, BANKED
931
	call	MIOS_HLP_GetBitORMask
932
	iorwf	SID_SE_TRG_EVNT_ENVA, F, BANKED
933
 
934
	movf	SID_SE_ELEMENT_NUM, W, BANKED
935
	addlw	2
936
	call	MIOS_HLP_GetBitORMask
937
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
938
 
939
	movlw	0x3f
940
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
941
	;; TODO: optional LFO resync!
942
	rgoto	SIDSE_Arp_NewNote_Cont
943
 
944
SIDSE_Arp_NewNote_Lead
945
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 0, WREG
379 tk 946
	andlw	0xc0		; (gates handled separately)
1 tk 947
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
948
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 1, WREG
949
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
950
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 2, WREG
951
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
952
SIDSE_Arp_NewNote_Cont
953
SIDSE_Arp_NewNote_NoOn
954
 
955
SIDSE_Arp_NoNewNote
956
 
957
SIDSE_Arp_End
958
	;; clear arp sync flag
959
	movlw	SID_MVx_ARP_STATE
960
	bcf	PLUSW2, SID_MV_ARP_STATE_SYNC_ARP
961
 
962
	return
963
 
964
 
965
 
966
;; --------------------------------------------------------------------------
967
;; This function handles the Voice Gate
968
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
969
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
970
;;     Voice number in SID_SE_ELEMENT_NUM
971
;;     If SIDSE_Gate_Drums is called: bit #4 of Waveform (disable bit) in IRQ_TMP1
972
;; OUT: ZERO flag set if pitch should be changed
973
;; --------------------------------------------------------------------------
974
SIDSE_Gate
975
	;; small variation between Lead/Bassline/Multi Engine, and Drum Engine:
976
	;; for Drum Engine the waveform is predefined in model table, and not
977
	;; part of the patch (drum engine has to call SIDSE_Gate_Drums with
978
	;; waveform[4] in IRQ_TMP1)
979
	movlw	SID_Ix_Vx_WAVEFORM
980
	movff	PLUSW0, IRQ_TMP1
981
 
982
SIDSE_Gate_Drums		; expecting waveform[4] in IRQ_TMP1
983
 
984
	;; transfer pointer to SIDx_Vx_FRQ_L register -> FSR2
985
	call	SIDSE_Hlp_GetSIDFrqPtr
986
 
987
	;; voice disable handling (allows to turn on/off voice via waveform parameter)
988
	movlw	SID_Vx_STATE
989
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_DISABLED, ACCESS, SIDSE_Gate_VoiceNotDisabled
990
SIDSE_Gate_VoiceDisabled
991
	BRA_IFSET IRQ_TMP1, 4, ACCESS, SIDSE_Gate_Voice_Cont	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
992
	movlw	SID_Vx_STATE
993
	bcf	PLUSW1, SID_V_STATE_VOICE_DISABLED
994
	btfsc	PLUSW1, SID_V_STATE_VOICE_ACTIVE
995
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
996
	rgoto	SIDSE_Gate_Voice_Cont
997
SIDSE_Gate_VoiceNotDisabled
998
	BRA_IFCLR IRQ_TMP1, 4, ACCESS, SIDSE_Gate_Voice_Cont	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
999
	movlw	SID_Vx_STATE
1000
	bsf	PLUSW1, SID_V_STATE_VOICE_DISABLED
1001
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
1002
	;; 	rgoto	SIDSE_Gate_Voice_Cont
1003
SIDSE_Gate_Voice_Cont
1004
 
1005
	;; if gate not active: ignore clear request
1006
	movlw	SID_Vx_STATE
1007
	btfss	PLUSW1, SID_V_STATE_GATE_ACTIVE
1008
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
1009
 
1010
	;; gate set/clear request?
1011
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_CLR_REQ, ACCESS, SIDSE_Gate_ClrReq
1012
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_SET_REQ, ACCESS, SIDSE_Gate_SetReq
1013
	rgoto	SIDSE_Gate_Skip
1014
SIDSE_Gate_ClrReq
1015
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
1016
 
1017
	movlw	SIDx_V1_CTRL
1018
	bcf	PLUSW2, 3	; SIDx_Vx_CTRL.3 is the test bit which allows to sync an oscillator
1019
 
1020
	;; clear SID gate flag (SIDx_Vx_CTRL.0) if GSA (gate stays active) function not enabled
1021
	movlw	SID_Ix_Vx_FLAGS1
1022
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_GSA, ACCESS, SIDSE_Gate_ClrReq_GSA
1023
SIDSE_Gate_ClrReq_NoGSA
1024
	movlw	SIDx_V1_CTRL
1025
	bcf	PLUSW2, 0
1026
SIDSE_Gate_ClrReq_GSA
1027
 
1028
	;; gate not active anymore
1029
	movlw	SID_Vx_STATE
1030
	bcf	PLUSW1, SID_V_STATE_GATE_ACTIVE
1031
 
1032
	;; sync with SID_SR handler
1033
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1034
	call	MIOS_HLP_GetBitORMask
1035
	iorwf	SID_SE_SR_UPDATE_SYNC, F, BANKED	; (cleared by SID_SR_Handler)
1036
 
1037
	rgoto	SIDSE_Gate_End
1038
 
1039
SIDSE_Gate_SetReq
1040
	;; skip so long SRs haven't been updated
1041
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1042
	call	MIOS_HLP_GetBitORMask
1043
	andwf	SID_SE_SR_UPDATE_SYNC, W, BANKED
1044
	bnz	SIDSE_Gate_Skip
1045
 
1046
	;; don't set gate if oscillator disabled
1047
	BRA_IFSET IRQ_TMP1, 4, ACCESS, SIDSE_Gate_SetReqSkp	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
1048
 
1049
	;; temporary shift FSR1 to SID_Vx_SET_DELAY_CTR_L for easier handling
1050
	movlw	SID_Vx_SET_DELAY_CTR_L
1051
	addwf	FSR1L, F
1052
 
1053
	;; delay note so long 16bit delay counter != 0
1054
	movf	POSTINC1, W
1055
	iorwf	POSTDEC1, W
1056
	bz	SIDSE_Gate_SetReq_NoDelay
1057
SIDSE_Gate_SetReq_Delay
1058
	;; increment counter, set it to zero on overrun (no delay anymore)
1059
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1060
	andlw	0x03
1061
	xorlw	0x02
1062
	bnz	SIDSE_Gate_SetReq_Delay_LBM
1063
SIDSE_Gate_SetReq_Delay_D
1064
	clrf	IRQ_TMP3	; not available for drum engine
1065
	rgoto	SIDSE_Gate_SetReq_Delay_Cont
1066
SIDSE_Gate_SetReq_Delay_LBM
1067
	movlw	SID_Ix_Vx_DELAY
1068
	movff	PLUSW0, IRQ_TMP3; incrementer is the same like used for envelopes
1069
SIDSE_Gate_SetReq_Delay_Cont
1070
 
1071
	;; if ABW (ADSR bug workaround) active: use at least 30 ms delay
1072
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
1073
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_Gate_SetReq_DelayNoA
1074
SIDSE_Gate_SetReq_DelayABW
1075
	movlw	25
1076
	addwf	IRQ_TMP3, F
1077
	skpnc
1078
	setf	IRQ_TMP3
1079
SIDSE_Gate_SetReq_DelayNoA
1080
 
1081
	movlw	0x80		; curve *must* be disabled!
1082
	call	SIDSE_Hlp_ENV_GetBendedValue	; incrementer in MIOS_PARAMETER[12]
1083
	movf	MIOS_PARAMETER1, W
1084
	addwf	POSTINC1, F
1085
	movf	MIOS_PARAMETER2, W
1086
	addwfc	POSTDEC1, F
1087
	bc	SIDSE_Gate_SetReq_DelayOv
1088
	movlw	-SID_Vx_SET_DELAY_CTR_L	; switch back to SID_Vx_CTR_L
1089
	addwf	FSR1L, F
1090
#if 0
1091
	rgoto	SIDSE_Gate_End
1092
#else
1093
	;; experimental: don't modify frequency so long delay is active!
1094
	;; this is especially to avoid, that a new note frequency will already be set before the envelope is released
1095
	rgoto	SIDSE_Gate_End_NoPitch
1096
#endif
1097
SIDSE_Gate_SetReq_DelayOv
1098
	;; overrun: clear counter to disable delay
1099
	clrf	POSTINC1
1100
	clrf	POSTDEC1
1101
SIDSE_Gate_SetReq_NoDelay
1102
	movlw	-SID_Vx_SET_DELAY_CTR_L	; switch back to SID_Vx_CTR_L
1103
	addwf	FSR1L, F
1104
 
1105
	;; now acknowledge the set request
1106
	movlw	SID_Vx_STATE
1107
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
1108
 
1109
	;; if ABW (ADSR bug workaround) function active: update ADSR registers now!
1110
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
1111
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_Gate_SetReq_NoABW
1112
SIDSE_Gate_SetReq_ABW
1113
	movlw	SID_Ix_Vx_AD
1114
	movff	PLUSW0, PRODL
1115
	movlw	SIDx_V1_ENV_AD
1116
	movff	PRODL, PLUSW2
1117
 
1118
	;; accent only used in bassline and drum mode
1119
	;; force sustain to maximum if accent active
1120
	movlw	SID_Ix_Vx_SR
1121
	movff	PLUSW0, PRODL
1122
	movlw	SID_Vx_STATE
1123
	BRA_IFCLR PLUSW1, SID_V_STATE_ACCENT, ACCESS, SIDSE_Gate_SetReq_ABW_NoAcc
1124
SIDSE_Gate_SetReq_ABW_Acc
1125
	movlw	0xf0
1126
	iorwf	PRODL, F
1127
SIDSE_Gate_SetReq_ABW_NoAcc
1128
	movlw	SIDx_V1_ENV_SR
1129
	movff	PRODL, PLUSW2
1130
SIDSE_Gate_SetReq_NoABW
1131
 
1132
	;; branch for phase synchronisation: set test flag instead of gate
1133
	;; a special handler in sid_sr.inc will take care about the rest
1134
 
1135
	;; different handling depending on selected engine:
362 tk 1136
	;; lead and bassline engine: global sync for all voices with phase shift
1 tk 1137
	;; multi engine has individual flag for each instrument
1138
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1139
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Gate_SetReq_Sync_DM
1140
SIDSE_Gate_SetReq_Sync_LB
1141
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Gate_SetReq_Sync_B
1142
SIDSE_Gate_SetReq_Sync_L
362 tk 1143
SIDSE_Gate_SetReq_Sync_B
1 tk 1144
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_PHASE, WREG
1145
	andlw	0xff
1146
	bz	SIDSE_Gate_SetReq_NoSync
1147
	rgoto	SIDSE_Gate_SetReq_Sync_Cont
1148
 
362 tk 1149
#if 0
1 tk 1150
SIDSE_Gate_SetReq_Sync_B
1151
	movlw	SID_Ix_B_Vx_FLAGS2
1152
	BRA_IFCLR PLUSW0, SID_I_M_V_FLAGS2_PHASE, ACCESS, SIDSE_Gate_SetReq_NoSync
1153
	rgoto	SIDSE_Gate_SetReq_NoSync
362 tk 1154
#endif
1 tk 1155
 
1156
SIDSE_Gate_SetReq_Sync_DM
1157
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Gate_SetReq_Sync_M
1158
SIDSE_Gate_SetReq_Sync_D
1159
	;; synchronisation requested in SIDSE_D_NOTE_Restart
1160
	rgoto	SIDSE_Gate_SetReq_NoSync
1161
 
1162
SIDSE_Gate_SetReq_Sync_M
1163
	movlw	SID_Ix_M_Vx_FLAGS2
1164
	BRA_IFCLR PLUSW0, SID_I_M_V_FLAGS2_PHASE, ACCESS, SIDSE_Gate_SetReq_NoSync
1165
	;; 	rgoto	SIDSE_Gate_SetReq_Sync_Cont
1166
 
1167
SIDSE_Gate_SetReq_Sync_Cont
1168
	;; set SID test flag (SIDx_Vx_CTRL.3), ensure that gate flag not set
1169
	movlw	SIDx_V1_CTRL
1170
	bsf	PLUSW2, 3
1171
	bcf	PLUSW2, 0
1172
 
1173
	;; notify sync request
1174
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1175
	call	MIOS_HLP_GetBitORMask
1176
	iorwf	SID_SE_PHASE_SYNC_REQ, F, BANKED
1177
 
1178
	rgoto	SIDSE_Gate_SetReq_NoGate
1179
 
1180
SIDSE_Gate_SetReq_NoSync
1181
	;; set SID gate flag (SIDx_Vx_CTRL.0)
1182
	movlw	SIDx_V1_CTRL
1183
	bsf	PLUSW2, 0
1184
 
1185
SIDSE_Gate_SetReq_NoGate
1186
SIDSE_Gate_SetReqSkp
1187
	movlw	SID_Vx_STATE
1188
	bsf	PLUSW1, SID_V_STATE_GATE_ACTIVE
1189
 
1190
SIDSE_Gate_End
1191
SIDSE_Gate_Skip
1192
	iorlw	0xff		; clear ZERO flag (-> pitch should be changed)
1193
	return
1194
 
1195
 
1196
SIDSE_Gate_End_NoPitch
1197
	andlw	0x00		; set ZERO flag (-> pitch should not be changed)
1198
	return
1199
 
1200
 
1201
;; --------------------------------------------------------------------------
1202
;; This function handles the Voice Pitch
1203
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
1204
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
1205
;;     Voice number in SID_SE_ELEMENT_NUM
1206
;; --------------------------------------------------------------------------
1207
SIDSE_Pitch
1208
	;; ------------------------------------------------------------------
1209
	;; Transpose MIDI Note
1210
	;; ------------------------------------------------------------------
1211
SIDSE_Pitch_Transp
1212
	;; if arp mode is active: use SID_Vx_ARP_NOTE, otherwise SID_Vx_NOTE
1213
	movlw	SID_Ix_Vx_ARP_MODE
1214
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_ENABLE, ACCESS, SIDSE_Pitch_Transp_NoArp
1215
SIDSE_Pitch_Transp_Arp
1216
	movlw	SID_Vx_ARP_NOTE
1217
	rgoto	SIDSE_Pitch_Transp_Cont
1218
SIDSE_Pitch_Transp_NoArp
1219
	movlw	SID_Vx_NOTE
1220
	;; 	rgoto	SIDSE_Pitch_Transp_Cont
1221
SIDSE_Pitch_Transp_Cont
1222
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1223
 
368 tk 1224
	;; pointer to MIDI voice -> FSR2
1 tk 1225
	lfsr	FSR2, SID_MV1_BASE
1226
	movlw	SID_Vx_ASSIGNED_MV
1227
	movf	PLUSW1, W
1228
	mullw	SID_MVx_RECORD_LEN
1229
	movf	PRODL, W
1230
	addwf	FSR2L, F
1231
 
362 tk 1232
	;; copy transpose value to IRQ_TMP2 (will be modified by bassline engine depending on voice)
1233
	movlw	SID_Ix_Vx_TRANSPOSE
1234
	movff	PLUSW0, IRQ_TMP2
1235
 
1 tk 1236
	;; add voice based transpose to MIDI voice based transpose and saturate
1237
	;; if lead engine: transpose value taken from first MIDI voice!
1238
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1239
	andlw	0x03
1240
	xorlw	0x01
1241
	bnz	SIDSE_Pitch_Transp_NoBassline
1242
SIDSE_Pitch_Transp_Bassline
362 tk 1243
	;; get transpose value depending on voice number
1244
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1245
	bz	SIDSE_Pitch_Transp_Bassline_V1L
1246
	addlw	-1
1247
	bz	SIDSE_Pitch_Transp_Bassline_V2L
1248
	addlw	-1
1249
	bz	SIDSE_Pitch_Transp_Bassline_V3L
1250
	addlw	-1
1251
	bz	SIDSE_Pitch_Transp_Bassline_V1R
1252
	addlw	-1
1253
	bz	SIDSE_Pitch_Transp_Bassline_V2R
1254
	;; 	rgoto	SIDSE_Pitch_Transp_Bassline_V3R
1255
 
1256
SIDSE_Pitch_Transp_Bassline_V3L	; octave transpose based on SID_Ix_B_V3_OCT_TRANSPOSE
1257
SIDSE_Pitch_Transp_Bassline_V3R
1258
	;; change transposed note to static note?
1259
	movlw	SID_Ix_B_V3_STATIC_NOTE
1260
	movf	PLUSW0, W
1261
	bz	SIDSE_Pitch_Transp_Bassline_V3RT
1262
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1263
SIDSE_Pitch_Transp_Bassline_V3RT
1264
	movlw	SID_Ix_B_V3_OCT_TRANSPOSE
1265
	rgoto	SIDSE_Pitch_Transp_Bassline_V23C
1266
 
1267
SIDSE_Pitch_Transp_Bassline_V2L	; octave transpose based on SID_Ix_B_V2_OCT_TRANSPOSE
1268
SIDSE_Pitch_Transp_Bassline_V2R
1269
	;; change transposed note to static note?
1270
	movlw	SID_Ix_B_V2_STATIC_NOTE
1271
	movf	PLUSW0, W
1272
	bz	SIDSE_Pitch_Transp_Bassline_V2RT
1273
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1274
SIDSE_Pitch_Transp_Bassline_V2RT
1275
	movlw	SID_Ix_B_V2_OCT_TRANSPOSE
1276
SIDSE_Pitch_Transp_Bassline_V23C
1277
	movf	PLUSW0, W	; zero: no transpose
1278
	bz	SIDSE_Pitch_Transp_Bassline_Cont
1279
	movwf	IRQ_TMP3	; (to store sign in bit [2])
1280
	andlw	0x03		; transpose
1281
	BRA_IFCLR IRQ_TMP3, 2, ACCESS, SIDSE_Pitch_Transp_Bassline_NNeg	; revert if negative
1282
SIDSE_Pitch_Transp_Bassline_Neg
1283
	xorlw	0x03
1284
	addlw	1
1285
SIDSE_Pitch_Transp_Bassline_NNeg
1286
	mullw	12		; *12 notes
1287
	;; add/subtract based on sign
1288
	BRA_IFSET IRQ_TMP3, 2, ACCESS, SIDSE_Pitch_Transp_Bassline_N
1289
SIDSE_Pitch_Transp_Bassline_P
1290
	movf	PRODL, W
1291
	addwf	IRQ_TMP2, F
1292
	;; octavewise saturation
1293
SIDSE_Pitch_Transp_Bassline_PLop
1294
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Pitch_Transp_Bassline_Cont
1295
	movlw	-12
1296
	addwf	IRQ_TMP2, F
1297
	rgoto	SIDSE_Pitch_Transp_Bassline_PLop
1298
 
1299
SIDSE_Pitch_Transp_Bassline_N
1300
	comf	PRODL, W
1301
	addlw	1
1302
	addwf	IRQ_TMP2, F
1303
	;; octavewise saturation
1304
SIDSE_Pitch_Transp_Bassline_NLop
1305
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Pitch_Transp_Bassline_Cont
1306
	movlw	12
1307
	addwf	IRQ_TMP2, F
1308
	rgoto	SIDSE_Pitch_Transp_Bassline_NLop
1309
 
1310
SIDSE_Pitch_Transp_Bassline_V1L	; SID_Ix_Vx_TRANSPOSE already in IRQ_TMP2
1311
SIDSE_Pitch_Transp_Bassline_V1R
1312
SIDSE_Pitch_Transp_Bassline_Cont
1313
 
368 tk 1314
	;; if WTO enabled, note is transposed via MIDI voice 3/4
1 tk 1315
	movlw	SID_Ix_B_Vx_FLAGS2
368 tk 1316
	BRA_IFCLR PLUSW0, SID_I_B_V_FLAGS2_WT_ONLY, ACCESS, SIDSE_Pitch_Transp_NoBasslineSeq
1317
	;; no transpose if channel disabled (to ensure compatibility with older ensemble settings)
1318
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_MIDI_CHANNEL
1319
	movf	PLUSW2, W
1320
	andlw	0xf0
1321
	bnz	SIDSE_Pitch_Transp_NoIns34Trans
1322
SIDSE_Pitch_Transp_Ins34Trans
1323
	;; copy transpose value of midi voice into IRQ_TMP1
1324
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_TRANSPOSE
1325
	movff	PLUSW2, IRQ_TMP1
1326
	;; and if note has been played: use it for transpose as well
1327
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_NOTE_STACK_0
1328
	movf	PLUSW2, W
1329
	andlw	0x7f
1330
	bz	SIDSE_Pitch_Transp_Ins34TransNoN
1331
	addlw	-0x3c		; (decrement base note C-3)
1332
	addwf	IRQ_TMP1, F
1333
	BRA_IFCLR IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransNoO ; saturation?
1334
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvN ; saturate depending on sign
1335
SIDSE_Pitch_Transp_Ins34TransOvP
1336
	movlw	-12
1337
	addwf	IRQ_TMP1, F
1338
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvP
1339
	rgoto	SIDSE_Pitch_Transp_Ins34TransOvC
1340
SIDSE_Pitch_Transp_Ins34TransOvN
1341
	movlw	12
1342
	addwf	IRQ_TMP1, F
1343
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvN
1344
	;; 	rgoto	SIDSE_Pitch_Transp_Ins34TransOvC
1345
SIDSE_Pitch_Transp_Ins34TransOvC
1346
SIDSE_Pitch_Transp_Ins34TransNoO
1347
SIDSE_Pitch_Transp_Ins34TransNoN
1348
	rgoto	SIDSE_Pitch_Transp_Bassline_Seq
1349
 
1350
SIDSE_Pitch_Transp_NoIns34Trans
1351
	movlw	0x40		; no transpose for bassline sequencer
1 tk 1352
	movwf	IRQ_TMP1
1353
	rgoto	SIDSE_Pitch_Transp_Bassline_Seq
368 tk 1354
 
1 tk 1355
SIDSE_Pitch_Transp_NoBassline
368 tk 1356
	xorlw	0x01				; (reverse engine setting)
1357
	bnz	SIDSE_Pitch_Transp_NoLead	; (if engine != 0)
1 tk 1358
SIDSE_Pitch_Transp_Lead
1359
	lfsr	FSR2, SID_MV1_BASE
368 tk 1360
SIDSE_Pitch_Transp_NoBasslineSeq
1 tk 1361
SIDSE_Pitch_Transp_NoLead
1362
	movlw	SID_MVx_TRANSPOSE
1363
	movff	PLUSW2, IRQ_TMP1
1364
SIDSE_Pitch_Transp_Bassline_Seq
362 tk 1365
	movf	IRQ_TMP2, W	; SID_Ix_Vx_TRANSPOSE
1 tk 1366
	addwf	IRQ_TMP1, W
1367
	sublw	0x80
1368
	xorlw	0xff
1369
	movwf	IRQ_TMP1
1370
 
1371
	;; transpose note
1372
	addwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1373
	addlw	1
1374
	BRA_IFCLR WREG, 7, ACCESS, SIDSE_Pitch_Transp_NoOverflow
368 tk 1375
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_N
1376
SIDSE_Pitch_Transp_Overflow_P
1377
	addlw	-12		; octavewise saturation
1378
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_P
1379
	rgoto	SIDSE_Pitch_Transp_Overflow_Cont
1380
 
1381
SIDSE_Pitch_Transp_Overflow_N
1382
	addlw	12		; octavewise saturation
1383
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_N
1384
	;; 	rgoto	SIDSE_Pitch_Transp_Overflow_Cont
1385
 
1386
SIDSE_Pitch_Transp_Overflow_Cont
1 tk 1387
SIDSE_Pitch_Transp_NoOverflow
1388
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1389
 
1390
 
1391
	;; ------------------------------------------------------------------
1392
	;; Glissando Handling
1393
	;; ------------------------------------------------------------------
1394
	movlw	SID_Vx_OLD_TRANSP_NOTE		; store new transposed note?
1395
	movf	PLUSW1, W
1396
	cpfseq	SID_SE_TRANSPOSED_NOTE, BANKED
1397
	rgoto SIDSE_Pitch_GlissNewNote
1398
	rgoto	SIDSE_Pitch_GlissNoNewNote
1399
SIDSE_Pitch_GlissNewNote
1400
	movlw	SID_Vx_OLD_TRANSP_NOTE		; store new transposed note!
1401
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1402
 
1403
	;; init portamento/glissando counter if glissando active
1404
	movlw	SID_Ix_Vx_FLAGS1
1405
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_GlissNoNewNote
1406
	movlw	SID_Vx_PORTA_CTR_L
1407
	setf	PLUSW1		; force overrun
1408
	movlw	SID_Vx_PORTA_CTR_H
1409
	setf	PLUSW1
1410
SIDSE_Pitch_GlissNoNewNote
1411
 
1412
	;; portamento active?
1413
	movlw	SID_Vx_STATE
1414
	BRA_IFCLR PLUSW1, SID_V_STATE_PORTA_ACTIVE, ACCESS, SIDSE_Pitch_Gliss_Final
1415
 
1416
	;; glissando active?
1417
	movlw	SID_Ix_Vx_FLAGS1
1418
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Gliss_Final
1419
 
1420
	;; get portamento multiplier from envelope table -> MUL_A
1421
	;; this one is used for "constant time glide" and "normal portamento"
1422
	movlw	SID_Ix_Vx_PORTAMENTO
1423
	movf	PLUSW0, W
1424
	skpnz
1425
	rgoto	SIDSE_Pitch_Gliss_Final	; if rate has been changed to zero, set target frequency and finish portamento
1426
	clrc
1427
	rrf	WREG, W		; make it faster
1428
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
1429
	tblrd*+				; transfer table entry to MUL_A_[LH]
1430
	movff	TABLAT, MUL_A_L
1431
	tblrd*+
1432
	movff	TABLAT, MUL_A_H
1433
 
1434
	;; increment portamento counter by MUL_A_[LH], result in MUL_A_[LH]
1435
	movlw	SID_Vx_PORTA_CTR_L
1436
	movf	PLUSW1, W
1437
	addwf	MUL_A_L, F, BANKED
1438
	movlw	SID_Vx_PORTA_CTR_H
1439
	movf	PLUSW1, W
1440
	addwfc	MUL_A_H, F, BANKED
1441
	bc	SIDSE_Pitch_Gliss_Ov
1442
SIDSE_Pitch_Gliss_NoOv
1443
	;; store new counter and continue with current note
1444
	movlw	SID_Vx_PORTA_CTR_L
1445
	movff	MUL_A_L, PLUSW1
1446
	movlw	SID_Vx_PORTA_CTR_H
1447
	movff	MUL_A_H, PLUSW1
1448
	movlw	SID_Vx_TRANSP_NOTE
1449
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1450
	rgoto	SIDSE_Pitch_Gliss_End
1451
 
1452
SIDSE_Pitch_Gliss_Ov
1453
	;; reset portamento/glissando counter
1454
	movlw	SID_Vx_PORTA_CTR_L
1455
	clrf	PLUSW1
1456
	movlw	SID_Vx_PORTA_CTR_H
1457
	clrf	PLUSW1
1458
 
1459
	;; increment/decrement note
1460
	movlw	SID_Vx_TRANSP_NOTE
1461
	movf	PLUSW1, W
1462
	movwf	IRQ_TMP1
1463
	cpfsgt	SID_SE_TRANSPOSED_NOTE, BANKED
1464
	rgoto SIDSE_Pitch_Gliss_Dec
1465
SIDSE_Pitch_Gliss_Inc
1466
	incf	IRQ_TMP1, F	; increment note and check if final value reached
1467
	rgoto	SIDSE_Pitch_Gliss_Inc_Cont
1468
SIDSE_Pitch_Gliss_Dec
1469
	decf	IRQ_TMP1, F	; decrement note and check if final value reached
1470
	;; 	rgoto	SIDSE_Pitch_Gliss_Inc_Cont
1471
 
1472
SIDSE_Pitch_Gliss_Inc_Cont
1473
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Gliss_Final
1474
	movf	IRQ_TMP1, W
1475
	cpfseq	SID_SE_TRANSPOSED_NOTE, BANKED
1476
	rgoto SIDSE_Pitch_Gliss_NewNote
1477
	rgoto	SIDSE_Pitch_Gliss_Final
1478
SIDSE_Pitch_Gliss_NewNote
1479
	movff	IRQ_TMP1, SID_SE_TRANSPOSED_NOTE
1480
	movlw	SID_Vx_TRANSP_NOTE
1481
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1482
	rgoto	SIDSE_Pitch_Gliss_End
1483
 
1484
SIDSE_Pitch_Gliss_Final
1485
	movlw	SID_Vx_OLD_TRANSP_NOTE	; target note reached
1486
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1487
	movlw	SID_Vx_TRANSP_NOTE
1488
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1489
 
1490
	;; deactivate porta active gate if glissando active
1491
	movlw	SID_Ix_Vx_FLAGS1
1492
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Gliss_End
1493
	movlw	SID_Vx_STATE
1494
	bcf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
1495
SIDSE_Pitch_Gliss_End
1496
 
1497
	;; ------------------------------------------------------------------
1498
	;; Determine Target frequency depending on transposed note
1499
	;; ------------------------------------------------------------------
1500
SIDSE_Pitch_InitTargetFrq
1501
	clrf	SID_SE_TARGET_FRQ_L, BANKED
1502
	clrc
1503
	rlf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1504
	movwf	SID_SE_TARGET_FRQ_H, BANKED
1505
 
1506
	;; ------------------------------------------------------------------
1507
	;; Increase/Decrease target frequency by pitchrange depending on
1508
	;; Pitchbender and Finetune value
1509
	;; ------------------------------------------------------------------
1510
 
1511
	;; skip Pitchbender+Finetune processing if PITCHRANGE == zero
1512
	movlw	SID_Ix_Vx_PITCHRANGE
1513
	movf	PLUSW0, W
1514
	skpnz
1515
	rgoto	SIDSE_Pitch_NoOffset
1516
SIDSE_Pitch_Offset
1517
	;; determine scale multipler (9 bit signed value) -> MUL_B_L
1518
	clrf	MUL_B_L, BANKED
1519
	clrf	MUL_B_H, BANKED
1520
 
1521
	;; multi/bassline/drum engine: take pitchbender value from MIDI voice (pointer still in FSR2)
1522
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1523
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Pitch_PB_DM
1524
SIDSE_Pitch_PB_LB
1525
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Pitch_PB_B
1526
SIDSE_Pitch_PB_L
1527
	movlw	SID_Vx_PITCHBENDER
1528
	movf	PLUSW1, W
1529
	rgoto	SIDSE_Pitch_PB_Cont
1530
 
1531
SIDSE_Pitch_PB_B
1532
SIDSE_Pitch_PB_DM
1533
	movlw	SID_MVx_PITCHBENDER
1534
	movf	PLUSW2, W
1535
	;; 	rgoto	SIDSE_Pitch_PB_Cont
1536
 
1537
SIDSE_Pitch_PB_Cont
1538
	movwf	IRQ_TMP1
1539
	bz	SIDSE_Pitch_NoPitchBender
1540
SIDSE_Pitch_PitchBender
1541
	clrc
1542
	rlf	IRQ_TMP1, W
1543
	addwf	MUL_B_L, F, BANKED
1544
	movlw	0x00
1545
	btfsc	IRQ_TMP1, 7
1546
	movlw 0xff
1547
	addwfc	MUL_B_H, F, BANKED
1548
SIDSE_Pitch_NoPitchBender
1549
 
1550
	movlw	SID_Ix_Vx_FINETUNE
1551
	movf	PLUSW0, W
376 tk 1552
	movwf	IRQ_TMP1
1 tk 1553
	xorlw	0x80
1554
	bz	SIDSE_Pitch_NoFinetune
1555
SIDSE_Pitch_Finetune
1556
	clrc
1557
	rlf	IRQ_TMP1, W
1558
	addwf	MUL_B_L, F, BANKED
1559
	movlw	0x00
1560
	btfss	IRQ_TMP1, 7
1561
	movlw 0xff
1562
	addwfc	MUL_B_H, F, BANKED
1563
SIDSE_Pitch_NoFinetune
1564
 
1565
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
362 tk 1566
	andlw	0x02	; mask is valid for lead and bassline engine
1 tk 1567
	bnz	SIDSE_Pitch_NoDetune
1568
	SET_BSR	SID_PATCH_BUFFER_SHADOW
1569
	movf	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_DETUNE, W, BANKED
1570
	SET_BSR	SID_BASE
1571
	bz	SIDSE_Pitch_NoDetune
1572
SIDSE_Pitch_Detune
1573
	movwf	IRQ_TMP1
1189 tk 1574
 
1575
	;; implement detune modes
1576
	SET_BSR	SID_PATCH_BUFFER_SHADOW
1577
	BRA_IFSET SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_DTM, 0, BANKED, SIDSE_Pitch_SuperNeg
1578
	BRA_IFSET SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_DTM, 1, BANKED, SIDSE_Pitch_SuperPos
1579
	SET_BSR	SID_BASE
1580
	rgoto SIDSE_Pitch_NormalDetune
1581
 
1582
	;; super-saw like detune modes
1583
	;; Created by Lis0r, based on the research from this paper:
1584
	;; http://www.nada.kth.se/utbildning/grukth/exjobb/rapportlistor/2010/rapporter10/szabo_adam_10131.pdf
1585
SIDSE_Pitch_SuperNeg
1586
	SET_BSR	SID_BASE
1587
	;; Left OSC1: -detune
1588
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Pitch_Super_45
1589
SIDSE_Pitch_SuperNeg_0123
1590
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Pitch_Super_23
1591
SIDSE_Pitch_SuperNeg_01
1592
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Super_1
1593
SIDSE_Pitch_SuperNeg_0 ; SIDL, OSC1
1594
	rgoto	SIDSE_Pitch_Detune_Sub
1595
 
1596
SIDSE_Pitch_SuperPos
1597
	SET_BSR	SID_BASE
1598
	;; Left OSC1: +detune
1599
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Pitch_Super_45
1600
SIDSE_Pitch_SuperPos_0123
1601
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Pitch_Super_23
1602
SIDSE_Pitch_SuperPos_01
1603
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Super_1
1604
SIDSE_Pitch_SuperPos_0 ; SIDL, OSC1
1605
	rgoto	SIDSE_Pitch_Detune_Add
1606
 
1607
	;; Right OSC1: 0
1608
	;; Left OSC2: +detune/3
1609
	;; Right OSC2: -detune/3
1610
	;; Left OSC3: -2*detune/3
1611
	;; Right OSC3: +2*detune/3
1612
SIDSE_Pitch_Super_1 ; SIDL, OSC2
1613
	rcall	SIDSE_Hlp_Div3
1614
	rgoto	SIDSE_Pitch_Detune_Add
1615
 
1616
SIDSE_Pitch_Super_23
1617
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Super_3
1618
SIDSE_Pitch_Super_2	; SIDL, OSC3
1619
	rcall SIDSE_Hlp_Div3
1620
	movf  IRQ_TMP1, W
1621
	addwf IRQ_TMP1, F
1622
	rgoto	SIDSE_Pitch_Detune_Sub
1623
SIDSE_Pitch_Super_3	; SIDR, OSC1
1624
	rgoto SIDSE_Pitch_NoDetune
1625
 
1626
SIDSE_Pitch_Super_45
1627
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Super_5
1628
SIDSE_Pitch_Super_4	; SIDR, OSC2
1629
	rcall SIDSE_Hlp_Div3
1630
	rgoto	SIDSE_Pitch_Detune_Sub
1631
SIDSE_Pitch_Super_5	; SIDR, OSC3
1632
	rcall SIDSE_Hlp_Div3
1633
	movf  IRQ_TMP1, W
1634
	addwf IRQ_TMP1, F
1635
	rgoto	SIDSE_Pitch_Detune_Add
1636
 
1637
	;; traditional normal detune mode
1638
SIDSE_Pitch_NormalDetune
1639
	movf	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_DETUNE, W, BANKED
1640
	SET_BSR	SID_BASE
1641
	bz	SIDSE_Pitch_NoDetune
1 tk 1642
	;; additional detuning depending on SID channel and oscillator
362 tk 1643
	;; Left OSC1: +detune/4   (lead only, 0 in bassline mode)
1644
	;; Right OSC1: -detune/4  (lead only, 0 in bassline mode)
1 tk 1645
	;; Left OSC2: +detune
1646
	;; Right OSC2: -detune
1647
	;; Left OSC3: -detune
1648
	;; Right OSC3: +detune
1649
 
1650
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Pitch_Detune_45
1651
SIDSE_Pitch_Detune_0123
1652
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Pitch_Detune_23
1653
SIDSE_Pitch_Detune_01
1654
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_1
1655
SIDSE_Pitch_Detune_0	; SIDL, OSC1
362 tk 1656
	;; in mono or bassline mode: don't detune OSC1, so that at least one oscillator runs at the target frequency!
1657
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG				; check for mono
1 tk 1658
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_Pitch_NoDetune
362 tk 1659
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG			; check for bassline
1660
	andlw	0x03
1661
	xorlw	0x01
1662
	bz	SIDSE_Pitch_NoDetune
1663
 
1 tk 1664
	clrc
1665
	rrf	IRQ_TMP1, F
1666
	clrc
1667
	rrf	IRQ_TMP1, F
1668
	rgoto	SIDSE_Pitch_Detune_Add
1669
SIDSE_Pitch_Detune_1	; SIDL, OSC2
1670
	rgoto	SIDSE_Pitch_Detune_Add
1671
 
1672
SIDSE_Pitch_Detune_23
1673
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_3
1674
SIDSE_Pitch_Detune_2	; SIDL, OSC3
1675
	rgoto	SIDSE_Pitch_Detune_Sub
1676
SIDSE_Pitch_Detune_3	; SIDR, OSC1
362 tk 1677
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG			; check for bassline
1678
	andlw	0x03
1679
	xorlw	0x01
1680
	bz	SIDSE_Pitch_NoDetune
1681
 
1 tk 1682
	clrc
1683
	rrf	IRQ_TMP1, F
1684
	clrc
1685
	rrf	IRQ_TMP1, F
1686
	rgoto	SIDSE_Pitch_Detune_Sub
1687
 
1688
SIDSE_Pitch_Detune_45
1689
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_5
1690
SIDSE_Pitch_Detune_4	; SIDR, OSC2
1691
	rgoto	SIDSE_Pitch_Detune_Sub
1692
SIDSE_Pitch_Detune_5	; SIDR, OSC3
1693
	rgoto	SIDSE_Pitch_Detune_Add
1694
 
1695
SIDSE_Pitch_Detune_Sub
1696
	comf	IRQ_TMP1, W
1697
	addlw	1
1698
	addwf	MUL_B_L, F, BANKED
1699
	movf	IRQ_TMP1, W
1700
	skpz
1701
	movlw	0xff
1702
	addwfc	MUL_B_H, F, BANKED
1703
	rgoto	SIDSE_Pitch_Detune_Cont
1704
 
1705
SIDSE_Pitch_Detune_Add
1706
	movf	IRQ_TMP1, W
1707
	addwf	MUL_B_L, F, BANKED
1708
	movlw	0x00
1709
	addwfc	MUL_B_H, F, BANKED
1710
	;; 	rgoto	SIDSE_Pitch_Detune_Cont
1711
SIDSE_Pitch_Detune_Cont
1712
SIDSE_Pitch_NoDetune
1713
 
1714
 
1715
	;; skip tuning if scale multiplier is zero
1716
	movf	MUL_B_L, W, BANKED
1717
	iorwf	MUL_B_H, W, BANKED
1718
	bz	SIDSE_Pitch_NoOffset
1719
 
1720
	;; get f_in[target], save it in MIOS_PARAMETER[12]
1721
	;; add pitchrange depending on direction with saturation
1722
	BRA_IFSET MUL_B_H, 7, BANKED, SIDSE_Pitch_Frq_Dec
1723
SIDSE_Pitch_Frq_Inc
1724
	movlw	SID_Ix_Vx_PITCHRANGE
1725
	movf	PLUSW0, W
1726
	addwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1727
	btfsc	WREG, 7
1728
	movlw 0x7f
1729
	rgoto	SIDSE_Pitch_Frq_Inc_Cont
1730
SIDSE_Pitch_Frq_Dec
1731
	movlw	SID_Ix_Vx_PITCHRANGE
1732
	movf	PLUSW0, W
1733
	subwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1734
	btfsc	WREG, 7
1735
	movlw 0x00
1736
SIDSE_Pitch_Frq_Inc_Cont
1737
 
398 tk 1738
SIDSE_Pitch_Frq_TuneFrq
1 tk 1739
	clrf	MIOS_PARAMETER1
1740
	clrc
1741
	rlf	WREG, W
1742
	movwf	MIOS_PARAMETER2
1743
 
1744
	;; add and multiply to target frequency
1745
SIDSE_Pitch_Frq_AddMul
1746
	BRA_IFSET MUL_B_H, 7, BANKED, SIDSE_Pitch_Frq_AddMul_Neg
1747
SIDSE_Pitch_Frq_AddMul_Pos
1748
	;; calc MUL_A_[LH] = MIOS_PARAMETER[12] - SID_Vx_FRQ_[LH]
1749
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
1750
	subwf	MIOS_PARAMETER1, W
1751
	movwf	MUL_A_L, BANKED
1752
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
1753
	subwfb	MIOS_PARAMETER2, W
1754
	movwf	MUL_A_H, BANKED
1755
 
1756
	;; ensure that bit #15 (sign) not set
1757
	BRA_IFCLR MUL_A_H, 7, BANKED, SIDSE_Pitch_Frq_AddMul_Cont
1758
	setf	MUL_A_L, BANKED
1759
	movlw	0x7f
1760
	movwf	MUL_A_H, BANKED
1761
	rgoto	SIDSE_Pitch_Frq_AddMul_Cont
1762
 
1763
SIDSE_Pitch_Frq_AddMul_Neg
1764
	;; calc MUL_A_[LH] = SID_Vx_FRQ_[LH] - MIOS_PARAMETER[12]
1765
	movf	MIOS_PARAMETER1, W
1766
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
1767
	movwf	MUL_A_L, BANKED
1768
	movf	MIOS_PARAMETER2, W
1769
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1770
	movwf	MUL_A_H, BANKED
1771
	;; 	rgoto	SIDSE_Pitch_Frq_AddMul_Cont
1772
 
1773
SIDSE_Pitch_Frq_AddMul_Cont
1774
	;; calc MUL_R_[12] = MUL_A_[LH] * MUL_B_[LH]
1775
	call	MATH_MUL16_16_SIGNED
1776
 
1777
	;; SID_Vx_FRQ += signed result[23:8]
1778
	movf	MUL_R_1, W, BANKED
1779
	addwf	SID_SE_TARGET_FRQ_L, F, BANKED
1780
	movf	MUL_R_2, W, BANKED
1781
	addwfc	SID_SE_TARGET_FRQ_H, F, BANKED
1782
 
1783
SIDSE_Pitch_NoOffset
1784
 
1785
	;; ------------------------------------------------------------------
1786
	;; pitch modulation
1787
	;; ------------------------------------------------------------------
1788
	rcall	SIDSE_Hlp_Pitch_Mod
1789
 
1790
	;; ------------------------------------------------------------------
1791
	;; Portamento Handling
1792
	;; ------------------------------------------------------------------
1793
 
398 tk 1794
	;; transfer current linear frequency (stored in voice array) to SID_SE_LINEAR_FRQ_[LH]
1795
	movlw	SID_Vx_LINEAR_FRQ_L
1796
	movff	PLUSW1, SID_SE_LINEAR_FRQ_L
1797
	movlw	SID_Vx_LINEAR_FRQ_H
1798
	movff	PLUSW1, SID_SE_LINEAR_FRQ_H
1 tk 1799
 
1800
SIDSE_Pitch_Porta
1801
	;; whenever target frequency has been changed, update portamento frequency
1802
	movlw	SID_Vx_OLD_TARGET_FRQ_L
1803
	movf	PLUSW1, W
1804
	cpfseq	SID_SE_TARGET_FRQ_L, BANKED
398 tk 1805
	rgoto	SIDSE_Pitch_Porta_Update
1 tk 1806
	movlw	SID_Vx_OLD_TARGET_FRQ_H
1807
	movf	PLUSW1, W
1808
	cpfseq	SID_SE_TARGET_FRQ_H, BANKED
398 tk 1809
	rgoto	SIDSE_Pitch_Porta_Update
1 tk 1810
	rgoto	SIDSE_Pitch_Porta_NoUpdate
1811
SIDSE_Pitch_Porta_Update
1812
	;; memorize new target frequency
1813
	movlw	SID_Vx_OLD_TARGET_FRQ_L
1814
	movff	SID_SE_TARGET_FRQ_L, PLUSW1
1815
	movlw	SID_Vx_OLD_TARGET_FRQ_H
1816
	movff	SID_SE_TARGET_FRQ_H, PLUSW1
1817
 
398 tk 1818
	;; store current linear frequency (SID_SE_LINEAR_FRQ_[LH]) into SID_Vx_PORTA_FRQ_[LH]
1 tk 1819
	movlw	SID_Vx_PORTA_FRQ_L
398 tk 1820
	movff	SID_SE_LINEAR_FRQ_L, PLUSW1
1 tk 1821
	movlw	SID_Vx_PORTA_FRQ_H
398 tk 1822
	movff	SID_SE_LINEAR_FRQ_H, PLUSW1
1 tk 1823
 
398 tk 1824
	;; reset portamento counter
1 tk 1825
	;; skip if glissando active
1826
	movlw	SID_Ix_Vx_FLAGS1
1827
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_NoUpdate
1828
	movlw	SID_Vx_PORTA_CTR_L
1829
	clrf	PLUSW1
1830
	movlw	SID_Vx_PORTA_CTR_H
1831
	clrf	PLUSW1
1832
SIDSE_Pitch_Porta_NoUpdate
1833
 
1834
	;; skip the rest if portamento not active
1835
	movlw	SID_Vx_STATE
1836
	BRA_IFCLR PLUSW1, SID_V_STATE_PORTA_ACTIVE, ACCESS, SIDSE_Pitch_Porta_Final
1837
 
1838
	;; skip if glissando active
1839
	movlw	SID_Ix_Vx_FLAGS1
1840
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_Final
1841
 
1842
	;; get portamento multiplier from envelope table -> MUL_A
1843
	;; this one is used for "constant time glide" and "normal portamento"
1844
	movlw	SID_Ix_Vx_PORTAMENTO
1845
	movf	PLUSW0, W
1846
	skpnz
1847
	rgoto	SIDSE_Pitch_Porta_Final	; if rate has been changed to zero, set target frequency and finish portamento
1848
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
1849
	tblrd*+				; transfer table entry to MUL_A_[LH]
1850
	movff	TABLAT, MUL_A_L
1851
	tblrd*+
1852
	movff	TABLAT, MUL_A_H
1853
 
1854
	;; branch depending on portamento mode
1855
	movlw	SID_Ix_Vx_FLAGS1
1856
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_CTG, ACCESS, SIDSE_Pitch_Porta_Norm
1857
 
1858
	;; ------------------------------------------------------------------
1859
	;; constant glide time
1860
SIDSE_Pitch_Porta_Const
1861
 
1862
	;; increment portamento counter by MUL_A_[LH], result in MUL_A_[LH]
1863
	movlw	SID_Vx_PORTA_CTR_L
1864
	movf	PLUSW1, W
1865
	addwf	MUL_A_L, F, BANKED
1866
	movlw	SID_Vx_PORTA_CTR_H
1867
	movf	PLUSW1, W
1868
	addwfc	MUL_A_H, F, BANKED
1869
	bnc	SIDSE_Pitch_Porta_Const_NoOv
1870
SIDSE_Pitch_Porta_Const_Ov
1871
	;; if value >= 0xffff target reached, saturate
1872
	setf	MUL_A_L, BANKED
1873
	setf	MUL_A_H, BANKED
1874
SIDSE_Pitch_Porta_Const_NoOv
1875
 
1876
	;; transfer back new counter value to original registers
1877
	;; portamento counter value -> MUL_A_[LH]
1878
	movlw	SID_Vx_PORTA_CTR_L
1879
	movff	MUL_A_L, PLUSW1
1880
	movlw	SID_Vx_PORTA_CTR_H
1881
	movff	MUL_A_H, PLUSW1
1882
 
1883
	;; get difference between target and previous frequency -> IRQ_TMP[12]
1884
	movlw	SID_Vx_PORTA_FRQ_L
1885
	movf	PLUSW1, W
1886
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
1887
	movwf	IRQ_TMP1
1888
	movlw	SID_Vx_PORTA_FRQ_H
1889
	movf	PLUSW1, W
1890
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1891
	movwf	IRQ_TMP2
1892
 
1893
	;; convert IRQ_TMP[12] to absolute value
1894
	call	SIDSE_Hlp_GetAbs16
1895
	;; result in IRQ_TMP[12], sign in IRQ_TMP3[0]
1896
	;; increment four to ensure that target will be reached
1897
	movlw	4
1898
	addwf	IRQ_TMP1, F
1899
	movlw	0
1900
	addwfc	IRQ_TMP2, F
1901
	movff	IRQ_TMP1, MUL_B_L
1902
	movff	IRQ_TMP2, MUL_B_H
1903
 
1904
	;; calc MUL_A_[LH] * MUL_B_[LH]
1905
	call	MATH_MUL16_16
1906
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
1907
 
1908
	;; branch depending on direction
1909
	BRA_IFSET IRQ_TMP3, 0, ACCESS, SIDSE_Pitch_Porta_Const_Down
1910
SIDSE_Pitch_Porta_Const_Up
1911
	;; add scaled value to starting frequency
1912
	movlw	SID_Vx_PORTA_FRQ_L
1913
	movf	PLUSW1, W
1914
	addwf	MUL_R_2, W, BANKED
398 tk 1915
	movwf	SID_SE_LINEAR_FRQ_L, BANKED
1 tk 1916
	movlw	SID_Vx_PORTA_FRQ_H
1917
	movf	PLUSW1, W
1918
	addwfc	MUL_R_3, W, BANKED
398 tk 1919
	movwf	SID_SE_LINEAR_FRQ_H, BANKED
1 tk 1920
 
1921
	;; continue at normal portamento routine
1922
	rgoto	SIDSE_Pitch_Porta_Const_Up_Cont
1923
 
1924
SIDSE_Pitch_Porta_Const_Down
1925
	;; subtract scaled value from starting frequency
1926
	movlw	SID_Vx_PORTA_FRQ_L
398 tk 1927
	movff	PLUSW1, PRODL
1 tk 1928
	movlw	SID_Vx_PORTA_FRQ_H
398 tk 1929
	movff	PLUSW1, PRODH
1 tk 1930
 
1931
	movf	MUL_R_2, W, BANKED
398 tk 1932
	subwf	PRODL, W
1933
	movwf	SID_SE_LINEAR_FRQ_L, BANKED
1 tk 1934
	movf	MUL_R_3, W, BANKED
398 tk 1935
	subwfb	PRODH, W
1936
	movwf	SID_SE_LINEAR_FRQ_H, BANKED
1 tk 1937
 
1938
	;; continue at normal portamento routine
1939
	rgoto	SIDSE_Pitch_Porta_Const_Down_C
1940
 
1941
 
1942
	;; ------------------------------------------------------------------
1943
	;; "normal" portamento mode (non-constant glide time)
1944
SIDSE_Pitch_Porta_Norm
1945
	;; get current frequency -> MUL_B
398 tk 1946
	movff	SID_SE_LINEAR_FRQ_L, MUL_B_L
1947
	movff	SID_SE_LINEAR_FRQ_H, MUL_B_H
1 tk 1948
 
1949
	;; multiply MUL_A * MUL_B
1950
	call	MATH_MUL16_16
1951
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
1952
	;; ensure that result is != 0
1953
	movf	MUL_R_2, W, BANKED
1954
	iorwf	MUL_R_3, W, BANKED
1955
	skpnz
1956
	incf	MUL_R_2, F, BANKED
1957
 
398 tk 1958
	;; SID_Vx_LINEAR_FRQ += result (depending on Portamento Direction)
1 tk 1959
 
1960
	;; branch depending on portamento direction
1961
	;; check if value > current value
1962
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1963
	subwf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1964
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
398 tk 1965
	subwfb	SID_SE_LINEAR_FRQ_H, W, BANKED
1 tk 1966
	bc	SIDSE_Pitch_Porta_Norm_Down
1967
 
1968
SIDSE_Pitch_Porta_Norm_Up
398 tk 1969
	movf	MUL_R_2, W, BANKED
1970
	addwf	SID_SE_LINEAR_FRQ_L, F, BANKED
1 tk 1971
	movf	MUL_R_3, W, BANKED
398 tk 1972
	addwfc	SID_SE_LINEAR_FRQ_H, F, BANKED
1 tk 1973
 
1974
SIDSE_Pitch_Porta_Const_Up_Cont		; re-used by "constant glide" option
1975
	;; check if value > MAX_VALUE
398 tk 1976
	movf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1977
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1978
	movf	SID_SE_LINEAR_FRQ_H, W, BANKED
1 tk 1979
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1980
	bc	SIDSE_Pitch_Porta_End	; branch to end if MAX_VALUE not reached
1981
	rgoto	SIDSE_Pitch_Porta_Final	; final value reached
1982
 
1983
SIDSE_Pitch_Porta_Norm_Down
1984
	movf	MUL_R_2, W
398 tk 1985
	subwf	SID_SE_LINEAR_FRQ_L, F, BANKED
1 tk 1986
	movf	MUL_R_3, W, BANKED
398 tk 1987
	subwfb	SID_SE_LINEAR_FRQ_H, F, BANKED
1 tk 1988
 
1989
SIDSE_Pitch_Porta_Const_Down_C	; re-used by "constant glide" option
1990
	;; check if value < MIN_VALUE
1991
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1992
	subwf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1993
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
398 tk 1994
	subwfb	SID_SE_LINEAR_FRQ_H, W, BANKED
1995
	bc	SIDSE_Pitch_Porta_End	; branch if MIN_VALUE not reached
1 tk 1996
	;; final value reached
1997
 
1998
SIDSE_Pitch_Porta_Final
398 tk 1999
	;; copy target frequency to SID_SE_LINEAR_FRQ_[LH] and finish portamento
2000
	movff	SID_SE_TARGET_FRQ_L, SID_SE_LINEAR_FRQ_L
2001
	movff	SID_SE_TARGET_FRQ_H, SID_SE_LINEAR_FRQ_H
2002
 
2003
	;; deactivate porta active gate if glissando not active
2004
	movlw	SID_Ix_Vx_FLAGS1
2005
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_End
2006
	movlw	SID_Vx_STATE
2007
 	bcf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
2008
SIDSE_Pitch_Porta_End
2009
 
2010
 
2011
	;; ------------------------------------------------------------------
2012
	;; Linear Frequency -> SID Frequency conversion
2013
	;; ------------------------------------------------------------------
2014
SIDSE_Pitch_FrqConvert
399 tk 2015
	movlw	SID_Vx_STATE2	; (for multi-engine to takeover portamento)
2016
	BRA_IFSET PLUSW1, SID_V_STATE2_FORCE_FRQ_RECALC, ACCESS, SIDSE_Pitch_FrqConvert_Changed
2017
 
398 tk 2018
	;; check if linear frequency has been changed
2019
	movlw	SID_Vx_LINEAR_FRQ_L
2020
	movf	PLUSW1, W
2021
	xorwf	SID_SE_LINEAR_FRQ_L, W, BANKED
2022
	bnz	SIDSE_Pitch_FrqConvert_Changed
2023
	movlw	SID_Vx_LINEAR_FRQ_H
2024
	movf	PLUSW1, W
2025
	xorwf	SID_SE_LINEAR_FRQ_H, W, BANKED
2026
	bz	SIDSE_Pitch_FrqConvert_End
2027
SIDSE_Pitch_FrqConvert_Changed
399 tk 2028
	movlw	SID_Vx_STATE2
2029
	bcf	PLUSW1, SID_V_STATE2_FORCE_FRQ_RECALC
398 tk 2030
 
2031
	;; store new linear frequency value into SID_Vx_LINEAR_FRQ_[LH]
2032
	movlw	SID_Vx_LINEAR_FRQ_L
2033
	movff	SID_SE_LINEAR_FRQ_L, PLUSW1
2034
	movlw	SID_Vx_LINEAR_FRQ_H
2035
	movff	SID_SE_LINEAR_FRQ_H, PLUSW1
2036
 
2037
	;; transfer pointer to SIDx_Vx_FRQ_L register -> FSR2
2038
	call	SIDSE_Hlp_GetSIDFrqPtr
2039
 
391 tk 2040
	;; convert upper 7 bit of 16bit linear frequency to SID frequency value
398 tk 2041
	rrf	SID_SE_LINEAR_FRQ_H, W, BANKED
391 tk 2042
	andlw	0x7f
2043
	addlw	21
2044
	btfsc	WREG, 7; the note value
398 tk 2045
	movlw	0x7f
391 tk 2046
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; determine table address
2047
	tblrd*+				; transfer table entry to SID_FRQ_[LH]
2048
	movff	TABLAT, POSTINC2
2049
	movff	TABLAT, MUL_A_L
2050
	tblrd*+
2051
	movff	TABLAT, POSTDEC2
2052
	movff	TABLAT, MUL_A_H
2053
 
2054
	tblrd*+				; for interpolation: transfer next table entry to MUL_B_[LH]
2055
	movff	TABLAT, MUL_B_L
2056
	tblrd*+
2057
	movff	TABLAT, MUL_B_H
2058
 
2059
	;; calculate difference: MUL_A_[LH] = MUL_B_[LH] - MUL_A_[LH]
2060
	movf	MUL_A_L, W, BANKED
2061
	subwf	MUL_B_L, W, BANKED
2062
	movwf	MUL_A_L, BANKED
2063
	movf	MUL_A_H, W, BANKED
2064
	subwfb	MUL_B_H, W, BANKED
2065
	movwf	MUL_A_H, BANKED
2066
 
398 tk 2067
	;; use bit 8:1 of 16bit linear frequency for linear scaling between two semitones
2068
	rrf	SID_SE_LINEAR_FRQ_H, W, BANKED
2069
	rrf	SID_SE_LINEAR_FRQ_L, W, BANKED
391 tk 2070
	movwf	MUL_B_L, BANKED
2071
 
398 tk 2072
	;; 16*8 multiplication
2073
	call	MATH_MUL16_8
391 tk 2074
 
2075
	;; add result to SID frequency registers
398 tk 2076
	movf	MUL_R_1, W, BANKED
2077
	addwf	POSTINC2, F
391 tk 2078
	movf	MUL_R_2, W, BANKED
2079
	addwfc	POSTDEC2, F
398 tk 2080
SIDSE_Pitch_FrqConvert_End
1 tk 2081
 
2082
 
2083
	;; ------------------------------------------------------------------
2084
	;; K2A Function
2085
	;; ------------------------------------------------------------------
2086
 
2087
	;; forward key value to AOUT if enabled
2088
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2089
	BRA_IFCLR WREG, SID_ENS_CTRL2_K2A, ACCESS, SIDSE_Pitch_Key_NoAOUT
2090
SIDSE_Pitch_Key_AOUT
2091
	;; get channel assignment (0: channel disabled)
2092
	movlw	LOW(SIDSE_KEY_EXT_ASSG_TABLE)
2093
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
2094
	movwf	TBLPTRL
2095
	clrf	TBLPTRH
2096
	movlw	HIGH(SIDSE_KEY_EXT_ASSG_TABLE)
2097
	addwfc	TBLPTRH, F
2098
	clrf    TBLPTRU
2099
        movlw   UPPER(SIDSE_KEY_EXT_ASSG_TABLE)
2100
	addwfc	TBLPTRU, F
2101
	tblrd*+
2102
	movf	TABLAT, W
2103
	bz	SIDSE_Pitch_Key_NoAOUT	; channel assignment disabled
2104
 
136 tk 2105
	;; copy key value to MIOS_PARAMETER[12]
2106
	clrf	MIOS_PARAMETER1
1 tk 2107
	clrc
2108
	rlf	SID_SE_TRANSPOSED_NOTE, W, BANKED
136 tk 2109
	movwf	MIOS_PARAMETER2
1 tk 2110
 
136 tk 2111
	;; forward MIOS_PARAMETER[12] to channel #TABLAT-1
1 tk 2112
	decf	TABLAT, W
136 tk 2113
	call	AOUT_Pin16bitSet
2114
	SET_BSR	SID_BASE
1 tk 2115
 
2116
	;; notify that channel has already been updated by K2A function
2117
	decf	TABLAT, W
2118
	call	MIOS_HLP_GetBitORMask
2119
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2120
SIDSE_Pitch_Key_NoAOUT
2121
 
2122
	;; ------------------------------------------------------------------
2123
	;; O2A Function
2124
	;; ------------------------------------------------------------------
2125
 
398 tk 2126
	;; forward linear frequency value to AOUT if enabled
1 tk 2127
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2128
	BRA_IFCLR WREG, SID_ENS_CTRL2_O2A, ACCESS, SIDSE_Pitch_Osc_NoAOUT
2129
SIDSE_Pitch_Osc_AOUT
2130
	;; get channel assignment (0: channel disabled)
2131
	movlw	LOW(SIDSE_OSC_EXT_ASSG_TABLE)
2132
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
2133
	movwf	TBLPTRL
2134
	clrf	TBLPTRH
2135
	movlw	HIGH(SIDSE_OSC_EXT_ASSG_TABLE)
2136
	addwfc	TBLPTRH, F
2137
	clrf    TBLPTRU
2138
        movlw   UPPER(SIDSE_OSC_EXT_ASSG_TABLE)
2139
	addwfc	TBLPTRU, F
2140
	tblrd*+
2141
	movf	TABLAT, W
2142
	bz	SIDSE_Pitch_Osc_NoAOUT	; channel assignment disabled
2143
 
136 tk 2144
	;; copy oscillator frequency to MIOS_PARAMETER[12]
398 tk 2145
	movff	SID_SE_LINEAR_FRQ_L, MIOS_PARAMETER1
2146
	movff	SID_SE_LINEAR_FRQ_H, MIOS_PARAMETER2
1 tk 2147
 
136 tk 2148
	;; forward MIOS_PARAMETER[12] to channel #TABLAT-1
1 tk 2149
	decf	TABLAT, W
136 tk 2150
	call	AOUT_Pin16bitSet
2151
	SET_BSR	SID_BASE
1 tk 2152
 
2153
	;; notify that channel has already been updated by O2A function
2154
	decf	TABLAT, W
2155
	call	MIOS_HLP_GetBitORMask
2156
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2157
SIDSE_Pitch_Osc_NoAOUT
2158
 
2159
	return
2160
 
2161
 
2162
	;; AOUT assignments for K2A
2163
SIDSE_KEY_EXT_ASSG_TABLE
2164
	db	DEFAULT_K2A_OSC1_L_AOUT, DEFAULT_K2A_OSC2_L_AOUT
2165
	db	DEFAULT_K2A_OSC3_L_AOUT, DEFAULT_K2A_OSC1_R_AOUT
2166
	db	DEFAULT_K2A_OSC2_L_AOUT, DEFAULT_K2A_OSC3_R_AOUT
2167
 
2168
	;; AOUT assignments for O2A
2169
SIDSE_OSC_EXT_ASSG_TABLE
2170
	db	DEFAULT_O2A_OSC1_L_AOUT, DEFAULT_O2A_OSC2_L_AOUT
2171
	db	DEFAULT_O2A_OSC3_L_AOUT, DEFAULT_O2A_OSC1_R_AOUT
2172
	db	DEFAULT_O2A_OSC2_L_AOUT, DEFAULT_O2A_OSC3_R_AOUT
2173
 
2174
 
2175
;; --------------------------------------------------------------------------
2176
;; This function handles the Pulsewidth of a voice
2177
;; IN: pointer to SID_Ix_L_SxVy_BASE in FSR0 (patch record)
2178
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
2179
;;     Voice number in SID_SE_ELEMENT_NUM
2180
;;     If SIDSE_PW_Drums is called: 16bit pulsewidth in IRQ_TMP[12]
2181
;; --------------------------------------------------------------------------
2182
SIDSE_PW
2183
	;; small variation between Lead/Bassline/Multi Engine, and Drum Engine:
2184
	;; for Drum Engine the pulsewidth is predefined in model table, and not
2185
	;; part of the patch (drum engine has to call SIDSE_PW_Drums with
2186
	;; 16bit pulsewidth in IRQ_TMP[12]
2187
 
362 tk 2188
	;; bassline engine: select OSC2/3 pulsewidth depending on voice
2189
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
2190
	andlw	0x03
2191
	xorlw	0x01
2192
	bnz	SIDSE_PW_NoBassline
2193
SIDSE_PW_Bassline
2194
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2195
	bz	SIDSE_PW_Bassline_V1L
2196
	addlw	-1
2197
	bz	SIDSE_PW_Bassline_V2L
2198
	addlw	-1
2199
	bz	SIDSE_PW_Bassline_V3L
2200
	addlw	-1
2201
	bz	SIDSE_PW_Bassline_V1R
2202
	addlw	-1
2203
	bz	SIDSE_PW_Bassline_V2R
2204
	;; 	rgoto	SIDSE_PW_Bassline_V3R
2205
 
2206
SIDSE_PW_Bassline_V3L	; store SID_Ix_V_V3_PULSEWIDTH_[LH] in IRQ_TMP[12]
2207
SIDSE_PW_Bassline_V3R
2208
	movlw	SID_Ix_B_V3_PULSEWIDTH_L
2209
	movff	PLUSW0, IRQ_TMP1
2210
	movlw	SID_Ix_B_V3_PULSEWIDTH_H
2211
	rgoto	SIDSE_PW_Bassline_Cont
2212
 
2213
SIDSE_PW_Bassline_V2L	; store SID_Ix_V_V2_PULSEWIDTH_[LH] in IRQ_TMP[12]
2214
SIDSE_PW_Bassline_V2R
1 tk 2215
	;; store 12bit pulsewidth in IRQ_TMP[12]
362 tk 2216
	movlw	SID_Ix_B_V2_PULSEWIDTH_L
2217
	movff	PLUSW0, IRQ_TMP1
2218
	movlw	SID_Ix_B_V2_PULSEWIDTH_H
2219
	rgoto	SIDSE_PW_Bassline_Cont
2220
 
2221
SIDSE_PW_Bassline_V1L	; store SID_Ix_Vx_PULSEWIDTH_[LH] in IRQ_TMP[12]
2222
SIDSE_PW_Bassline_V1R
2223
SIDSE_PW_NoBassline
1 tk 2224
	movlw	SID_Ix_Vx_PULSEWIDTH_L
2225
	movff	PLUSW0, IRQ_TMP1
2226
	movlw	SID_Ix_Vx_PULSEWIDTH_H
362 tk 2227
SIDSE_PW_Bassline_Cont
1 tk 2228
	movf	PLUSW0, W
2229
	andlw	0x0f
2230
	movwf	IRQ_TMP2
2231
 
2232
	;; extend to 16bit
2233
	swapf	IRQ_TMP2, F
2234
	swapf	IRQ_TMP1, W
2235
	andlw	0x0f
2236
	iorwf	IRQ_TMP2, F
2237
	swapf	IRQ_TMP1, W
2238
	andlw	0xf0
2239
	movwf	IRQ_TMP1
2240
 
2241
SIDSE_PW_Drums
2242
	;; transfer pointer to SIDx_Vx_PW_L register -> FSR2
2243
	call	SIDSE_Hlp_GetSIDPWPtr
2244
 
2245
	;; calculate pointer to MOD target array -> FSR2
2246
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2247
	addlw	(SID_MOD_TARG_PW1_L-SID_MOD_TARG_BASE)/3
2248
	mullw	3
2249
	lfsr	FSR1, SID_MOD_TARG_BASE
2250
	movf	PRODL, W
2251
	addwf	FSR1L, F
2252
 
2253
	;; add modulation value to pulsewidth
2254
	movf	POSTINC1, W
2255
	addwf	IRQ_TMP1, F
2256
	movf	POSTINC1, W
2257
	addwfc	IRQ_TMP2, F
2258
 
2259
	;; saturate
2260
	BRA_IFSET INDF1, 7, ACCESS, SIDSE_PW_Mod_SatNeg
2261
SIDSE_PW_Mod_SatPos
2262
	movf	INDF1, W
2263
	bnz	SIDSE_PW_Mod_SatPos_Sat
2264
	bnc	SIDSE_PW_Mod_Sat_NoSat
2265
SIDSE_PW_Mod_SatPos_Sat
2266
	setf	IRQ_TMP1
2267
	setf	IRQ_TMP2
2268
	rgoto	SIDSE_PW_Mod_Sat_Cont
2269
SIDSE_PW_Mod_SatNeg
2270
	comf	INDF1, W
2271
	bnz	SIDSE_PW_Mod_SatNeg_Sat
2272
	bc	SIDSE_PW_Mod_Sat_NoSat
2273
SIDSE_PW_Mod_SatNeg_Sat
2274
	clrf	IRQ_TMP1
2275
	clrf	IRQ_TMP2
2276
	;; 	rgoto	SIDSE_PW_Mod_Sat_Cont
2277
SIDSE_PW_Mod_Sat_Cont
2278
SIDSE_PW_Mod_Sat_NoSat
2279
 
2280
	;; convert back to 12bit value -> IRQ_TMP[34]
2281
	swapf	IRQ_TMP1, W
2282
	andlw	0x0f
2283
	movwf	IRQ_TMP3
2284
	swapf	IRQ_TMP2, W
2285
	andlw	0xf0
2286
	iorwf	IRQ_TMP3, F
2287
	swapf	IRQ_TMP2, W
2288
	andlw	0x0f
2289
	movwf	IRQ_TMP4
2290
 
2291
	;; transfer to SID registers
2292
	movff	IRQ_TMP3, POSTINC2
2293
	movff	IRQ_TMP4, POSTDEC2
2294
 
2295
	;; forward pulsewidth to AOUT if enabled
2296
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2297
	BRA_IFCLR WREG, SID_ENS_CTRL2_P2A, ACCESS, SIDSE_PW_NoAOUT
2298
SIDSE_PW_AOUT
2299
	;; get channel assignment (0: channel disabled)
2300
	movlw	LOW(SIDSE_PW_EXT_ASSG_TABLE)
2301
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
2302
	movwf	TBLPTRL
2303
	clrf	TBLPTRH
2304
	movlw	HIGH(SIDSE_PW_EXT_ASSG_TABLE)
2305
	addwfc	TBLPTRH, F
2306
	clrf    TBLPTRU
2307
        movlw   UPPER(SIDSE_PW_EXT_ASSG_TABLE)
2308
	addwfc	TBLPTRU, F
2309
	tblrd*+
2310
	movf	TABLAT, W
2311
	bz	SIDSE_PW_NoAOUT		; channel assignment disabled
2312
 
136 tk 2313
	;; forward IRQ_TMP[12] to channel #TABLAT-1
2314
	movff	IRQ_TMP1, MIOS_PARAMETER1
2315
	movff	IRQ_TMP2, MIOS_PARAMETER2
1 tk 2316
	decf	TABLAT, W
136 tk 2317
	call	AOUT_Pin16bitSet
2318
	SET_BSR	SID_BASE
1 tk 2319
 
2320
	;; notify that channel has already been updated by P2A function
2321
	decf	TABLAT, W
2322
	call	MIOS_HLP_GetBitORMask
2323
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2324
SIDSE_PW_NoAOUT
2325
	return
2326
 
2327
 
2328
	;; AOUT assignments for P2A
2329
SIDSE_PW_EXT_ASSG_TABLE
2330
	db	DEFAULT_P2A_OSC1_L_AOUT, DEFAULT_P2A_OSC2_L_AOUT
2331
	db	DEFAULT_P2A_OSC3_L_AOUT, DEFAULT_P2A_OSC1_R_AOUT
2332
	db	DEFAULT_P2A_OSC2_L_AOUT, DEFAULT_P2A_OSC3_R_AOUT
2333
 
2334
;; --------------------------------------------------------------------------
2335
;; This function handles the Filter
2336
;; IN: pointer to SID_Ix_L_SxF_BASE in FSR0 (patch record)
2337
;;     pointer to SID_MOD_TARG_FILx_L in FSR1 (modulation target)
2338
;;     pointer to SIDx_BASE in FSR2 (SID registers)
2339
;;     Filter number in SID_SE_ELEMENT_NUM
2340
;; --------------------------------------------------------------------------
2341
SIDSE_Filter
2342
	;; store 12bit cutoff in IRQ_TMP[12]
2343
	movlw	SID_Ix_L_Fx_CUTOFF_L
2344
	movff	PLUSW0, IRQ_TMP1
2345
	movlw	SID_Ix_L_Fx_CUTOFF_H
2346
	movf	PLUSW0, W
2347
	andlw	0x0f
2348
	movwf	IRQ_TMP2
2349
 
2350
	;; extend to 16bit
2351
	swapf	IRQ_TMP2, F
2352
	swapf	IRQ_TMP1, W
2353
	andlw	0x0f
2354
	iorwf	IRQ_TMP2, F
2355
	swapf	IRQ_TMP1, W
2356
	andlw	0xf0
2357
	movwf	IRQ_TMP1
2358
 
2359
	;; pointer to SID_MOD_TARG_FILx_L already in FSR1
880 tk 2360
	;; multiplty target value by 2 (to simplify extreme modulation results)
1 tk 2361
	;; -> IRQ_TMP[345]
2362
	movf	INDF1, W
2363
	addwf	POSTINC1, W
2364
	movwf	IRQ_TMP3
2365
	movf	INDF1, W
2366
	addwfc	POSTINC1, W
2367
	movwf	IRQ_TMP4
2368
	movf	INDF1, W
2369
	addwfc	POSTINC1, W
2370
	movwf	IRQ_TMP5
2371
 
2372
	;; add modulation value to cutoff
2373
	movf	IRQ_TMP3, W
2374
	addwf	IRQ_TMP1, F
2375
	movf	IRQ_TMP4, W
2376
	addwfc	IRQ_TMP2, F
2377
 
2378
	;; saturate
2379
	BRA_IFSET IRQ_TMP5, 7, ACCESS, SIDSE_Filter_Mod_SatNeg
2380
SIDSE_Filter_Mod_SatPos
2381
	movf	IRQ_TMP5, W
2382
	bnz	SIDSE_Filter_Mod_SatPos_Sat
2383
	bnc	SIDSE_Filter_Mod_Sat_NoSat
2384
SIDSE_Filter_Mod_SatPos_Sat
2385
	setf	IRQ_TMP1
2386
	setf	IRQ_TMP2
2387
	rgoto	SIDSE_Filter_Mod_Sat_Cont
2388
SIDSE_Filter_Mod_SatNeg
2389
	comf	IRQ_TMP5, W
2390
	bnz	SIDSE_Filter_Mod_SatNeg_Sat
2391
	bc	SIDSE_Filter_Mod_Sat_NoSat
2392
SIDSE_Filter_Mod_SatNeg_Sat
2393
	clrf	IRQ_TMP1
2394
	clrf	IRQ_TMP2
2395
	;; 	rgoto	SIDSE_Filter_Mod_Sat_Cont
2396
SIDSE_Filter_Mod_Sat_Cont
2397
SIDSE_Filter_Mod_Sat_NoSat
2398
 
398 tk 2399
	;; bassline and lead engine: add keytracking * linear frequency value
1 tk 2400
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
2401
	andlw	0x03
340 tk 2402
	bz	SIDSE_Filter_KTr
1 tk 2403
	xorlw	0x01
2404
	bnz	SIDSE_Filter_KTr_Skip
2405
SIDSE_Filter_KTr
2406
	movlw	SID_Ix_L_Fx_KEYTRACK
2407
	movf	PLUSW0, W
2408
	bz	SIDSE_Filter_KTr_Skip
2409
	movwf	PRODL
2410
 
398 tk 2411
	;; linear frequency value -> PRODH
2412
	movff	SIDL_V1_BASE + SID_Vx_LINEAR_FRQ_H, PRODH
1 tk 2413
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
398 tk 2414
	movff	SIDR_V1_BASE + SID_Vx_LINEAR_FRQ_H, PRODH
340 tk 2415
 
2416
	;; if keytracking == 0xff: no multiplication required -> 100%
2417
	incf	PRODL, W
2418
	bnz	SIDSE_Filter_KTr_No100P
2419
SIDSE_Filter_KTr_100P
2420
	clrf	PRODL		; 100%, key value already in PRODH
2421
	rgoto	SIDSE_Filter_KTr_100P_Cont
2422
 
2423
SIDSE_Filter_KTr_No100P
2424
	incf	PRODL, F	; <100%
2425
	incf	PRODH, W
1 tk 2426
	mulwf	PRODL, ACCESS
2427
 
340 tk 2428
SIDSE_Filter_KTr_100P_Cont
2429
 
2430
	;; bias at C-3 (0x3c)
2431
	movlw	-(0x3c << 1)
2432
	addwf	PRODH, F
2433
 
2434
	;; add to filter and saturate if required
1 tk 2435
	movf	PRODL, W
2436
	addwf	IRQ_TMP1, F
2437
	movf	PRODH, W
2438
	addwfc	IRQ_TMP2, F
340 tk 2439
	BRA_IFSET PRODH, 7, ACCESS, SIDSE_Filter_KTr_SatNeg
2440
SIDSE_Filter_KTr_SatPos
2441
	bnc	SIDSE_Filter_KTr_Sat_End
1 tk 2442
	setf	IRQ_TMP1
2443
	setf	IRQ_TMP2
340 tk 2444
	rgoto	SIDSE_Filter_KTr_Sat_End
2445
 
2446
SIDSE_Filter_KTr_SatNeg
2447
	bc	SIDSE_Filter_KTr_Sat_End
2448
	clrf	IRQ_TMP1
2449
	clrf	IRQ_TMP2
2450
	;; 	rgoto	SIDSE_Filter_KTr_Sat_End
2451
SIDSE_Filter_KTr_Sat_End
1 tk 2452
SIDSE_Filter_KTr_Skip
2453
 
2454
 
340 tk 2455
	;; transform to log scale if enabled
2456
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
2457
	BRA_IFCLR WREG, SID_ENS_CTRL1_FIL_LOG, ACCESS, SIDSE_Filter_NoLog
2458
SIDSE_Filter_Log
2459
	rrf	IRQ_TMP2, W			; take only upper 7bit
2460
	andlw	0x7f
2461
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; re-use frequency table
2462
	tblrd*+
2463
	movff	TABLAT, IRQ_TMP1
2464
	tblrd*+
2465
	movff	TABLAT, IRQ_TMP2
2466
SIDSE_Filter_NoLog
2467
 
1 tk 2468
	;; copy SID_Gx_CALI_FIL[12]_[MIN|MAX]_[LH] into IRQ_TMP[34]/PROD[LH] depending on selected filter
2469
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Filter_MinMax2
2470
SIDSE_Filter_MinMax1
2471
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MIN_L, IRQ_TMP3
2472
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MIN_H, IRQ_TMP4
2473
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MAX_L, PRODL
2474
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MAX_H, PRODH
2475
	rgoto	SIDSE_Filter_MinMax_Cont
2476
SIDSE_Filter_MinMax2
2477
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MIN_L, IRQ_TMP3
2478
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MIN_H, IRQ_TMP4
2479
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MAX_L, PRODL
2480
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MAX_H, PRODH
2481
	;; 	rgoto	SIDSE_Filter_MinMax_Cont
2482
SIDSE_Filter_MinMax_Cont
2483
 
2484
	;; scale between min/max value
2485
	movf	IRQ_TMP3, W	; SID_Gx_CALI_FIL1_MIN_L
2486
	subwf	PRODL, W	; SID_Gx_CALI_FIL1_MAX_L
2487
	movff	WREG, MUL_A_L
2488
	movf	IRQ_TMP4, W	; SID_Gx_CALI_FIL1_MIN_H
2489
	subwfb	PRODH, W	; SID_Gx_CALI_FIL1_MAX_H
2490
	movff	WREG, MUL_A_H
2491
	movff	IRQ_TMP1, MUL_B_L
2492
	movff	IRQ_TMP2, MUL_B_H
2493
	;; calc MUL_A_[LH] * MUL_B_[LH]
2494
	call	MATH_MUL16_16
2495
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
2496
	movf	IRQ_TMP3, W	; SID_Gx_CALI_FIL1_MIN_L
2497
	addwf	MUL_R_2, W, BANKED
2498
	movwf	IRQ_TMP1
2499
	movf	IRQ_TMP4, W	; SID_Gx_CALI_FIL1_MIN_H
2500
	addwfc	MUL_R_3, W, BANKED
2501
	movwf	IRQ_TMP2
2502
 
2503
	;; optional interpolation
2504
	movlw	SID_Ix_L_Fx_CUTOFF_H
2505
	BRA_IFCLR PLUSW0, SID_I_F_FIP_ON, ACCESS, SIDSE_Filter_NoIP
2506
SIDSE_Filter_IP
2507
	lfsr	FSR1, FIP1_BASE
2508
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2509
	skpz
2510
	lfsr	FSR1, FIP2_BASE
2511
	rcall	SIDSE_Hlp_IP
2512
SIDSE_Filter_NoIP
2513
 
904 tk 2514
	;; map to calibration table in sid_filter_table.inc
2515
#if 1
2516
	;; convert 16bit to 12bit value and create table pointer
2517
	;; to save CPU cycles, we assume that the table is located at 0x17000
2518
  IF LOW(SID_FILTER_TABLE) != 0x00
2519
    ERROR "SID_FILTER_TABLE assigned to wrong address, expecting 0x17000"
2520
  ENDIF
2521
  IF HIGH(SID_FILTER_TABLE) != 0x70
2522
    ERROR "SID_FILTER_TABLE assigned to wrong address, expecting 0x17000"
2523
  ENDIF
2524
  IF UPPER(SID_FILTER_TABLE) != 0x01
2525
    ERROR "SID_FILTER_TABLE assigned to wrong address, expecting 0x17000"
2526
  ENDIF
2527
 
2528
	swapf	IRQ_TMP1, W
2529
	andlw	0x0e		; bit #0 always 0 to ensure correct alignment
2530
	movwf	TBLPTRL
2531
	swapf	IRQ_TMP2, W
2532
	andlw	0xf0
2533
	iorwf	TBLPTRL, F
2534
	swapf	IRQ_TMP2, W
2535
	andlw	0x0f
2536
	addlw	HIGH(SID_FILTER_TABLE)
2537
	movwf	TBLPTRH
2538
	movlw	UPPER(SID_FILTER_TABLE)
2539
	movwf	TBLPTRU
2540
 
2541
	;; read low-byte
2542
	tblrd*+
2543
	swapf	TABLAT, F	; SID format: 3 lowes bits in bit [2:0] of low-register
2544
	clrc
2545
	rrf	TABLAT, F
2546
	movlw	SIDx_FC_L
2547
	movff	TABLAT, PLUSW2
2548
 
2549
	;; read high-byte
2550
	tblrd*+
2551
	movlw	SIDx_FC_H
2552
	movff	TABLAT, PLUSW2
2553
#else
1 tk 2554
	;; convert to 11bit value (SID format: 3 lowes bits in bit [2:0] of low-register)
2555
	swapf	IRQ_TMP1, W
2556
	rrf	WREG, W
2557
	andlw	0x07
2558
	movwf	IRQ_TMP3
2559
 
2560
	;; transfer to SID registers
2561
	movlw	SIDx_FC_L
2562
	movff	IRQ_TMP3, PLUSW2
2563
	movlw	SIDx_FC_H
2564
	movff	IRQ_TMP2, PLUSW2
904 tk 2565
#endif
1 tk 2566
 
2567
	;; Forward CutOff and Resonance to AOUT if enabled
2568
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2569
	BRA_IFCLR WREG, SID_ENS_CTRL2_F2A, ACCESS, SIDSE_Filter_NoAOUT
2570
SIDSE_Filter_AOUT
2571
	;; expecting 16bit value in IRQ_TMP[12] and pointer to AOUT register in FSR1
2572
#if DEFAULT_F2A_CUTOFF_L_AOUT == 0 || DEFAULT_F2A_CUTOFF_L_AOUT > 8
2573
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2574
	bz	SIDSE_Filter_AOUT_NoCutOff
2575
#endif
2576
#if DEFAULT_F2A_CUTOFF_R_AOUT == 0 || DEFAULT_F2A_CUTOFF_R_AOUT > 8
2577
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2578
	bz	SIDSE_Filter_AOUT_NoCutOff
2579
#endif
2580
 
990 tk 2581
	;; forward IRQ_TMP[12] to predefined channel
136 tk 2582
	movff	IRQ_TMP1, MIOS_PARAMETER1
2583
	movff	IRQ_TMP2, MIOS_PARAMETER2
2584
	movlw	DEFAULT_F2A_CUTOFF_L_AOUT-1
1 tk 2585
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2586
	movlw	DEFAULT_F2A_CUTOFF_R_AOUT-1
2587
	call	AOUT_Pin16bitSet
2588
	SET_BSR	SID_BASE
1 tk 2589
 
2590
	;; notify that channel has already been updated by F2A function
2591
	;; (for faster handling, do this for all enabled channels each time this function is called)
2592
	movlw	0x00
2593
#if DEFAULT_F2A_CUTOFF_L_AOUT
2594
	iorlw	(1 << (DEFAULT_F2A_CUTOFF_L_AOUT-1))
2595
#endif
2596
#if DEFAULT_F2A_CUTOFF_R_AOUT
2597
	iorlw	(1 << (DEFAULT_F2A_CUTOFF_R_AOUT-1))
2598
#endif
2599
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2600
SIDSE_Filter_AOUT_NoCutOff
2601
 
2602
#if DEFAULT_F2A_RESONANCE_L_AOUT == 0 || DEFAULT_F2A_RESONANCE_L_AOUT > 8
2603
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2604
	bz	SIDSE_Filter_AOUT_NoResonance
2605
#endif
2606
#if DEFAULT_F2A_RESONANCE_R_AOUT == 0 || DEFAULT_F2A_RESONANCE_R_AOUT > 8
2607
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2608
	bz	SIDSE_Filter_AOUT_NoResonance
2609
#endif
2610
 
2611
	;; resonance (8bit)
2612
	movlw	SID_Ix_L_Fx_RESONANCE
136 tk 2613
	movff	PLUSW0, MIOS_PARAMETER2
2614
	clrf	MIOS_PARAMETER1
2615
	movlw	DEFAULT_F2A_RESONANCE_L_AOUT-1
1 tk 2616
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2617
	movlw	DEFAULT_F2A_RESONANCE_R_AOUT-1
2618
	call	AOUT_Pin16bitSet
2619
	SET_BSR	SID_BASE
1 tk 2620
 
2621
	;; notify that channel has already been updated by F2A function
2622
	;; (for faster handling, do this for all enabled channels each time this function is called)
2623
	movlw	0x00
2624
#if DEFAULT_F2A_RESONANCE_L_AOUT
2625
	iorlw	(1 << (DEFAULT_F2A_RESONANCE_L_AOUT-1))
2626
#endif
2627
#if DEFAULT_F2A_RESONANCE_R_AOUT
2628
	iorlw	(1 << (DEFAULT_F2A_RESONANCE_R_AOUT-1))
2629
#endif
2630
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2631
SIDSE_Filter_AOUT_NoResonance
2632
SIDSE_Filter_NoAOUT
2633
 
2634
	;; Channels and Resonance
2635
	movlw	SID_Ix_L_Fx_CHN_MODE
2636
	movf	PLUSW0, W
2637
	andlw	0x0f
2638
	movwf	PRODL
2639
	movlw	SID_Ix_L_Fx_RESONANCE
2640
	movf	PLUSW0, W
2641
	andlw	0xf0
2642
	iorwf	PRODL, F
2643
	movlw	SIDx_RES_FCHN
2644
	movff	PRODL, PLUSW2
2645
 
2646
	;; volume and filter mode
2647
 
2648
	;; volume can be modulated (result in IRQ_TMP[12])
2649
	clrf	IRQ_TMP1
2650
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_VOLUME, IRQ_TMP2
2651
	clrc
2652
	rlf	IRQ_TMP2, F
2653
 
2654
	;; calculate pointer to MOD target array -> FSR2
2655
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2656
	addlw	(SID_MOD_TARG_VOL1_L-SID_MOD_TARG_BASE)/3
2657
	mullw	3
2658
	lfsr	FSR1, SID_MOD_TARG_BASE
2659
	movf	PRODL, W
2660
	addwf	FSR1L, F
2661
	movf	POSTINC1, W
2662
	addwf	IRQ_TMP1, F
2663
	movf	POSTINC1, W
2664
	addwfc	IRQ_TMP2, F
2665
 
2666
	;; saturate
2667
	BRA_IFSET INDF1, 7, ACCESS, SIDSE_Filter_Mod_Vol_SatNeg
2668
SIDSE_Filter_Mod_Vol_SatPos
2669
	movf	INDF1, W
2670
	bnz	SIDSE_Filter_Mod_Vol_SatPos_Sat
2671
	bnc	SIDSE_Filter_Mod_Vol_NoSat
2672
SIDSE_Filter_Mod_Vol_SatPos_Sat
2673
	setf	IRQ_TMP1
2674
	setf	IRQ_TMP2
2675
	rgoto	SIDSE_Filter_Mod_Vol_Sat_Cont
2676
SIDSE_Filter_Mod_Vol_SatNeg
2677
	comf	INDF1, W
2678
	bnz	SIDSE_Filter_Mod_Vol_SatNeg_Sat
2679
	bc	SIDSE_Filter_Mod_Vol_NoSat
2680
SIDSE_Filter_Mod_Vol_SatNeg_Sat
2681
	clrf	IRQ_TMP1
2682
	clrf	IRQ_TMP2
2683
	;; 	rgoto	SIDSE_Filter_Mod_Vol_Sat_Cont
2684
SIDSE_Filter_Mod_Vol_Sat_Cont
2685
SIDSE_Filter_Mod_Vol_NoSat
2686
 
2687
	;; copy SID_Gx_CTRL1 to IRQ_TMP3 - we need this to check if V2A is enabled
2688
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, IRQ_TMP3
2689
 
2690
	;; patch volume -> PRODL
2691
	;; volume always maximum when V2A enabled
2692
	swapf	IRQ_TMP2, W
2693
	andlw	0x0f
2694
	btfsc	IRQ_TMP3, SID_ENS_CTRL2_V2A
2695
	movlw 0x0f
2696
	movwf	PRODL
2697
 
2698
	movlw	SID_Ix_L_Fx_CHN_MODE
2699
	movf	PLUSW0, W
2700
	andlw	0xf0
2701
	iorwf	PRODL, F
2702
	movlw	SIDx_MODE_VOL
2703
	movff	PRODL, PLUSW2
2704
 
2705
	;; Forward Volume to AOUT if enabled
2706
	BRA_IFCLR IRQ_TMP3, SID_ENS_CTRL2_V2A, ACCESS, SIDSE_Filter_Vol_NoAOUT
2707
SIDSE_Filter_Vol_AOUT
2708
	;; expecting 16bit value in IRQ_TMP[12] and pointer to AOUT register in FSR1
2709
#if DEFAULT_V2A_VOLUME_L_AOUT == 0 || DEFAULT_V2A_VOLUME_L_AOUT > 8
2710
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2711
	bz	SIDSE_Filter_Vol_NoAOUT
2712
#endif
2713
#if DEFAULT_V2A_VOLUME_R_AOUT == 0 || DEFAULT_V2A_VOLUME_R_AOUT > 8
2714
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2715
	bz	SIDSE_Filter_Vol_NoAOUT
2716
#endif
2717
 
136 tk 2718
	movff	IRQ_TMP1, MIOS_PARAMETER1
2719
	movff	IRQ_TMP2, MIOS_PARAMETER2
2720
	movlw	DEFAULT_V2A_VOLUME_L_AOUT-1
1 tk 2721
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2722
	movlw	DEFAULT_V2A_VOLUME_R_AOUT-1
2723
	call	AOUT_Pin16bitSet
2724
	SET_BSR	SID_BASE
1 tk 2725
 
2726
	;; notify that channel has already been updated by V2A function
2727
	;; (for faster handling, do this for all enabled channels each time this function is called)
2728
	movlw	0x00
2729
#if DEFAULT_V2A_VOLUME_L_AOUT
2730
	iorlw	(1 << (DEFAULT_V2A_VOLUME_L_AOUT-1))
2731
#endif
2732
#if DEFAULT_V2A_VOLUME_R_AOUT
2733
	iorlw	(1 << (DEFAULT_V2A_VOLUME_R_AOUT-1))
2734
#endif
2735
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2736
SIDSE_Filter_Vol_NoAOUT
2737
 
2738
	return
2739
 
2740
 
2741
;; --------------------------------------------------------------------------
2742
;; This function handles the AOUTs
2743
;; Used by Bassline/Drum and Multi Engine
2744
;; IN: pointer to SID_Ix_EXT_PARx_L in FSR0 (patch record)
2745
;;     EXT number in SID_SE_ELEMENT_NUM
2746
;; --------------------------------------------------------------------------
2747
SIDSE_BDM_EXT
2748
	;; skip if any F2X function has already updated the AOUTx register
2749
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2750
	call	MIOS_HLP_GetBitORMask
2751
	andwf	SID_SE_EXT_ALLOCATED, W, BANKED
2752
	bnz	SIDSE_BDM_EXT_End
2753
 
136 tk 2754
	;; store 16bit offset in MIOS_PARAMETER[12]
2755
	movff	POSTINC0, MIOS_PARAMETER1
2756
	movff	POSTDEC0, MIOS_PARAMETER2
2757
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2758
	call	AOUT_Pin16bitSet
2759
	SET_BSR	SID_BASE
1 tk 2760
 
2761
SIDSE_BDM_EXT_End
2762
	return
2763
 
2764
 
2765
;; --------------------------------------------------------------------------
2766
;; This function updates the 8 external switches (called once per update cycle)
2767
;; IN: -
2768
;; --------------------------------------------------------------------------
2769
SIDSE_EXT_Switches
136 tk 2770
	lfsr	FSR1, GATES			; for easier addressing
1 tk 2771
 
136 tk 2772
	;; copy switch state from patch to GATES
1 tk 2773
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_CUSTOM_SW, INDF1
2774
 
2775
	;; help macro to improve oversight
2776
SIDSE_EXT_SWITCHES_FORWARD MACRO addr, flag, out
2777
	;; overlay with various gate functions if enabled
2778
  IF out && (out <= 8)
2779
	bcf	INDF1, 	out-1
2780
	btfsc	addr, flag, BANKED
2781
	bsf	INDF1, 	out-1
2782
  ENDIF
2783
	ENDM
2784
 
2785
	SET_BSR	SIDL_V1_BASE			; BSR set to SIDx_Vx_BASE for direct access
2786
 
2787
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC1_L_OUT
2788
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC2_L_OUT
2789
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC3_L_OUT
2790
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC1_R_OUT
2791
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC2_R_OUT
2792
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC3_R_OUT
2793
 
2794
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC1_L_OUT
2795
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC2_L_OUT
2796
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC3_L_OUT
2797
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC1_R_OUT
2798
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC2_R_OUT
2799
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC3_R_OUT
2800
 
2801
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC1_L_OUT
2802
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC2_L_OUT
2803
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC3_L_OUT
2804
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC1_R_OUT
2805
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC2_R_OUT
2806
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC3_R_OUT
2807
 
990 tk 2808
	SET_BSR	SIDL_BASE
2809
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_MODE_VOL, 4, DEFAULT_FILTER_LP_L_OUT
2810
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_MODE_VOL, 5, DEFAULT_FILTER_BP_L_OUT
2811
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_MODE_VOL, 6, DEFAULT_FILTER_HP_L_OUT
2812
 
2813
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_MODE_VOL, 4, DEFAULT_FILTER_LP_R_OUT
2814
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_MODE_VOL, 5, DEFAULT_FILTER_BP_R_OUT
2815
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_MODE_VOL, 6, DEFAULT_FILTER_HP_R_OUT
2816
 
2817
 
2818
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_RES_FCHN, 0, DEFAULT_FILTER_O1_L_OUT
2819
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_RES_FCHN, 1, DEFAULT_FILTER_O2_L_OUT
2820
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_RES_FCHN, 2, DEFAULT_FILTER_O3_L_OUT
2821
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_RES_FCHN, 3, DEFAULT_FILTER_EXTIN_L_OUT
2822
 
2823
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_RES_FCHN, 0, DEFAULT_FILTER_O1_R_OUT
2824
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_RES_FCHN, 1, DEFAULT_FILTER_O2_R_OUT
2825
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_RES_FCHN, 2, DEFAULT_FILTER_O3_R_OUT
2826
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_RES_FCHN, 3, DEFAULT_FILTER_EXTIN_R_OUT
2827
 
2828
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V1_CTRL, 4, DEFAULT_WAVE_O1_L_TRI
2829
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V1_CTRL, 5, DEFAULT_WAVE_O1_L_SAW
2830
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V1_CTRL, 6, DEFAULT_WAVE_O1_L_PULSE
2831
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V1_CTRL, 7, DEFAULT_WAVE_O1_L_NOISE
2832
 
2833
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V2_CTRL, 4, DEFAULT_WAVE_O2_L_TRI
2834
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V2_CTRL, 5, DEFAULT_WAVE_O2_L_SAW
2835
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V2_CTRL, 6, DEFAULT_WAVE_O2_L_PULSE
2836
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V2_CTRL, 7, DEFAULT_WAVE_O2_L_NOISE
2837
 
2838
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V3_CTRL, 4, DEFAULT_WAVE_O3_L_TRI
2839
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V3_CTRL, 5, DEFAULT_WAVE_O3_L_SAW
2840
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V3_CTRL, 6, DEFAULT_WAVE_O3_L_PULSE
2841
	SIDSE_EXT_SWITCHES_FORWARD SIDL_BASE + SIDx_V3_CTRL, 7, DEFAULT_WAVE_O3_L_NOISE
2842
 
2843
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V1_CTRL, 4, DEFAULT_WAVE_O1_R_TRI
2844
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V1_CTRL, 5, DEFAULT_WAVE_O1_R_SAW
2845
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V1_CTRL, 6, DEFAULT_WAVE_O1_R_PULSE
2846
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V1_CTRL, 7, DEFAULT_WAVE_O1_R_NOISE
2847
 
2848
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V2_CTRL, 4, DEFAULT_WAVE_O2_R_TRI
2849
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V2_CTRL, 5, DEFAULT_WAVE_O2_R_SAW
2850
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V2_CTRL, 6, DEFAULT_WAVE_O2_R_PULSE
2851
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V2_CTRL, 7, DEFAULT_WAVE_O2_R_NOISE
2852
 
2853
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V3_CTRL, 4, DEFAULT_WAVE_O3_R_TRI
2854
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V3_CTRL, 5, DEFAULT_WAVE_O3_R_SAW
2855
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V3_CTRL, 6, DEFAULT_WAVE_O3_R_PULSE
2856
	SIDSE_EXT_SWITCHES_FORWARD SIDR_BASE + SIDx_V3_CTRL, 7, DEFAULT_WAVE_O3_R_NOISE
2857
 
1 tk 2858
	SET_BSR	SID_BASE			; switch BSR back to SID base
2859
	return
2860
 
2861
 
2862
;; --------------------------------------------------------------------------
2863
;; --------------------------------------------------------------------------
2864
;;  Help Functions which are used by all engines
2865
;; --------------------------------------------------------------------------
2866
;; --------------------------------------------------------------------------
2867
 
2868
;; --------------------------------------------------------------------------
1189 tk 2869
;; Help Function: Divide by 3 by evaluating series x/2 - x/4 + x/8 - x/16...
2870
;; based on http://www.piclist.com/techref/microchip/math/div/8byconst3-aw.htm
2871
;; IN:  8 bit value in IRQ_TMP1
2872
;; OUT: result in IRQ_TMP1
2873
;; USES: WREG
2874
;; --------------------------------------------------------------------------
2875
SIDSE_Hlp_Div3
2876
	movff  IRQ_TMP1, IRQ_TMP2
2877
 	clrf   IRQ_TMP1
2878
 
2879
SIDSE_Hlp_Div3_Loop			;; while IRQ_TMP2 != 0
2880
 	bcf    STATUS, C
2881
 	rrf    IRQ_TMP2, F		;; IRQ_TMP2 /= 2 (i.e. "x/2" in Series)
2882
 	movf   IRQ_TMP2, W
2883
 	btfsc  STATUS, Z		;; ==0?
2884
 	return					;; Yes, done
2885
 
2886
 	addwf  IRQ_TMP1, F		;; IRQ_TMP1 += IRQ_TMP2
2887
 
2888
	rrf    IRQ_TMP2, F		;; IRQ_TMP2 /= 2 (i.e. "x/4" in Series)
2889
	movf   IRQ_TMP2, W
2890
	btfsc  STATUS, Z 		;; ==0?
2891
	return					;; Yes, done
2892
 
2893
	subwf  IRQ_TMP1, f		;; IRQ_TMP1 -= IRQ_TMP2
2894
	goto   SIDSE_Hlp_Div3_Loop
2895
 
2896
;; --------------------------------------------------------------------------
1 tk 2897
;; Help Function: Scale Depth (7bit signed value scales 15bit signed value)
2898
;; IN:  8bit signed depth value (+0x80) in WREG
2899
;;      15bit signed value in MUL_A_[LH]
2900
;; OUT: result in MUL_R_[123]
2901
;; USES: TABLAT
2902
;; --------------------------------------------------------------------------
2903
SIDSE_Hlp_ScaleDepth
2904
	movwf	TABLAT		; temporary store depth value in TABLAT
2905
 
2906
	rcall	SIDSE_Hlp_GetAbs8
2907
	clrc
2908
	rlf	WREG, W
2909
	movwf	MUL_B_L, BANKED
2910
	clrf	MUL_B_H, BANKED
2911
 
2912
	;; 16*16 multiplication, result in MUL_R_[0123]
2913
	call	MATH_MUL16_16_SIGNED
2914
 
2915
	;; invert result if required
2916
	BRA_IFSET TABLAT, 7, ACCESS, SIDSE_Hlp_ScaleDepth_Cont
2917
SIDSE_Hlp_ScaleDepth_Neg
2918
	comf	MUL_R_1, BANKED
2919
	comf	MUL_R_2, BANKED
2920
	comf	MUL_R_3, BANKED
2921
	incf	MUL_R_1, F, BANKED
2922
	skpnz
2923
	incf	MUL_R_2, F, BANKED
2924
	skpnz
2925
	incf	MUL_R_3, F, BANKED
2926
SIDSE_Hlp_ScaleDepth_Cont
2927
	return
2928
 
2929
 
2930
;; --------------------------------------------------------------------------
2931
;; Like SIDSE_Hlp_ScaleDepth, but depth is increased/decreased by SID_Ix_Vx_ACCENT
2932
;; if the SID_SE_STATE, SID_SE_STATE_ACCENT flag is set
2933
;; IN:  8bit signed depth value (+0x80) in WREG
2934
;;      15bit signed value in MUL_A_[LH]
2935
;;      pointer to patch structure in FSR0
2936
;; OUT: result in MUL_R_[123]
2937
;; USES: TABLAT
2938
;; --------------------------------------------------------------------------
2939
SIDSE_Hlp_ScaleDepthAcc
2940
	;; check accent flag
2941
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ACCENT, BANKED, SIDSE_Hlp_ScaleDepth
2942
 
2943
	movwf	MUL_R_1, BANKED	; (used as temporary register)
2944
 
2945
	;; increase/decrease value by 0x40 and saturate
2946
	BRA_IFCLR WREG, 7, ACCESS, SIDSE_Hlp_ScaleDepthAcc_Neg
2947
SIDSE_Hlp_ScaleDepthAcc_Pos
2948
	movlw	SID_Ix_Vx_ACCENT
2949
	movf	PLUSW0, W
2950
	addwf	MUL_R_1, W, BANKED
2951
	btfss	WREG, 7
2952
	movlw 0xff
2953
	rgoto	SIDSE_Hlp_ScaleDepth
2954
SIDSE_Hlp_ScaleDepthAcc_Neg
2955
	movlw	SID_Ix_Vx_ACCENT
2956
	comf	PLUSW0, W
2957
	addlw	1
2958
	btfsc	WREG, 7
2959
	movlw 0x00
2960
	rgoto	SIDSE_Hlp_ScaleDepth
2961
 
2962
;; --------------------------------------------------------------------------
2963
;; Help Function: Get absolute value
2964
;; IN:  signed 16-bit value in IRQ_TMP[12]
2965
;; Out: unsigned absolute value in IRQ_TMP[12]
2966
;;      sign in IRQ_TMP3[0]
2967
;; --------------------------------------------------------------------------
2968
SIDSE_Hlp_GetAbs16
2969
	;; convert IRQ_TMP[12] to unsigned integer, keep sign in IRQ_TMP3[0]
2970
	clrf	IRQ_TMP3
2971
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Hlp_GetABS16_Pos
2972
SIDSE_Hlp_GetABS16_Neg
2973
	bsf	IRQ_TMP3, 0	; memorize sign in IRQ_TMP3[0]
2974
	comf	IRQ_TMP1, F
2975
	comf	IRQ_TMP2, F
2976
	incf	IRQ_TMP1, F
2977
	skpnz
2978
	incf	IRQ_TMP2, F
2979
SIDSE_Hlp_GetABS16_Pos
2980
	return
2981
 
2982
 
2983
;; --------------------------------------------------------------------------
2984
;; Help Function which returns the absolute value
2985
;; IN:  8-bit signed value in WREG
2986
;; OUT:	absolute value (0x00-0x7f) in WREG
2987
;; --------------------------------------------------------------------------
2988
SIDSE_Hlp_GetAbs8
2989
	movf	WREG, W
2990
	skpnz
2991
	addlw	1
2992
	btfss	WREG, 7
2993
	sublw 0x80
2994
	andlw	0x7f
2995
	return
2996
 
2997
;; --------------------------------------------------------------------------
2998
;; Help Function for SIDSE_ENV to increase or decrease the ENV counter
2999
;; IN:  incr value in MIOS_PARAMETER[12]
3000
;;	target level in IRQ_TMP1
3001
;;      pointer to SID_ENVx_BASE in FSR1
3002
;; OUT:	zero flag set if max value reached
3003
;; --------------------------------------------------------------------------
3004
SIDSE_Hlp_ENV_IncrDecrCtr
3005
	;; if current level > target level, branch to decr function
3006
	movlw	SID_ENVx_CTR_H
3007
	movf	PLUSW1, W
3008
	cpfslt	IRQ_TMP1, ACCESS
3009
	rgoto SIDSE_Hlp_ENV_IncrCtr
3010
	rgoto	SIDSE_Hlp_ENV_DecrCtr
3011
 
3012
 
3013
;; --------------------------------------------------------------------------
3014
;; Help Function for SIDSE_ENV to increase the ENV counter
3015
;; IN:  incr value in MIOS_PARAMETER[12]
3016
;;	max level in IRQ_TMP1
3017
;;      pointer to SID_ENVx_BASE in FSR1
3018
;; OUT:	zero flag set if max value reached
3019
;; --------------------------------------------------------------------------
3020
SIDSE_Hlp_ENV_IncrCtr
3021
	;; add to ENV counter
3022
	movf	POSTINC1, W	; SID_ENVx_CTR_L
3023
	addwf	MIOS_PARAMETER1, F
3024
	movf	POSTDEC1, W	; SID_ENVx_CTR_H
3025
	addwfc	MIOS_PARAMETER2, F
3026
	bc	SIDSE_Hlp_ENV_IncrCtr_Max
3027
 
3028
	;; if value >= level: switch to next phase
3029
	movf	MIOS_PARAMETER1, W
3030
	sublw	0x00
3031
	movf	MIOS_PARAMETER2, W
3032
	subwfb	IRQ_TMP1, W
3033
	bc	SIDSE_Hlp_ENV_IncrCtr_NoMax
3034
 
3035
SIDSE_Hlp_ENV_IncrCtr_Max
3036
	;; write level to MIOS_PARAMETER[12]
3037
	movff	IRQ_TMP1, MIOS_PARAMETER2
3038
	clrf	MIOS_PARAMETER1
3039
 
3040
	andlw	0x00		; set zero flag and exit
3041
	return
3042
 
3043
SIDSE_Hlp_ENV_IncrCtr_NoMax
3044
	iorlw	0xff		; clear zero flag and exit
3045
	return
3046
 
3047
 
3048
;; --------------------------------------------------------------------------
3049
;; Help Function for SIDSE_ENV to decrease the ENV counter
3050
;; IN:  decr value in MIOS_PARAMETER[12]
3051
;;	min level in IRQ_TMP1
3052
;;      pointer to SID_ENVx_BASE in FSR1
3053
;; OUT:	zero flag set if min value reached
3054
;; --------------------------------------------------------------------------
3055
SIDSE_Hlp_ENV_DecrCtr
3056
	;; subtraction from ENV counter
3057
	movf	MIOS_PARAMETER1, W
3058
	subwf	POSTINC1, W	; SID_ENVx_CTR_L
3059
	movwf	MIOS_PARAMETER1
3060
	movf	MIOS_PARAMETER2, W
3061
	subwfb	POSTDEC1, W	; SID_ENVx_CTR_H
3062
	movwf	MIOS_PARAMETER2
3063
	bnc	SIDSE_Hlp_ENV_DecrCtr_Min
3064
 
3065
	;; if value < level: switch to next phase
3066
	movlw	0x00
3067
	subwf	MIOS_PARAMETER1, W
3068
	movf	IRQ_TMP1, W
3069
	subwfb	MIOS_PARAMETER2, W
3070
	bc	SIDSE_Hlp_ENV_DecrCtr_NoMin
3071
 
3072
SIDSE_Hlp_ENV_DecrCtr_Min
3073
	;; write level to MIOS_PARAMETER[12]
3074
	movff	IRQ_TMP1, MIOS_PARAMETER2
3075
	clrf	MIOS_PARAMETER1
3076
 
3077
	andlw	0x00		; set zero flag and exit
3078
	return
3079
 
3080
SIDSE_Hlp_ENV_DecrCtr_NoMin
3081
	iorlw	0xff		; clear zero flag and exit
3082
	return
3083
 
3084
;; --------------------------------------------------------------------------
3085
;; Help Function for SIDSE_ENV
3086
;; IN:  pointer to SID_Ix_L_ENVx_BASE in FSR0 (patch record)
3087
;;      pointer to SID_ENVx_BASE in FSR1
3088
;;      curve value in WREG (0x80: no curve)
3089
;;	MBFM_Ix_ENVx_ATTACKx/MBFM_Ix_ENVx_DECAYx or MBFM_Ix_ENVx_SUSTAINx in IRQ_TMP3
3090
;;
3091
;;      Can also be used to determine the delay increment value
3092
;;      In this case, only IRQ_TMP3 (Ix_xxx_Delay) is expected in IRQ_TMP3, and 0x80 in WREG (no curve!)
3093
;;
3094
;; OUT:	value which should be added to - or subtracted from - SID_ENVx_CTR_[LH]
3095
;;      low-byte in MIOS_PARAMETER1; high-byte in MIOS_PARAMETER2
3096
;; --------------------------------------------------------------------------
3097
SIDSE_Hlp_ENV_GetBendedValue
3098
	;; get curve parameter and store it in IRQ_TMP1
3099
	movwf	IRQ_TMP1
3100
	xorlw	0x80		; if != 0x80, we apply the curve, otherwise we have a linear waveform
3101
 	bnz	SIDSE_Hlp_ENV_GetBendedValue_Crv
3102
 
3103
	;; curve not selected, get value from ENV_TABLE
3104
	movf	IRQ_TMP3, W
3105
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
3106
	tblrd*+				; transfer table entry to MUL_A_[LH]
3107
	movff	TABLAT, MIOS_PARAMETER1
3108
	tblrd*+
3109
	movff	TABLAT, MIOS_PARAMETER2
3110
	return
3111
 
3112
SIDSE_Hlp_ENV_GetBendedValue_Crv
3113
	;; copy current counter value to IRQ_TMP2
3114
	movlw	SID_ENVx_CTR_H
3115
	movff	PLUSW1, IRQ_TMP2
3116
 
878 tk 3117
	;; rightshift rate in IRQ_TMP3 (8bit -> 7bit value range)
1 tk 3118
	clrc
3119
	rrf	IRQ_TMP3, F
3120
 
3121
	;; feedback: calculate ABS8(CURVE) * ENV_x_CTR_H
3122
	movf	IRQ_TMP1, W		; get absolute value of curve parameter
3123
	rcall	SIDSE_Hlp_GetAbs8
3124
	btfsc	IRQ_TMP1, 7; invert if positive range (for more logical behaviour of positive/negative curve)
3125
	xorlw 0x7f
3126
	mulwf	IRQ_TMP2, ACCESS	; multiply with current counter value
3127
 
3128
	;; when CURVE parameter < 0x80: bend down, else up
3129
	BRA_IFCLR IRQ_TMP1, 7, ACCESS, SIDSE_Hlp_ENV_GetBendedValueDown
3130
SIDSE_Hlp_ENV_GetBendedValueUp
3131
	comf	IRQ_TMP3, F
3132
	bcf	IRQ_TMP3, 7
3133
	movf	PRODH, W
3134
	subwf	IRQ_TMP3, W
3135
	btfsc	WREG, 7
3136
	movlw 0x00
3137
	rgoto	SIDSE_Hlp_ENV_GetBendedValueCont
3138
 
3139
SIDSE_Hlp_ENV_GetBendedValueDown
3140
	comf	IRQ_TMP3, W
3141
	andlw	0x7f
3142
	addwf	PRODH, W
3143
	btfsc	WREG, 7
3144
	movlw 0x7f
3145
	;; 	rgoto	SIDSE_Hlp_ENV_GetBendedValue_Cont
3146
 
3147
SIDSE_Hlp_ENV_GetBendedValueCont
3148
	andlw	0x7f
3149
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; determine table address
3150
	tblrd*+				; transfer table entry to MIOS_PARAMETER[12]
3151
	movff	TABLAT, MIOS_PARAMETER1
3152
	tblrd*+
3153
	movff	TABLAT, MIOS_PARAMETER2
3154
	return
3155
 
3156
 
3157
;; --------------------------------------------------------------------------
3158
;;  FUNCTION: SIDSE_Hlp_GetSIDFrqPtr
3159
;;  DESCRIPTION: returns pointer to SIDx_V1_FRQ_L register
3160
;;  IN: SID_SE_ELEMENT_NUM
3161
;;  OUT: pointer in FSR2
3162
;; --------------------------------------------------------------------------
3163
SIDSE_Hlp_GetSIDFrqPtr
3164
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Hlp_GetSIDFrqPtr_4567
3165
SIDSE_Hlp_GetSIDFrqPtr_0123
3166
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Hlp_GetSIDFrqPtr_23
3167
SIDSE_Hlp_GetSIDFrqPtr_01
3168
	lfsr	FSR2, SIDL_BASE + SIDx_V1_FRQ_L
3169
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3170
	lfsr	FSR2, SIDL_BASE + SIDx_V2_FRQ_L
3171
	return
3172
 
3173
SIDSE_Hlp_GetSIDFrqPtr_23
3174
	lfsr	FSR2, SIDL_BASE + SIDx_V3_FRQ_L
3175
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3176
	lfsr	FSR2, SIDR_BASE + SIDx_V1_FRQ_L
3177
	return
3178
 
3179
SIDSE_Hlp_GetSIDFrqPtr_4567
3180
	lfsr	FSR2, SIDR_BASE + SIDx_V2_FRQ_L
3181
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3182
	lfsr	FSR2, SIDR_BASE + SIDx_V3_FRQ_L
3183
	return
3184
 
3185
;; --------------------------------------------------------------------------
3186
;;  FUNCTION: SIDSE_Hlp_GetSIDPWPtr
3187
;;  DESCRIPTION: returns pointer to SIDx_V1_PW_L register
3188
;;  IN: SID_SE_ELEMENT_NUM
3189
;;  OUT: pointer in FSR2
3190
;; --------------------------------------------------------------------------
3191
SIDSE_Hlp_GetSIDPWPtr
3192
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Hlp_GetSIDPWPtr_4567
3193
SIDSE_Hlp_GetSIDPWPtr_0123
3194
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Hlp_GetSIDPWPtr_23
3195
SIDSE_Hlp_GetSIDPWPtr_01
3196
	lfsr	FSR2, SIDL_BASE + SIDx_V1_PW_L
3197
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3198
	lfsr	FSR2, SIDL_BASE + SIDx_V2_PW_L
3199
	return
3200
 
3201
SIDSE_Hlp_GetSIDPWPtr_23
3202
	lfsr	FSR2, SIDL_BASE + SIDx_V3_PW_L
3203
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3204
	lfsr	FSR2, SIDR_BASE + SIDx_V1_PW_L
3205
	return
3206
 
3207
SIDSE_Hlp_GetSIDPWPtr_4567
3208
	lfsr	FSR2, SIDR_BASE + SIDx_V2_PW_L
3209
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
3210
	lfsr	FSR2, SIDR_BASE + SIDx_V3_PW_L
3211
	return
3212
 
3213
;; --------------------------------------------------------------------------
3214
;;  FUNCTION: SIDSE_Hlp_Pitch_Mod
3215
;; IN: frequency in SID_SE_TARGET_FRQ_[LH]
3216
;;     Signed Modulation offset in SID_MOD_TARG_PITCHx_[LHU]
3217
;;     Voice number in SID_SE_ELEMENT_NUM
3218
;; OUT: modulated frequency in SID_SE_TARGET_FRQ_[LH]
3219
;; --------------------------------------------------------------------------
3220
SIDSE_Hlp_Pitch_Mod
3221
	;; calculate pointer to MOD target array -> FSR2
3222
	movf	SID_SE_ELEMENT_NUM, W, BANKED
3223
	addlw	(SID_MOD_TARG_PITCH1_L-SID_MOD_TARG_BASE)/3
3224
	mullw	3
3225
	lfsr	FSR2, SID_MOD_TARG_BASE
3226
	movf	PRODL, W
3227
	addwf	FSR2L, F
3228
 
3229
	;; add modulation value to frequency
3230
	movff	POSTINC2, PRODL
3231
	movff	POSTINC2, PRODH
3232
	movff	POSTINC2, TABLAT
3233
 
398 tk 3234
#if 0
391 tk 3235
	;; value is divided by four for better usage of the depth range
1 tk 3236
	clrc
3237
	btfsc	TABLAT, 7
3238
	setc
3239
	rrf	TABLAT, F
3240
	rrf	PRODH, F
3241
	rrf	PRODL, F
3242
 
3243
	clrc
3244
	btfsc	TABLAT, 7
3245
	setc
3246
	rrf	TABLAT, F
3247
	rrf	PRODH, F
3248
	rrf	PRODL, F
391 tk 3249
#endif
1 tk 3250
 
3251
	movf	PRODL, W
3252
	addwf	SID_SE_TARGET_FRQ_L, F, BANKED
3253
	movf	PRODH, W
3254
	addwfc	SID_SE_TARGET_FRQ_H, F, BANKED
3255
 
3256
	;; saturate
3257
	BRA_IFSET TABLAT, 7, ACCESS, SIDSE_Hlp_Pitch_Mod_SatNeg
3258
SIDSE_Hlp_Pitch_Mod_SatPos
3259
	movf	TABLAT, W
3260
	bnz	SIDSE_Hlp_Pitch_Mod_SatPos_Sat
3261
	bnc	SIDSE_Hlp_Pitch_Mod_NoSat
3262
SIDSE_Hlp_Pitch_Mod_SatPos_Sat
3263
	setf	SID_SE_TARGET_FRQ_L, BANKED
3264
	setf	SID_SE_TARGET_FRQ_H, BANKED
3265
	rgoto	SIDSE_Hlp_Pitch_Mod_Sat_Cont
3266
SIDSE_Hlp_Pitch_Mod_SatNeg
3267
	comf	TABLAT, W
3268
	bnz	SIDSE_Hlp_Pitch_Mod_SatNeg_Sat
3269
	bc	SIDSE_Hlp_Pitch_Mod_NoSat
3270
SIDSE_Hlp_Pitch_Mod_SatNeg_Sat
3271
	clrf	SID_SE_TARGET_FRQ_L, BANKED
3272
	clrf	SID_SE_TARGET_FRQ_H, BANKED
3273
	;; 	rgoto	SIDSE_Hlp_Pitch_Mod_Sat_Cont
3274
SIDSE_Hlp_Pitch_Mod_Sat_Cont
3275
SIDSE_Hlp_Pitch_Mod_NoSat
3276
	return
3277
 
3278
;; --------------------------------------------------------------------------
3279
;; Help Function which interpolates a 16bit value
3280
;; IN:  base address of parameter set (FIPx_BASE) in FSR1
3281
;;      target value in IRQ_TMP[12]
3282
;; OUT:	interpolated value in IRQ_TMP[12]
3283
;; USES: PROD[LH]
3284
;; --------------------------------------------------------------------------
3285
SIDSE_Hlp_IP
3286
	;; shift-right target value (internally we have to calculate with a signed 16-bit value)
3287
	clrc
3288
	rrf	IRQ_TMP2, F
3289
	rrf	IRQ_TMP1, F
3290
 
3291
	;; check for new target value
3292
	movlw	FIPx_TARGET_VALUE_L
3293
	movf	PLUSW1, W
3294
	cpfseq	IRQ_TMP1, ACCESS
3295
	rgoto SIDSE_Hlp_IP_Change
3296
	movlw	FIPx_TARGET_VALUE_H
3297
	movf	PLUSW1, W
3298
	cpfseq	IRQ_TMP2, ACCESS
3299
	rgoto SIDSE_Hlp_IP_Change
3300
	rgoto	SIDSE_Hlp_IP_Cont
3301
SIDSE_Hlp_IP_Change
3302
	;; copy new target value
3303
	movlw	FIPx_TARGET_VALUE_L
3304
	movff	IRQ_TMP1, PLUSW1
3305
	movlw	FIPx_TARGET_VALUE_H
3306
	movff	IRQ_TMP2, PLUSW1
3307
 
3308
	;; calculate difference between current value and new target value
3309
	movlw	FIPx_VALUE_L
3310
	movf	PLUSW1, W
3311
	subwf	IRQ_TMP1, W
3312
	movwf	IRQ_TMP1
3313
	movlw	FIPx_VALUE_H
3314
	movf	PLUSW1, W
3315
	subwfb	IRQ_TMP2, W
3316
	movwf	IRQ_TMP2
3317
 
3318
	;; value which will be added on each step: diverence / 8
3319
	rrf	IRQ_TMP2, F
3320
	rrf	IRQ_TMP1, F
3321
	rrf	IRQ_TMP2, F
3322
	rrf	IRQ_TMP1, F
3323
	rrf	IRQ_TMP2, F
3324
	rrf	IRQ_TMP1, F
3325
 
3326
	movf	IRQ_TMP2, W
3327
	andlw	0x1f
3328
	btfsc	WREG, 4
3329
	iorlw 0xe0
3330
	movwf	IRQ_TMP2
3331
 
3332
	;; should be at least 1 (!)
3333
	movf	IRQ_TMP1, W
3334
	iorwf	IRQ_TMP2, W
3335
	skpnz
3336
	incf	IRQ_TMP1, F
3337
 
3338
	;; store divided value
3339
	movlw	FIPx_DIV_VALUE_L
3340
	movff	IRQ_TMP1, PLUSW1
3341
	movlw	FIPx_DIV_VALUE_H
3342
	movff	IRQ_TMP2, PLUSW1
3343
 
3344
SIDSE_Hlp_IP_Cont
3345
 
3346
	;; step handler
3347
 
3348
	;; copy current filter value into IRQ_TMP[12]
3349
	movlw	FIPx_VALUE_L
3350
	movff	PLUSW1, IRQ_TMP1
3351
	movlw	FIPx_VALUE_H
3352
	movff	PLUSW1, IRQ_TMP2
3353
 
3354
	;; do nothing if target value already reached
3355
	movlw	FIPx_TARGET_VALUE_L
3356
	movf	PLUSW1, W
3357
	cpfseq	IRQ_TMP1, ACCESS
3358
	rgoto SIDSE_Hlp_IP_Cont_Do
3359
	movlw	FIPx_TARGET_VALUE_H
3360
	movf	PLUSW1, W
3361
	cpfseq	IRQ_TMP2, ACCESS
3362
	rgoto SIDSE_Hlp_IP_Cont_Do
3363
	rgoto	SIDSE_Hlp_IP_End
3364
SIDSE_Hlp_IP_Cont_Do
3365
 
3366
	;; add div value to current value
3367
	movlw	FIPx_DIV_VALUE_L
3368
	movf	PLUSW1, W
3369
	addwf	IRQ_TMP1, F
3370
	movlw	FIPx_DIV_VALUE_H
3371
	movf	PLUSW1, W
3372
	addwfc	IRQ_TMP2, F
3373
 
3374
	;; end reached on overflow
3375
	BRA_IFSET IRQ_TMP2, 7, ACCESS, SIDSE_Hlp_IP_TargetReached
3376
 
3377
	;; end reached if value >= target value
3378
	movlw	FIPx_TARGET_VALUE_L
3379
	movf	PLUSW1, W
3380
	subwf	IRQ_TMP1, W
3381
	movlw	FIPx_TARGET_VALUE_H
3382
	movf	PLUSW1, W
3383
	subwfb	IRQ_TMP2, W
3384
 
3385
	;; branch depending on increment/decrement
3386
	movlw	FIPx_DIV_VALUE_H
3387
	BRA_IFSET PLUSW1, 7, ACCESS, SIDSE_Hlp_IP_Dec
3388
SIDSE_Hlp_IP_Inc
3389
	bnc	SIDSE_Hlp_IP_End
3390
	;; 	rgoto	SIDSE_Hlp_IP_TargetReached
3391
 
3392
SIDSE_Hlp_IP_TargetReached
3393
	movlw	FIPx_TARGET_VALUE_L
3394
	movff	PLUSW1, IRQ_TMP1
3395
	movlw	FIPx_TARGET_VALUE_H
3396
	movff	PLUSW1, IRQ_TMP2
3397
	rgoto	SIDSE_Hlp_IP_End
3398
 
3399
SIDSE_Hlp_IP_Dec
3400
	bc	SIDSE_Hlp_IP_End
3401
	rgoto	SIDSE_Hlp_IP_TargetReached
3402
 
3403
SIDSE_Hlp_IP_End
3404
	;; copy back IRQ_TMP[12] to FIPx_VALUE_[LH]
3405
	movlw	FIPx_VALUE_L
3406
	movff	IRQ_TMP1, PLUSW1
3407
	movlw	FIPx_VALUE_H
3408
	movff	IRQ_TMP2, PLUSW1
3409
 
3410
	;; left-shift result (it's 16bit unsigned again)
3411
	clrc
3412
	rlf	IRQ_TMP1, F
3413
	rlf	IRQ_TMP2, F
3414
 
3415
	return
3416