1/*
2 * PicoDrive
3 * (C) notaz, 2006
4 * (C) kub, 2020	added SSG-EG and simple output rate interpolation
5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
9
10@ this is a rewrite of MAME's ym2612 code, in particular this is only the main sample-generatin loop.
11@ it does not seem to give much performance increase (if any at all), so don't use it if it causes trouble.
12@ - notaz, 2006
13
14@ vim:filetype=armasm
15
16#include "../arm_features.h"
17
18@ very simple YM2612 output rate to sample rate adaption (~500k cycles @44100)
19#define INTERPOL
20#define SSG_EG
21
22.equiv SLOT1, 0
23.equiv SLOT2, 2
24.equiv SLOT3, 1
25.equiv SLOT4, 3
26.equiv SLOT_STRUCT_SIZE, 0x38
27
28.equiv TL_TAB_LEN, 0x1A00
29
30.equiv EG_ATT, 4
31.equiv EG_DEC, 3
32.equiv EG_SUS, 2
33.equiv EG_REL, 1
34.equiv EG_OFF, 0
35
36.equiv EG_SH,		  16             @ 16.16 fixed point (envelope generator timing)
37.equiv EG_TIMER_OVERFLOW, (3*(1<<EG_SH)) @ envelope generator timer overflows every 3 samples (on real chip)
38.equiv LFO_SH,            24  /*  8.24 fixed point (LFO calculations)       */
39
40.equiv ENV_QUIET,	  (2*13*256/8)
41
42.text
43.align 2
44    PIC_LDR_INIT()
45
46@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
47@ writes output to routp, but only if vol_out changes
48.macro update_eg_phase_slot
49#if defined(INTERPOL)
50    ldrh    r0, [r5,#0x34]       @ vol_out
51#endif
52    ldrb    r2, [r5,#0x17]       @ state
53    add     r3, r5, #0x1c
54#if defined(INTERPOL)
55    strh    r0, [r5,#0x36]       @ vol_ipol
56#endif
57    tst     r2, r2
58    beq     0f                   @ EG_OFF
59
60    ldr     r2, [r3, r2, lsl #2] @ pack
61    mov     r3, #1
62    mov     r0, r2, lsr #24      @ shift
63    mov     r3, r3, lsl r0
64    sub     r3, r3, #1
65
66    tst     r1, r3
67    bne     0f                   @ no volume change
68
69    mov     r3, r1, lsr r0
70    ldrb    r0, [r5,#0x30]       @ ssg
71    and     r3, r3, #7
72    add     r3, r3, r3, lsl #1
73    mov     r3, r2, lsr r3
74    and     r3, r3, #7           @ eg_inc_val shift, may be 0
75    ldrb    r2, [r5,#0x17]       @ state
76
77#if defined(SSG_EG)
78    tst     r0, #0x08            @ ssg enabled?
79    tstne   r12, #0x02
80    bne     9f
81#endif
82
83    @ non-SSG-EG mode
84    cmp     r2, #4               @ EG_ATT
85    ldrh    r0, [r5,#0x1a]       @ volume, unsigned (0-1023)
86    beq     4f
87
88    cmp     r2, #2
89    mov     r2, #1
90    mov     r2, r2, lsl r3
91    mov     r2, r2, lsr #1       @ eg_inc_val
92    add     r0, r0, r2
93    blt     1f                   @ EG_REL
94    beq     2f                   @ EG_SUS
95
963:  @ EG_DEC
97    ldr     r2, [r5,#0x1c]       @ sl (can be 16bit?)
98    mov     r3, #EG_SUS
99    cmp     r0, r2               @ if ( volume >= (INT32) SLOT->sl )
100    strgeb  r3, [r5,#0x17]       @ state
101    b       10f
102
1034:  @ EG_ATT
104    subs    r3, r3, #1           @ eg_inc_val_shift - 1
105    mvnpl   r2, r0
106    movpl   r2, r2, lsl r3
107    addpl   r0, r0, r2, asr #4
108    cmp     r0, #0               @ if (volume <= MIN_ATT_INDEX)
109    bgt     10f
110    ldr     r2, [r5,#0x1c]
111    mov     r0, #0
112    cmp     r2, #0
113    movne   r3, #EG_DEC
114    moveq   r3, #EG_SUS
115    strb    r3, [r5,#0x17]       @ state
116    b       10f
117
1182:  @ EG_SUS
119    mov     r2, #1024
120    sub     r2, r2, #1           @ r2 = MAX_ATT_INDEX
121    cmp     r0, r2               @ if ( volume >= MAX_ATT_INDEX )
122    movge   r0, r2
123    b       10f
124
1251:  @ EG_REL
126    mov     r2, #1024
127    sub     r2, r2, #1           @ r2 = MAX_ATT_INDEX
128    cmp     r0, r2               @ if ( volume >= MAX_ATT_INDEX )
129    movge   r0, r2
130    movge   r3, #EG_OFF
131    strgeb  r3, [r5,#0x17]       @ state
132
13310: @ finish
134    ldrh    r3, [r5,#0x18]       @ tl
135    strh    r0, [r5,#0x1a]       @ volume
136#if defined(SSG_EG)
137    b       11f
138
1399:  @ SSG-EG mode
140    ldrh    r0, [r5,#0x1a]       @ volume, unsigned (0-1023)
141    cmp     r2, #4               @ EG_ATT
142    beq     4f
143
144    cmp     r0, #0x200           @ if ( volume < 0x200 )
145    movlt   r0, #1
146    movlt   r3, r0, lsl r3
147    ldrlth  r0, [r5,#0x1a]       @ volume, unsigned (0-1023)
148    movlt   r3, r3, lsr #1       @ eg_inc_val
149    addlt   r0, r0, r3, lsl #2
150
151    cmp     r2, #2
152    blt     1f                   @ EG_REL
153    beq     10f                  @ EG_SUS - nothing more to do
154
1553:  @ EG_DEC
156    ldr     r2, [r5,#0x1c]       @ sl (can be 16bit?)
157    mov     r3, #EG_SUS
158    cmp     r0, r2               @ if ( volume >= (INT32) SLOT->sl )
159    strgeb  r3, [r5,#0x17]       @ state
160    b       10f
161
1624:  @ EG_ATT
163    subs    r3, r3, #1           @ eg_inc_val_shift - 1
164    mvnpl   r2, r0
165    movpl   r2, r2, lsl r3
166    addpl   r0, r0, r2, asr #4
167    cmp     r0, #0               @ if (volume <= MIN_ATT_INDEX)
168    bgt     10f
169    ldr     r2, [r5,#0x1c]
170    mov     r0, #0
171    cmp     r2, #0
172    movne   r3, #EG_DEC
173    moveq   r3, #EG_SUS
174    strb    r3, [r5,#0x17]       @ state
175    b       10f
176
1771:  @ EG_REL
178    mov     r2, #0x200
179    cmp     r0, r2               @ if ( volume >= 0x200 )
180    movge   r0, #1024
181    subge   r0, #1
182    movge   r3, #EG_OFF
183    strgeb  r3, [r5,#0x17]       @ state
184
18510: @ finish
186    ldrb    r2, [r5,#0x30]       @ ssg
187    ldrb    r3, [r5,#0x17]       @ state
188    strh    r0, [r5,#0x1a]       @ volume
189    cmp     r2, #0x0c            @ if ( ssg&0x04 && state > EG_REL )
190    cmpge   r3, #EG_REL+1
191    ldrh    r3, [r5,#0x18]       @ tl
192    rsbge   r0, r0, #0x200       @ volume = (0x200-volume) & MAX_ATT
193    lslge   r0, r0, #22
194    lsrge   r0, r0, #22
195
19611:
197#endif
198    add     r0, r0, r3           @ volume += tl
199    strh    r0, [r5,#0x34]       @ vol_out
200
2010: @ EG_OFF
202.endm
203
204#if defined(SSG_EG)
205@ r5=slot, trashes: r0,r2,r3
206.macro update_ssg_eg
207    ldrh    r0, [r5,#0x30]                @ ssg+ssgn
208    ldrb    r2, [r5,#0x17]                @ state
209    ldrh    r3, [r5,#0x1a]                @ volume
210    tst     r0, #0x08                     @ ssg enabled &&
211    beq     9f
212    cmp     r2, #EG_REL+1                 @   state > EG_REL &&
213    cmpge   r3, #0x200                    @   volume >= 0x200?
214    blt     9f
215    orr     r4, r4, #0x10                 @ ssg_update
216
217    tst     r0, #0x01
218    beq     1f
219
220    tst     r0, #0x02
221    eorne   r0, r0, lsr #8                @ ssg ^= ssgn ^ 4
222    eorne   r0, r0, #0x4
223    orrne   r0, r0, #0x400                @ ssgn = 4
224    strneh  r0, [r5,#0x30]
225
226    eor     r0, r0, #0x4                  @ if ( !(ssg&0x04) )
227    tst     r0, #0x4
228    cmpne   r2, #EG_ATT                   @ if ( state != EG_ATT )
229    movne   r3, #0x400
230    subne   r3, r3, #1
231    strneh  r3, [r5,#0x1a]                @ volume = MAX_ATT
232    b       9f
233
2341:  tst     r0, #0x02
235    eorne   r0, r0, #0x4                  @ ssg ^= 4
236    eorne   r0, r0, #0x400                @ ssgn ^= 4
237    strneh  r0, [r5,#0x30]
238    moveq   r0, #0
239    streq   r0, [r5,#0x0c]                @ phase = 0
240
241    cmp     r2, #EG_ATT                   @ if ( state != EG_ATT )
242    beq     9f
243
244    ldr     r0, [r5,#0x1c]                @ sl
245    mov     r2, #EG_SUS                   @ state = sl==MIN_ATT ? EG_SUS:EG_DEC
246    cmp     r0, #0
247
248    ldrh    r0, [r5,#0x32]                @ ar+ksr
249    movne   r2, #EG_DEC
250    cmp     r0, #32+62                    @ if ( ar+ksr >= 32+62 )
251    movge   r3, #0
252    strgeh  r3, [r5,#0x1a]                @ volume = MIN_ATT
253    bge     9f
254
255    cmp     r3, #0
256    movgt   r2, #EG_ATT
257    strb    r2, [r5,#0x17]                @ state
2589:
259.endm
260
261@ r5=slot, trashes: r0,r2,r3
262.macro recalc_volout
263#if defined(INTERPOL)
264    ldrh    r0, [r5,#0x34]                @ vol_out
265#endif
266    ldrb    r2, [r5,#0x30]                @ ssg
267    ldrb    r3, [r5,#0x17]                @ state
268#if defined(INTERPOL)
269    strh    r0, [r5,#0x36]                @ vol_ipol
270#endif
271    ldrh    r0, [r5,#0x1a]                @ volume
272
273@    and     r2, r2, #0x0c
274    cmp     r2, #0x0c                     @ if ( ~ssg&0x0c && state > EG_REL )
275    cmpge   r3, #EG_REL+1
276    ldrh    r3, [r5,#0x18]                @ tl
277    rsbge   r0, r0, #0x200                @ volume = (0x200-volume) & MAX_ATT
278    lslge   r0, r0, #22
279    lsrge   r0, r0, #22
280    ldrh    r0, [r5,#0x1a]                @ volume
281    ldrh    r3, [r5,#0x18]                @ tl
282
283    add     r0, r0, r3                    @ volume += tl
284    strh    r0, [r5,#0x34]                @ vol_out
285.endm
286#endif
287
288@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch
289.macro advance_lfo_m
290    mov     r2, r2, lsr #LFO_SH
291    cmp     r2, r1, lsr #LFO_SH
292    beq     0f
293    and     r3, r2, #0x3f
294    cmp     r2, #0x40
295    eorlt   r3, r3, #0x3f
296    bic     r12,r12, #0xff000000          @ lfo_ampm &= 0xff
297    orr     r12,r12, r3, lsl #1+24
298
299    mov     r2, r2, lsr #2
300    cmp     r2, r1, lsr #LFO_SH+2
301    bicne   r12,r12, #0xff0000
302    orrne   r12,r12, r2, lsl #16
303
3040:
305.endm
306
307
308@ result goes to r1, trashes r2
309.macro make_eg_out slot
310    tst     r12, #8
311    tstne   r12, #(1<<(\slot+8))
312.if     \slot == SLOT1
313    mov     r1, r6, lsl #16
314    mov     r1, r1, lsr #16
315.elseif \slot == SLOT2
316    mov     r1, r6, lsr #16
317.elseif \slot == SLOT3
318    mov     r1, r7, lsl #16
319    mov     r1, r1, lsr #16
320.elseif \slot == SLOT4
321    mov     r1, r7, lsr #16
322.endif
323    andne   r2, r12, #0xc0
324    movne   r2, r2,  lsr #6
325    addne   r2, r2,  #24
326    addne   r1, r1,  r12, lsr r2
327    bic     r1, r1,  #1
328.endm
329
330
331@ \r=sin/result, r1=env, r3=ym_tl_tab
332.macro lookup_tl r
333    tst     \r, #0x100
334    eorne   \r, \r, #0xff   @ if (sin & 0x100) sin = 0xff - (sin&0xff);
335    tst     \r, #0x200
336    and     \r, \r, #0xff
337    orr     \r, \r, r1, lsl #7
338    mov     \r, \r, lsl #1
339    ldrh    \r, [r3, \r]    @ 2ci if ne
340    rsbne   \r, \r, #0
341.endm
342
343
344@ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
345@ r0-r2=scratch, r3=sin_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
346.macro upd_algo0_m
347
348    @ SLOT3
349    make_eg_out SLOT3
350    cmp     r1, #ENV_QUIET
351    movcs   r0, #0
352    bcs     0f
353    ldr     r2, [lr, #0x18]
354    ldr     r0, [lr, #0x38] @ mem (signed)
355    mov     r2, r2, lsr #16
356    add     r0, r2, r0, lsr #1
357    lookup_tl r0                  @ r0=c2
358
3590:
360
361    @ SLOT4
362    make_eg_out SLOT4
363    cmp     r1, #ENV_QUIET
364    movcs   r0, #0
365    bcs     1f
366    ldr     r2, [lr, #0x1c]
367    mov     r0, r0, lsr #1
368    add     r0, r0, r2, lsr #16
369    lookup_tl r0                  @ r0=output smp
370
3711:
372    @ SLOT2
373    make_eg_out SLOT2
374    cmp     r1, #ENV_QUIET
375    movcs   r2, #0
376    bcs     2f
377    ldr     r2, [lr, #0x14]       @ 1ci
378    mov     r5, r10, lsr #17
379    add     r2, r5, r2, lsr #16
380    lookup_tl r2                  @ r2=mem
381
3822:
383    str     r2, [lr, #0x38] @ mem
384.endm
385
386
387.macro upd_algo1_m
388
389    @ SLOT3
390    make_eg_out SLOT3
391    cmp     r1, #ENV_QUIET
392    movcs   r0, #0
393    bcs     0f
394    ldr     r2, [lr, #0x18]
395    ldr     r0, [lr, #0x38] @ mem (signed)
396    mov     r2, r2, lsr #16
397    add     r0, r2, r0, lsr #1
398    lookup_tl r0                 @ r0=c2
399
4000:
401    @ SLOT4
402    make_eg_out SLOT4
403    cmp     r1, #ENV_QUIET
404    movcs   r0, #0
405    bcs     1f
406    ldr     r2, [lr, #0x1c]
407    mov     r0, r0, lsr #1
408    add     r0, r0, r2, lsr #16
409    lookup_tl r0                 @ r0=output smp
410
4111:
412    @ SLOT2
413    make_eg_out SLOT2
414    cmp     r1, #ENV_QUIET
415    movcs   r2, #0
416    bcs     2f
417    ldr     r2, [lr, #0x14]      @ 1ci
418    mov     r2, r2, lsr #16
419    lookup_tl r2                 @ r2=mem
420
4212:
422    add     r2, r2, r10, asr #16
423    str     r2, [lr, #0x38]
424.endm
425
426
427.macro upd_algo2_m
428
429    @ SLOT3
430    make_eg_out SLOT3
431    cmp     r1, #ENV_QUIET
432    movcs   r0, #0
433    bcs     0f
434    ldr     r2, [lr, #0x18]
435    ldr     r0, [lr, #0x38] @ mem (signed)
436    mov     r2, r2, lsr #16
437    add     r0, r2, r0, lsr #1
438    lookup_tl r0                 @ r0=c2
439
4400:
441    add     r0, r0, r10, asr #16
442
443    @ SLOT4
444    make_eg_out SLOT4
445    cmp     r1, #ENV_QUIET
446    movcs   r0, #0
447    bcs     1f
448    ldr     r2, [lr, #0x1c]
449    mov     r0, r0, lsr #1
450    add     r0, r0, r2, lsr #16
451    lookup_tl r0                 @ r0=output smp
452
4531:
454    @ SLOT2
455    make_eg_out SLOT2
456    cmp     r1, #ENV_QUIET
457    movcs   r2, #0
458    bcs     2f
459    ldr     r2, [lr, #0x14]
460    mov     r2, r2, lsr #16      @ 1ci
461    lookup_tl r2                 @ r2=mem
462
4632:
464    str     r2, [lr, #0x38] @ mem
465.endm
466
467
468.macro upd_algo3_m
469
470    @ SLOT3
471    make_eg_out SLOT3
472    cmp     r1, #ENV_QUIET
473    ldr     r2, [lr, #0x38] @ mem (for future)
474    mov     r0, #0
475    bcs     0f
476    ldr     r0, [lr, #0x18]      @ phase3
477    mov     r0, r0, lsr #16
478    lookup_tl r0                 @ r0=c2
479
4800:
481    add     r0, r0, r2
482
483    @ SLOT4
484    make_eg_out SLOT4
485    cmp     r1, #ENV_QUIET
486    movcs   r0, #0
487    bcs     1f
488    ldr     r2, [lr, #0x1c]
489    mov     r0, r0, lsr #1
490    add     r0, r0, r2, lsr #16
491    lookup_tl r0                 @ r0=output smp
492
4931:
494    @ SLOT2
495    make_eg_out SLOT2
496    cmp     r1, #ENV_QUIET
497    movcs   r2, #0
498    bcs     2f
499    ldr     r2, [lr, #0x14]      @ phase2
500    mov     r5, r10, lsr #17
501    add     r2, r5, r2, lsr #16
502    lookup_tl r2                 @ r2=mem
503
5042:
505    str     r2, [lr, #0x38]      @ mem
506.endm
507
508
509.macro upd_algo4_m
510
511    @ SLOT3
512    make_eg_out SLOT3
513    cmp     r1, #ENV_QUIET
514    movcs   r0, #0
515    bcs     0f
516    ldr     r0, [lr, #0x18]
517    mov     r0, r0, lsr #16      @ 1ci
518    lookup_tl r0                 @ r0=c2
519
5200:
521    @ SLOT4
522    make_eg_out SLOT4
523    cmp     r1, #ENV_QUIET
524    movcs   r0, #0
525    bcs     1f
526    ldr     r2, [lr, #0x1c]
527    mov     r0, r0, lsr #1
528    add     r0, r0, r2, lsr #16
529    lookup_tl r0                 @ r0=output smp
530
5311:
532    @ SLOT2
533    make_eg_out SLOT2
534    cmp     r1, #ENV_QUIET
535    bcs     2f
536    ldr     r2, [lr, #0x14]
537    mov     r5, r10, lsr #17
538    add     r2, r5, r2, lsr #16
539    lookup_tl r2
540    add     r0, r0, r2            @ add to smp
541
5422:
543.endm
544
545
546.macro upd_algo5_m
547
548    @ SLOT3
549    make_eg_out SLOT3
550    cmp     r1, #ENV_QUIET
551    movcs   r0, #0
552    bcs     0f
553    ldr     r2, [lr, #0x18]
554    ldr     r0, [lr, #0x38] @ mem (signed)
555    mov     r2, r2, lsr #16
556    add     r0, r2, r0, lsr #1
557    lookup_tl r0                 @ r0=output smp
558
5590:
560    @ SLOT4
561    make_eg_out SLOT4
562    cmp     r1, #ENV_QUIET
563    bcs     1f
564    ldr     r2, [lr, #0x1c]
565    mov     r5, r10, lsr #17
566    add     r2, r5, r2, lsr #16
567    lookup_tl r2
568    add     r0, r0, r2           @ add to smp
569
5701:  @ SLOT2
571    make_eg_out SLOT2
572    cmp     r1, #ENV_QUIET
573    bcs     2f
574    ldr     r2, [lr, #0x14]
575    mov     r5, r10, lsr #17
576    add     r2, r5, r2, lsr #16
577    lookup_tl r2
578    add     r0, r0, r2           @ add to smp
579
5802:
581    mov     r1, r10, asr #16
582    str     r1, [lr, #0x38] @ mem
583.endm
584
585
586.macro upd_algo6_m
587
588    @ SLOT3
589    make_eg_out SLOT3
590    cmp     r1, #ENV_QUIET
591    movcs   r0, #0
592    bcs     0f
593    ldr     r0, [lr, #0x18]
594    mov     r0, r0, lsr #16      @ 1ci
595    lookup_tl r0                 @ r0=output smp
596
5970:
598    @ SLOT4
599    make_eg_out SLOT4
600    cmp     r1, #ENV_QUIET
601    bcs     1f
602    ldr     r2, [lr, #0x1c]
603    mov     r2, r2, lsr #16      @ 1ci
604    lookup_tl r2
605    add     r0, r0, r2           @ add to smp
606
6071:  @ SLOT2
608    make_eg_out SLOT2
609    cmp     r1, #ENV_QUIET
610    bcs     2f
611    ldr     r2, [lr, #0x14]
612    mov     r5, r10, lsr #17
613    add     r2, r5, r2, lsr #16
614    lookup_tl r2
615    add     r0, r0, r2           @ add to smp
616
6172:
618.endm
619
620
621.macro upd_algo7_m
622
623    @ SLOT3
624    make_eg_out SLOT3
625    cmp     r1, #ENV_QUIET
626    movcs   r0, #0
627    bcs     0f
628    ldr     r0, [lr, #0x18]
629    mov     r0, r0, lsr #16      @ 1ci
630    lookup_tl r0                 @ r0=output smp
631
6320:
633    add     r0, r0, r10, asr #16
634
635    @ SLOT4
636    make_eg_out SLOT4
637    cmp     r1, #ENV_QUIET
638    bcs     1f
639    ldr     r2, [lr, #0x1c]
640    mov     r2, r2, lsr #16      @ 1ci
641    lookup_tl r2
642    add     r0, r0, r2           @ add to smp
643
6441:  @ SLOT2
645    make_eg_out SLOT2
646    cmp     r1, #ENV_QUIET
647    bcs     2f
648    ldr     r2, [lr, #0x14]
649    mov     r2, r2, lsr #16      @ 1ci
650    lookup_tl r2
651    add     r0, r0, r2           @ add to smp
652
6532:
654.endm
655
656
657.macro upd_slot1_m
658
659    make_eg_out SLOT1
660    cmp     r1, #ENV_QUIET
661    movcs   r10, r10, lsl #16     @ ct->op1_out <<= 16; // op1_out0 = op1_out1; op1_out1 = 0;
662    bcs     0f
663    ands    r2, r12, #0xf000
664    moveq   r0, #0
665    movne   r2, r2, lsr #12
666    addne   r0, r10, r10, lsl #16
667    movne   r0, r0, asr #16
668    movne   r0, r0, lsl r2
669
670    ldr     r2, [lr, #0x10]     @ phase1
671    add     r0, r0, r2
672    mov     r0, r0, lsr #16
673    lookup_tl r0
674    mov     r10,r10,lsl #16     @ ct->op1_out <<= 16;
675    mov     r0, r0, lsl #16
676    orr     r10,r10, r0, lsr #16
677
6780:
679.endm
680
681
682@ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
683@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[3],ssg_update,was_update,algo[3], r5=tl_tab/slot,
684@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
685.global chan_render_loop @ chan_rend_context *ct, int *buffer, int length
686
687chan_render_loop:
688    stmfd   sp!, {r4-r11,lr}
689    mov     lr,  r0
690    mov     r4,  r2, lsl #8      @ no more 24 bits here
691    ldr     r12, [lr, #0x4c]
692    ldr     r0,  [lr, #0x50]
693    mov     r11, r1
694    and     r0,  r0, #7
695    orr     r4,  r4, r0          @ (length<<8)|algo
696    ldr     r8, [lr, #0x44]      @ eg_timer
697    ldr     r9, [lr, #0x48]      @ eg_timer_add
698    ldr     r10, [lr, #0x54]     @ op1_out
699
700    tst     r12, #8              @ lfo?
701    beq     crl_loop
702
703crl_loop_lfo:
704    ldr     r1, [lr, #0x30]      @ lfo_cnt
705    ldr     r2, [lr, #0x34]      @ lfo_inc
706
707    subs    r4, r4, #0x100
708    bmi     crl_loop_end
709
710    add     r2, r2, r1
711    str     r2, [lr, #0x30]
712
713    @ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt
714    advance_lfo_m
715
716    add     r4, r4, #0x100
717
718crl_loop:
719    subs    r4, r4, #0x100
720    bmi     crl_loop_end
721
722    ldr     r5, [lr, #0x40]      @ CH
723#if defined(SSG_EG)
724    tst     r12, #0x02              @ ssg_enabled?
725    beq     ssg_done
726    @ -- SSG --
727    lsl     r7, r8, #EG_SH
728    add     r7, r9, r7, lsr #EG_SH
729    subs    r7, r7, #1<<EG_SH
730    blt     ssg_done
731
732ssg_loop:
733    mov     r6, #4
734ssg_upd_loop:
735    update_ssg_eg
736#if 0
737    subs    r6, r6, #1
738    addne   r5, r5, #SLOT_STRUCT_SIZE
739#else
740    add     r5, r5, #SLOT_STRUCT_SIZE*2
741    update_ssg_eg
742    subs    r6, r6, #2
743    subne   r5, r5, #SLOT_STRUCT_SIZE
744#endif
745    bne     ssg_upd_loop
746    sub     r5, r5, #SLOT_STRUCT_SIZE*3
747
748    subs    r7, r7, #1<<EG_SH
749    bge     ssg_loop
750ssg_done:
751#endif
752
753    @ -- EG --
754    add     r8, r8, r9
755    cmp     r8, #EG_TIMER_OVERFLOW
756    bcc     volout_upd
757    ldr     r1, [lr, #0x3c]     @ eg_cnt
758eg_loop:
759    sub     r8, r8, #EG_TIMER_OVERFLOW
760    add     r1, r1, #1
761    cmp     r1, #4096
762    movge   r1, #1
763
764    mov     r6, #4
765eg_upd_loop:
766    update_eg_phase_slot
767#if 1
768    subs    r6, r6, #1
769    addne   r5, r5, #SLOT_STRUCT_SIZE
770#else
771    add     r5, r5, #SLOT_STRUCT_SIZE*2
772    update_eg_phase_slot
773    subs    r6, r6, #2
774    subne   r5, r5, #SLOT_STRUCT_SIZE
775#endif
776    bne     eg_upd_loop
777
778    cmp     r8, #EG_TIMER_OVERFLOW
779    sub     r5, r5, #SLOT_STRUCT_SIZE*3
780    bhs     eg_loop
781    str     r1, [lr, #0x3c]
782    b       eg_done
783
784volout_upd:
785#if defined(SSG_EG)
786    tst     r4, #0x10               @ ssg_update?
787    beq     eg_done
788
789    @ recalc vol_out
790    mov     r6, #4
791volout_loop:
792    recalc_volout
793#if 0
794    subs    r6, r6, #1
795    addne   r5, r5, #SLOT_STRUCT_SIZE
796#else
797    add     r5, r5, #SLOT_STRUCT_SIZE*2
798    recalc_volout
799    subs    r6, r6, #2
800    subne   r5, r5, #SLOT_STRUCT_SIZE
801#endif
802    bne     volout_loop
803    sub     r5, r5, #SLOT_STRUCT_SIZE*3
804#endif
805
806eg_done:
807    @ -- disabled? --
808    and     r0, r12, #0xC
809    cmp     r0, #0xC
810    beq     crl_loop_lfo
811    cmp     r0, #0x4
812    beq     crl_loop
813
814    @ output interpolation
815#if defined(INTERPOL)
816#if 1 // possibly too expensive for slow platforms?
817    @ basic interpolator, interpolate in middle region, else use closer value
818    mov     r3, r8, lsr #EG_SH      @ eg_timer, [0..3<<EG_SH) after loop
819    cmp     r3, #(EG_TIMER_OVERFLOW>>EG_SH)/2
820    bne     0f                      @ mix is vol_out
821
822    ldr     r6, [r5, #0x34]      @ vol_out, vol_ipol for all slots
823    ldr     r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
824    ldr     r7, [r5, #0x34+SLOT_STRUCT_SIZE]
825    ldr     r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
826    add     r6, r6, r6, lsl #16
827    lsr     r6, r6, #17
828    add     r2, r2, r2, lsl #16
829    lsr     r2, r2, #17
830    add     r7, r7, r7, lsl #16
831    lsr     r7, r7, #17
832    add     r3, r3, r3, lsl #16
833    lsr     r3, r3, #17
834    b       1f
835#else
836    @ super-basic... just take value closest to sample point
837    mov     r3, r8, lsr #EG_SH-1    @ eg_timer, [0..3<<EG_SH) after loop
838    cmp     r3, #(EG_TIMER_OVERFLOW>>EG_SH)
839#endif
840
8410:  ldrgeh  r6, [r5, #0x34]      @ vol_out values for all slots
842    ldrlth  r6, [r5, #0x36]      @ vol_ipol values for all slots
843    ldrgeh  r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
844    ldrlth  r2, [r5, #0x36+SLOT_STRUCT_SIZE*2]
845    ldrgeh  r7, [r5, #0x34+SLOT_STRUCT_SIZE]
846    ldrlth  r7, [r5, #0x36+SLOT_STRUCT_SIZE]
847    ldrgeh  r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
848    ldrlth  r3, [r5, #0x36+SLOT_STRUCT_SIZE*3]
849
850#else
851    ldrh    r6, [r5, #0x34]      @ vol_out values for all slots
852    ldrh    r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
853    ldrh    r7, [r5, #0x34+SLOT_STRUCT_SIZE]
854    ldrh    r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
855#endif
8561:  orr     r6, r6, r2, lsl #16
857    orr     r7, r7, r3, lsl #16
858
859    @ -- SLOT1 --
860    PIC_LDR(r3, r2, ym_tl_tab)
861
862    @ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
863    @ r0-r2=scratch, r3=tl_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
864    upd_slot1_m
865
866    @ -- SLOT2+ --
867    and     r0, r4, #7
868    PIC_XB(,r0, lsl #2)
869    nop
870    PIC_BT(crl_algo0)
871    PIC_BT(crl_algo1)
872    PIC_BT(crl_algo2)
873    PIC_BT(crl_algo3)
874    PIC_BT(crl_algo4)
875    PIC_BT(crl_algo5)
876    PIC_BT(crl_algo6)
877    PIC_BT(crl_algo7)
878    .pool
879
880crl_algo0:
881    upd_algo0_m
882    b       crl_algo_done
883    .pool
884
885crl_algo1:
886    upd_algo1_m
887    b       crl_algo_done
888    .pool
889
890crl_algo2:
891    upd_algo2_m
892    b       crl_algo_done
893    .pool
894
895crl_algo3:
896    upd_algo3_m
897    b       crl_algo_done
898    .pool
899
900crl_algo4:
901    upd_algo4_m
902    b       crl_algo_done
903    .pool
904
905crl_algo5:
906    upd_algo5_m
907    b       crl_algo_done
908    .pool
909
910crl_algo6:
911    upd_algo6_m
912    b       crl_algo_done
913    .pool
914
915crl_algo7:
916    upd_algo7_m
917
918
919crl_algo_done:
920    @ -- WRITE SAMPLE --
921    tst     r0, r0
922    beq     ctl_sample_skip
923    orr     r4, r4, #8              @ have_output
924    tst     r12, #1
925    beq     ctl_sample_mono
926
927    tst     r12, #0x20              @ L
928    ldrne   r1, [r11]
929    addeq   r11, r11, #4
930    addne   r1, r0, r1
931    strne   r1, [r11], #4
932    tst     r12, #0x10              @ R
933    ldrne   r1, [r11]
934    addeq   r11, r11, #4
935    addne   r1, r0, r1
936    strne   r1, [r11], #4
937    b       crl_do_phase
938
939ctl_sample_mono:
940    ldr     r1, [r11]
941    add     r1, r0, r1
942    str     r1, [r11], #4
943    b       crl_do_phase
944
945ctl_sample_skip:
946    and     r1, r12, #1
947    add     r1, r1,  #1
948    add     r11,r11, r1, lsl #2
949
950crl_do_phase:
951    @ -- PHASE UPDATE --
952    add     r5, lr, #0x10
953    ldmia   r5, {r0-r3,r6-r7}
954    add     r0, r0, r6
955    add     r1, r1, r7
956    ldr     r6, [r5, #0x18]
957    ldr     r7, [r5, #0x1c]
958    add     r2, r2, r6
959    add     r3, r3, r7
960    stmia   r5, {r0-r3}
961
962    tst     r12, #8
963    bne     crl_loop_lfo
964    b       crl_loop
965
966
967crl_loop_end:
968    str     r8,  [lr, #0x44]     @ eg_timer
969    str     r12, [lr, #0x4c]     @ pack (for lfo_ampm)
970    str     r4,  [lr, #0x50]     @ was_update
971    str     r10, [lr, #0x54]     @ op1_out
972    ldmfd   sp!, {r4-r11,pc}
973
974.pool
975
976@ vim:filetype=armasm
977