;*********************************************************************
;* mod struct
;*********************************************************************	

	.def	modCurrentSongPosition			0
	.def	modCurrentRowPosition			1
	.def	modCurrentRowPositionStore		2 
	.def	modCurrentPatternStore			3
	.def	modSpeed				4
	.def	modBpm					5
	.def	modPatDelayTime				6
	.def	modTickCounter				7
	.def	modPlay					8
	.def	modModuleAdrLow				9
	.def	modModuleAdrHigh			10
	.def	modChannelAdr				11
	.def	modPatternCount				12
	.def	modSample0AdrLow			13
	.def	modSample0AdrHigh			14			
	.def	modSample1AdrLow			15
	.def	modSample1AdrHigh			16
	.def	modSample2AdrLow			17
	.def	modSample2AdrHigh			18
	.def	modSample3AdrLow			19
	.def	modSample3AdrHigh			20
	.def	modSample4AdrLow			21
	.def	modSample4AdrHigh			22
	.def	modSample5AdrLow			23
	.def	modSample5AdrHigh			24
	.def	modSample6AdrLow			25
	.def	modSample6AdrHigh			26
	.def	modSample7AdrLow			27
	.def	modSample7AdrHigh			28
	.def	modSample8AdrLow			29
	.def	modSample8AdrHigh			30
	.def	modSample9AdrLow			31
	.def	modSample9AdrHigh			32
	.def	modSample10AdrLow			33
	.def	modSample10AdrHigh			34
	.def	modSample11AdrLow			35
	.def	modSample11AdrHigh			36
	.def	modSample12AdrLow			37
	.def	modSample12AdrHigh			38
	.def	modSample13AdrLow			39
	.def	modSample13AdrHigh			40
	.def	modSample14AdrLow			41
	.def	modSample14AdrHigh			42
	.def	modSample15AdrLow			43
	.def	modSample15AdrHigh			44
	.def	modSample16AdrLow			45
	.def	modSample16AdrHigh			46
	.def	modSample17AdrLow			47
	.def	modSample17AdrHigh			48
	.def	modSample18AdrLow			49
	.def	modSample18AdrHigh			50
	.def	modSample19AdrLow			51
	.def	modSample19AdrHigh			52
	.def	modSample20AdrLow			53
	.def	modSample20AdrHigh			54
	.def	modSample21AdrLow			55
	.def	modSample21AdrHigh			56
	.def	modSample22AdrLow			57
	.def	modSample22AdrHigh			58
	.def	modSample23AdrLow			59
	.def	modSample23AdrHigh			60
	.def	modSample24AdrLow			61
	.def	modSample24AdrHigh			62
	.def	modSample25AdrLow			63
	.def	modSample25AdrHigh			64
	.def	modSample26AdrLow			65
	.def	modSample26AdrHigh			66
	.def	modSample27AdrLow			67
	.def	modSample27AdrHigh			68
	.def	modSample28AdrLow			69
	.def	modSample28AdrHigh			70
	.def	modSample29AdrLow			71
	.def	modSample29AdrHigh			72
	.def	modSample30AdrLow			73
	.def	modSample30AdrHigh			74
	                                                
							
modStruct	;yes its not a struct .. an object .. memory .. blabla
                                                        
	.space	75      
	.data	$1111,$2222,$3333,$4444
	;	 ????  ????		 <- two word overwrite ???
	
;******************************                         
;*                                                      
;* modInit                                              
;*                                                      
;* r0 = module address low                              
;* r1 = module address high                             
;* r4 = module channels adr                             
;*                                                      
	                                                
modInit	     
                                                
	push	r6                                      
	push	r2                                      
	push	r7      

	;stop irq to prevent irq in branches
	
	getssr	r7,0	;get ucore status reg 0 (irq 0 = irq enabled)
	cli		;stop irqs
	push	r7
	
	;
	                                                
	movei	r6,modStruct                            
	movei	r2,0				        
	moveih	r6,>modStruct                           
	                                                
	ssto	modCurrentSongPosition		;=0
	stwo	r6,r2
	
	movei	r3,$0
	ssto	modCurrentRowPosition		;=0
	stwo	r6,r3
	
	ssto	modCurrentRowPositionStore	;=0
	stwo	r6,r2
	
	ssto	modCurrentPatternStore		;=0
	stwo	r6,r2
	
	movei	r3,6			;6
	ssto	modSpeed			;=6
	stwo	r6,r3
	
	movei	r3,125
	ssto	modBpm				;=125
	stwo	r6,r3
	
	ssto	modPatDelayTime			;=0
	stwo	r6,r2
	
	ssto	modTickCounter			;=0
	stwo	r6,r2
	
	ssto	modPlay				;=0
	stwo	r6,r2
	
	ssto	modModuleAdrLow			;=0
	stwo	r6,r0
	
	ssto	modModuleAdrHigh		;=0
	stwo	r6,r1
	
	ssto	modChannelAdr
	stwo	r6,r4
	
	;change timer 2
	
	gpci	r7,2
	br	modUpdateBPM
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	;some calculation start here
	
	push	r0
	push	r1
	push	r6
	
	gpci	r7,2
	br	patternGetCount
	or	r5,r0,r0	;delay slot
	or	r6,r1,r1	;delay slot
	nop			;delay slot
	nop			;delay slot

	or	r2,r0,r0	;r2 = max pattern
	
	rqpop	
	rqpop
	rqpop
	pop	r6
	pop	r1	;mod adr high
	pop	r0	;mod adr low
	
	ssto	modPatternCount
	stwo	r6,r2
	
	;calculate sample start adr
			
	dexti	2
	muli	r2,0		;pattern count * 512 (1024 bytes)
	gmulhi	r3
	add	r0,r0,r2	;adr + pattern count
	addt	r1,r1,r3
	dexti	2
	addi	r0,$1e		;+542 (1084 bytes) = 0x21e
	addtqi	r1,r1,0
	
	;r1:r0 sample start address

	or	r2,r6,r6	;mod struct
	movei	r3,30		;0..30
	addi	r2,modSample0AdrLow
	
setSampleBaseLoop		

	subi	r3,1
	brts	setSampleBaseLoop	
	stinc	r2,r0	;delay slot	low address
	nop             ;delay slot
	stinc	r2,r1	;delay slot	high address
	nop             ;delay slot
	
	;--
	
	or	r3,r6,r6	;r3 = sample struct
	push	r6	;store sample struct
	addi	r3,modSample1AdrLow	;sample adr 1
	rqldi	r6,modModuleAdrLow
	rqldi	r6,modModuleAdrHigh
	movei	r4,0	;sample num
	ld	r5	
	ld	r6
	movei	r1,0	;sample offset counter low
	movei	r2,0	;sample offset counter high
	
	
sampleStartLoop	
	
	gpci	r7,2
	br	sampleGetLength
	nop             ;delay slot
	nop             ;delay slot
	nop             ;delay slot
	nop             ;delay slot	return r0 = sample length in BYTES!!
	
	lsri	r0,1		;/2
	nop
	
	add	r1,r1,r0	;offset counter + current length
	addtqi	r2,r2,0		;32 bit
	
	;dump
	
	rqldi	r3,0	;low
	rqldi	r3,1	;high
	nop
	ld	r0	;low
	ld	r7	;high
	
	;dump
	
	add	r0,r0,r1	;+offset counter
	addt	r7,r7,r2

	cmpeqi	r4,30
	brtc	sampleStartLoop
	stinc	r3,r0	;delay slot		store low
	addi	r4,1    ;delay slot
	stinc	r3,r7	;delay slot		store high             
	nop             ;delay slot
	
	rqpop
	nop
	nop
	pop	r6
	
	;restore irq enable
	
	rqpop
	nop
	nop
	pop	r7
	nop
	setssr	r7,0	;write back
	
	;
	
	rqpop	
	rqpop
	rqpop
	pop	r7
	pop	r2	
	pop	r6
	
	jmpi	r7,0	
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
;******************************
;*
;* modStart
;*
;*
	
modStart	

	push	r6
	push	r2
	
	movei	r6,modStruct
	movei	r2,1				
	moveih	r6,>modStruct
	
	;
	
	ssto	modPlay				;=1 start
	stwo	r6,r2
	
	;
	
	rqpop	
	rqpop
	jmpi	r7,0	
	pop	r2	;delay slot
	pop	r6	;delay slot
	nop		;delay slot
	nop		;delay slot
	
;******************************
;*
;* modStop
;*
;*
	
modStop	

	push	r0
	push	r2
	push	r4
	push	r5
	push	r6
	push	r7
	
	;stop irq to prevent irq in modStopChannel loop
	
	getssr	r7,0	;get ucore status reg 0 (irq 0 = irq enabled)
	cli		;stop irqs
	push	r7
	
	;
	
	dexti	>modStruct
	movei	r4,modStruct
	movei	r2,0				
	
	;
	
	ssto	modPlay				;=0 stop
	stwo	r4,r2
	
	;set all periods to zero (stop audio output)
	
	movei	r5,0	;channel number

modStopChannel	
	
	;
	
	rqldi	r4,modChannelAdr	;get channel adr
	nop
	nop
	ld	r0
	nop
	add	r0,r0,r5		;channel adr + channel
	addi	r5,1			;next channel
	rqldi	r0,0			;get channelptr = channel adr[channel]
	dexti	>channelSetPeriode
	movei	r2,channelSetPeriode
	ld	r0			;r0 = channelptr (channel struct)
	
	;set periode for channel (r0 (r4+r5)) to zero
	
	gpci	r7,2
	jmpi	r2,0		;setPeriode
	or	r6,r0,r0	;r6 = channel struct 	delay slot
	movei	r0,0		;r0 = periode = 0	delay slot
	nop			;delay slot
	nop			;delay slot
		
	;

	cmploi	r5,4			;0..3 are mode channels
	brts	modStopChannel
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	;
	
	;restore irq enable
	
	rqpop
	nop
	nop
	pop	r7
	nop
	setssr	r7,0	;write back
	
	;

	rqpop	
	rqpop
	rqpop
	poparqp	r7
	poparqp	r6
	poparqp	r5
	pop	r4
	pop	r2
	pop	r0
	
	;
	
	jmpi	r7,0	
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
;******************************
;*
;* modTick 
;*
;*	

modTick

	push	r0
	push	r1
	push	r2
	push	r3
	push	r4
	push	r5
	push	r6
	push	r7
	
	;prolog
	
	dexti	>modStruct
	movei	r6,modStruct
	nop
	
	;dump
	
	;test mod playing enable
		
	rqldi	r6,modPlay
	nop
	nop
	ld	r0
	nop
	cmpeqi	r0,0
	brts	modTickNothingToDo	;modPlay = 0 so dont play
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	
	
	; 
	
	rqldi	r6,modTickCounter
	rqldi	r6,modSpeed
	nop
	ld	r0	;tick counter
	ld	r1	;mod speed
	
	addi	r0,1	;tick counter ++
	ssto	modTickCounter
	stwo	r6,r0	;tick counter store
	
	cmple	r1,r0	;m_speed <= m_tickCounter
	brtc	modTickNoRowUpdate
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	movei	r0,0	;clear tick counter
	ssto	modTickCounter
	stwo	r6,r0	
	
	rqldi	r6,modPatDelayTime
	nop
	nop
	ld	r0	;pattern delay
	nop
	subqi	r1,r0,1	;r1 = pattern delay - 1
	
	gpci	r7,3
	cmpeqi	r0,0			;if pattern delay = 0
	brts	modGetNote		;mod get note if pattern delay == 0
	movets	r0,r0,r1		;pattern delay = (pattern delay == 0) ? 0 : pattern delay  - 1		delay slot
	ssto	modPatDelayTime		;delay slot
	stwo	r6,r0			;delay slot
	nop				;delay slot
	
	;
	br	modTickNothingToDo
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	
	;else
	
modTickNoRowUpdate  

	gpci	r7,2
	br	modCheckEffects		;check effects
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
          

modTickNothingToDo
	    
	;dump 
	    
	;epilog 
	    
	rqpop
	rqpop
	rqpop
	poparqp	r7
	poparqp	r6
	poparqp	r5
	pop	r4
	pop	r3
	pop	r2
	
	rqpop
	rqpop
	jmpi	r7,0
	pop	r1	;delay slot
	pop	r0	;delay slot
	nop		;delay slot
	nop		;delay slot
	
;******************************
;*
;* modGetNote 
;*
;* r6 = mode struct	
;*
	
modGetNote

	push	r7
			
	rqldi	r6,modCurrentRowPosition
	rqldi	r6,modCurrentSongPosition
	nop
	ld	r1	;current row position
	ld	r4	;current song position (used by patternGetPatternNumberAtSongPosition)
	
	; ;
	
	ssto	modCurrentRowPositionStore
	stwo	r6,r1	;current row position store = current row position	// m_currentRowPositionStore =(UInt16) m_currentRowPosition;  // can be change by channel
	
	;get pattern at position
				
	push	r6		;store mode struct
	rqldi	r6,modModuleAdrLow
	rqldi	r6,modModuleAdrHigh
	nop
	ld	r5	;mod adr low
	ld	r6	;mode adr high
	
	gpci	r7,2
	br	patternGetPatternNumberAtSongPosition 	;m_songPositions[m_currentSongPosition];    // can be change by channel
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot		;return r0 = pattern number
	
	rqpop
	nop
	nop
	pop	r6		;recover mode struct
	
	ssto	modCurrentPatternStore		; m_currentPatternStore =
	stwo	r6,r0
	
	; ;------------------------
	
	movei	r5,0		;channel number
	
	;channel loop 0..3
	
getNoteLoopForEachChannels

	
	push	r6		;store mod struct
	push	r5		;store channel
	
	;->
	
	;get channel data and decode
	
	push	r6		;store mod struct
	push	r5             ;store channel
	
	or	r4,r5,r5	;r4 = channel num
	rqldi	r6,modModuleAdrLow
	rqldi	r6,modCurrentRowPositionStore
	rqldi	r6,modCurrentPatternStore
	ld	r5	;mod adr low
	ld	r3	;row position stored
	ld	r2	;current pattern stored
	
	rqldi	r6,modModuleAdrHigh
	gpci	r7,2
	br	patternGetCellValue
	ld	r6	;mod adr high delay slot			* return
	nop		;delay slot                                     * r2 = sample num
	nop		;delay slot                                     * r3 = note
	nop		;delay slot                                     * r4 = cmd
	      
	;restore  mode struct, channel counter
	   
	rqpop
	rqpop	
	nop
	pop	r5		;channel
	pop	r6		;mod struct
	
	nop
	rqldi	r6,modChannelAdr	;get channel adr
	nop
	nop
	ld	r0
	nop
	add	r0,r0,r5		;channel adr + channel
	nop
	rqldi	r0,0			;get channelptr = channel adr[channel]
	nop
	nop
	ld	r0			;r0 = channelptr (dont trash!)
		
	ssto	channelStCmd
	stwo	r0,r4		;currentChannel.n_cmd = cmd; 
	ssto	channelStNote
	stwo	r0,r3		;currentChannel.n_note = note;               // savenote
	
	;
	
	push	r0		;store current channel
	
	;
	
	;** if (cmd == 0 && note == 0) // no cmd and no note  (cmd or note == 0)
	
	or	r1,r3,r4
	nop
	cmpeqi	r1,0	
	brtc	cmdNoteNotZero
	nop		;delay slot 
	nop		;delay slot                                    
	nop		;delay slot                                    
	nop		;delay slot                                    
	
	or	r6,r0,r0
	nop
	rqldi	r6,channelStPeriode
	gpci	r7,2			; currentChannel.setHWPeriode(currentChannel.n_periode); // reset periode, no effect check
	br	channelSetPeriode
	ld	r0		;periode	delay slot          
	nop			;delay slot 		                          
	nop			;delay slot                                    
	nop			;delay slot   
	
	;dump
	
	br	cmdNoteZero
	nop		;delay slot 
	nop		;delay slot                                    
	nop		;delay slot                                    
	nop		;delay slot   
	  
cmdNoteNotZero	  
            
	;** else
	
	;r0 = current channel adr
	;r2 = sample num
	;r3 = note
	;r4 = cmd
	
	cmpeqi	r2,0				
	brts	sampleNumberZero	;if (sampleNumber != 0) // sample number is not zero 
	nop		;delay slot 
	nop		;delay slot                                    
	nop		;delay slot                                    
	nop		;delay slot 
		
	;store
	
	push	r6	;r6 = mode struct
	push	r0	;r0 = current channel adr
	push	r2	;r2 = sample number
	push	r3	;r3 = note
	push	r4	;r4 = cmd
	
	;
	
	or	r4,r2,r2			;r4 = sample num
	
	ssto	channelStSampleNumber
	stwo	r0,r4			;* currentChannel.n_sampleNumber = sampleNumber; // note start at 1
	
	subi	r4,1				;sampleNumber - 1 (because internal its start at 0) 
						; MODSample currentSample = m_samples[sampleNumber - 1];
	
	rqldi	r6,modModuleAdrHigh
	rqldi	r6,modModuleAdrLow
	or	r3,r0,r0	;r3 = current channel adr (save)
	ld	r6		;mod adr low
	ld	r5		;mod adr high
	
	movei	r0,0		;
	ssto	channelStStart
	stwo	r3,r0			;* currentChannel.n_start          = 0
	
	gpci	r7,2
	br	sampleGetLength
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = length
	nop		;delay slot             ;*
	
	ssto	channelStLength
	stwo	r3,r0			;* currentChannel.n_length         = currentSample.length;
	ssto	channelStRealLength
	stwo	r3,r0			;* currentChannel.n_realLength     = currentSample.length;
	
	gpci	r7,2
	br	sampleGetFineTune
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = fine tune
	nop		;delay slot             ;*
	
	ssto	channelStFineTune
	stwo	r3,r0			;* currentChannel.n_fineTune       = currentSample.fineTune;
	
	gpci	r7,2
	br	sampleGetVolume
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = volume
	nop		;delay slot             ;*
	
	ssto	channelStVolume
	stwo	r3,r0			;* currentChannel.n_volume         = currentSample.volume;
	
	gpci	r7,2
	br	sampleGetRepeatStart
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = repeat start
	nop		;delay slot             ;*
	
	ssto	channelStRepeatStart
	stwo	r3,r0			;* currentChannel.n_repeatStart      = currentSample.repeatStart;  
	
	gpci	r7,2
	br	sampleGetRepeatLength
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = repeat length
	nop		;delay slot             ;*
	
	ssto	channelStRepeatLength
	stwo	r3,r0			;* currentChannel.n_repeatLength     = currentSample.repeatLength;
	
	gpci	r7,2
	br	sampleGetDataAddress
	nop		;delay slot 		;* return
	nop		;delay slot             ;*
	nop		;delay slot             ;* r0 = sample low address
	nop		;delay slot             ;* r1 = sample high address
	
	ssto	channelSampleAdrLow
	stwo	r3,r0			; currentChannel.data = currentSample.data;
	ssto	channelSampleAdrHigh
	stwo	r3,r1			
	
	;restore
	
	rqpop
	rqpop
	rqpop
	pop	r4
	pop	r3
	pop	r2
	rqpop
	rqpop
	nop
	pop	r0
	pop	r6
	
	
sampleNumberZero	

	;r6 = mode struct
	;r0 = current channel adr
	;r2 = sample number
        ;r3 = note
	;r4 = cmd     

	;if (note == 0) // no note so only check effects
	
	cmpeqi	r3,0		;
	brtc	noteNotZero			
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	gpci	r7,2
	br	modCheckMoreEffects	;pt_CheckMoreEffects(currentChannel);	r0 = current channel adr
	nop		;delay slot						r6 = mod struct
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
			    
	br	cmdNoteZero
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
noteNotZero
	
	;r6 = mode struct
	;r0 = current channel adr
	;r2 = sample number
        ;r3 = note
	;r4 = cmd   
	
        ; else // there is anote 
	
	dexti	1
	lsrqi	r1,r4,0	;get effect	>> 8
	
	nop
	cmpeqi	r1,3		;  if (effect(cmd) == 3
	brts	Effect3
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
			
	cmpeqi	r1,5		;  			|| effect(cmd) == 5)
	brtc	notEffect35
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot

Effect3	
	; ; pt_ChkTonePorta(currentChannel);    //TonePortamento [+ VolSlide]

	dexti	>cmdNoteZero
	movei	r7,cmdNoteZero			;stop if after this
	br	checkTonePorta
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	;
	
notEffect35
	
	;r1 = get effect	>> 8
	
	nop
	cmpeqi	r1,9		; else if (effect(cmd) == 9) // this effect will change sample offset
	brtc	notEffect9
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	; pt_CheckMoreEffects(currentChannel);
		
	;dump	
		
	gpci	r7,2
	br	modCheckMoreEffects		;r0 = current channel adr
	nop		;delay slot              r6 = mod struct
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
       ; pt_SetPeriod(currentChannel);
       
	gpci	r7,2
	br	modSetPeriode			;r0 = current channel adr
	nop		;delay slot              r6 = mod struct
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	br	cmdNoteZero
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	
notEffect9	
			
                        ; else if (effect(cmd) == 9) // this effect will change sample offset
                        ; {
                            ; pt_CheckMoreEffects(currentChannel);
                            ; pt_SetPeriod(currentChannel);
                        ; }
                        ; else if (effect_ext(cmd) == 0xe5) // this effect change fine tune 
                        ; {
                            ; pt_DoSetFineTune(currentChannel);
                            ; pt_SetPeriod(currentChannel);
                        ; }
                    

	gpci	r7,2
	br	modSetPeriode			;r0 = current channel adr
	nop		;delay slot              r6 = mod struct
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	    ; else // normal processing
                        ; {                           
                            ; pt_SetPeriod(currentChannel);
                        ; }
                    ; }     

	     
cmdNoteZero

	;** end if
	
	rqpop
	nop
	nop
	pop	r6	;restore current channel adr
	nop
			
	rqldi	r6,channelStVolume	;currentChannel.n_volume
	gpci	r7,2
	br	channelSetVolume
	ld	r0	;delay slot	 currentChannel.setHWVolume(currentChannel.n_volume);
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	;<-
	
	rqpop
	rqpop	
	nop
	pop	r5
	pop	r6
	
	addi	r5,1
	nop
	cmploi	r5,4
	brts	getNoteLoopForEachChannels
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	
	; ;------------------------

	;next row (next pattern if needed)	
	
	;get song length
	
	push	r6		;store mod struct
	rqldi	r6,modModuleAdrLow
	rqldi	r6,modModuleAdrHigh
	nop
	ld	r5	;mod adr low
	ld	r6	;mode adr high
	gpci	r7,2
	br	patternGetSongLength
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot		;return r0 = song length
	
	rqpop
	or	r3,r0,r0	;r3 = song length
	nop
	pop	r6		;recover mode struct
	nop
	
	;next row (next pattern if overflow)
	
	rqldi	r6,modCurrentRowPosition
	rqldi	r6,modCurrentSongPosition
	nop
	ld	r0	;current row position
	ld	r1	;current song position
	
	addi	r0,1		;current row position++
	movei	r2,0	
	cmploi	r0,64		;t = 1 if row position < 64 else t = 0
	tnt			;t = 0 if row position < 64 else t = 1
	movets	r0,r2,r0	;current row position = (t==1)?0:current row position
	addtqi	r1,r1,0		;current song position += t; (NOTE: T OUT!)
	
	
	;check current song position (r1) agains max song length (r3)
	
	nop
	cmplo	r1,r3		;current song position < song length
	movets	r1,r1,r2	;current song position = (t==1)?current song position:0
	
	;store back
	
	ssto	modCurrentRowPosition
	stwo	r6,r0
	ssto	modCurrentSongPosition
	stwo	r6,r1
	
	
	rqpop
	nop
	nop
	pop	r7
	nop
	
	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot

;******************************
;*
;* modCheckMoreEffects 
;*
;* r0 = current channel struct
;* r6 = mode struct
;*	

modCheckMoreEffects

	push	r0
	push	r1
	push	r2
	push	r6
	push	r7
		
	rqldi	r0,channelStCmd
	nop
	nop
	ld	r1	;effect
	movei	r2,$f	;
	lsri	r1,8	;upper 4 bit are effect
	nop
	and	r1,r1,r2	;clear upper 4bit (only for safety)
	nop
	dexti	>moreEffectsList
	movei	r2,moreEffectsList	;jump list
	nop
	add	r2,r2,r1	;add cmd
	nop
	rqldi	r2,0		;request pointer
	nop
	nop
	ld	r2		;get pointer
	
	dexti	>moreEffectFinish
	movei	r7,moreEffectFinish
	jmpi	r2,0		;jump		r0 = channel struct, r6 = mod struct
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
moreEffectDefault

	 ; currentChannel.setHWPeriode(currentChannel.n_periode);          // periode   
	 
	 or	r6,r0,r0		;r6 = channel struct
	 dexti	>channelSetPeriode
	 movei	r1,channelSetPeriode
	 
	 rqldi	r0,channelStPeriode
	 gpci	r7,2
	 jmpi	r1,0	
	 ld	r0	;sample periode	delays lot
	 nop		;delay slot
	 nop		;delay slot
	 nop		;delay slot

moreEffectFinish
	
	;
	
	rqpop
	rqpop
	rqpop
	pop	r7
	pop	r6
	pop	r2
	
	rqpop
	rqpop
	jmpi	r7,0
	pop	r1	;delay slot
	pop	r0	;delay slot
	nop		;delay slot
	nop		;delay slot	
	
moreEffectsList

		word	moreEffectDefault	;0
		word	moreEffectDefault	;1
		word	moreEffectDefault	;2
		word	moreEffectDefault	;3
		word	moreEffectDefault	;4
		word	moreEffectDefault	;5
		word	moreEffectDefault	;6
		word	moreEffectDefault	;7
		word	moreEffectDefault	;8
		word	effectSampleOffset	;* 9
		word	moreEffectDefault	;a
		word	effectPositionJump	;* b
		word	effectVolumeChange	;* c
		word	effectPatternBreak	;* d
		word	effectECommands		;* e
		word	effectSetSpeed		;* f
	
;******************************
;*
;* modCheckEffects 
;* note: this effects are tick based
;*
;* r6 = mode struct
;*	

modCheckEffects

	push	r0
	push	r1
	push	r2
	push	r5
	push	r7
	
	;dead
	;-----------------------------------------------
	
	;
	
	movei	r5,0	;channel number
	nop

modCheckEffectsChannelLoop	
	
	push	r5	;store channel number
	
	; ;->
	
	rqldi	r6,modChannelAdr	;get channel adr
	nop
	nop
	ld	r0
	nop
	add	r0,r0,r5		;channel adr + channel
	nop
	rqldi	r0,0			;get channelptr = channel adr[channel]
	nop
	nop
	ld	r0			;r0 = channelptr (channel struct)
	
	;get cmd from channel
	
	nop
	rqldi	r0,channelStCmd
	nop
	nop
	ld	r1			;current_channel.cmd
	nop
	
	cmpeqi	r1,0				;cmd == 0 so ony update volume
	brts	modCheckEffectsChannelZeroCmd
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	; ;cmd != 0 so check effects
	
	movei	r2,$f
	lsri	r1,8		;get effect num
	nop
	and	r1,r1,r2	;clear for safety (0..f)
	
	
	dexti	>effectsList
	movei	r2,effectsList
	nop	
	add	r2,r2,r1	;goto effect
	nop
	rqldi	r2,0
	nop
	nop
	ld	r2		;address
	
	gpci	r7,2
	jmpi	r2,0		;jump	(r0 = channel struct adr, r6 module address)
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
modCheckEffectsChannelZeroCmd

	; ;set volume
	
	push	r6
	push	r0
	
	dexti	>channelSetVolume
	movei	r2,channelSetVolume
	gpci	r7,2
	jmpi	r2,0
	rqldi	r0,channelStVolume	;delay slot	currentChannel.n_volume						
	or	r6,r0,r0		;channel struct delay slot
	nop				;delay slot
	ld	r0			;delay slot	 currentChannel.setHWVolume(currentChannel.n_volume);		
	nop
	
	rqpop
	rqpop
	nop
	pop	r0
	pop	r6
	
	;<-
	
	rqpop
	nop
	nop
	pop	r5	;restore channel number
	nop
	
	;dump
	
	cmpeqi	r5,3	;0..3
	brtc	modCheckEffectsChannelLoop
	addi	r5,1	;next channel number	delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	
	rqpop
	rqpop
	nop
	pop	r7
	pop	r5
	
	rqpop
	rqpop
	rqpop
	pop	r2
	pop	r1
	pop	r0
	
	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
;-------------------	
	
; switch (effect(currentChannel.n_cmd))
                    ; {
                        ; case 0x0: pt_Arpeggio(currentChannel); break;
                        ; case 0x1: pt_PortaUp(currentChannel); break;
                        ; case 0x2: pt_PortaDown(currentChannel); break;
                        ; case 0x3: pt_TonePortamento(currentChannel); break;
                        ; case 0x4: pt_Vibrato(currentChannel); break;
                        ; case 0x5: pt_TonePlusVolSlide(currentChannel); break;
                        ; case 0x6: pt_VibratoPlusVolSlide(currentChannel); break;
                        ;--------- case 0xE: pt_ECommands(currentChannel); break;
                        ; default:

                            ; currentChannel.setHWPeriode(currentChannel.n_periode);

                          ;   switch (effect(currentChannel.n_cmd))
                          ;  {
                          ;      case 0x7: pt_Tremolo(currentChannel); return; /* tremelo will end here, because volume is direct modified*/
                         ;       case 0xA: pt_VolumeSlide(currentChannel); break;
                          ;  }

                            ; break;
                    ; }	

;*
;* r0 = current channel struct
;* r6 = mode struct
;*

effectDefault	

	push	r1
	push	r2
	push	r7
	
	; ;currentChannel.setHWPeriode(currentChannel.n_periode);
	
	; ;r0 = value
	; ;r6 = channel struct
	
	push	r0
	push	r6
	
	rqldi	r0,channelStPeriode
	or	r6,r0,r0		;r6 = channel struct
	nop
	ld	r0			;r0 = value
	
	;

	dexti	>channelSetPeriode
	movei	r2,channelSetPeriode
	gpci	r7,2
	jmpi	r2,0
	nop	;delay slot	 
	nop	;delay slot
	nop	;delay slot
	nop	;delay slot
	
	rqpop
	rqpop
	nop
	pop	r6
	pop	r0
	nop
	
	; ;
			    
	rqldi	r0,channelStCmd
	nop
	nop
	ld	r1			;current_channel.cmd	
	movei	r2,$f
	lsri	r1,8
	nop
	and	r1,r1,r2
	nop
	
	dexti	>effectDefaultProlog
	movei	r7,effectDefaultProlog
	
	cmpeqi	r1,$7	;tremolo?			case 0x7: pt_Tremolo(currentChannel); return; /* tremelo will end here, because volume is direct modified*/
	brts	effectTremolo
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
	dexti	>effectDefaultProlog
	movei	r7,effectDefaultProlog
	
	cmpeqi	r1,$a	;Volume slide?			; case 0xA: pt_VolumeSlide(currentChannel); break;
	brts	effectVolumeSlide
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
effectDefaultProlog
	
	;

	rqpop
	rqpop
	rqpop
	pop	r7	
	pop	r2	
	pop	r1	
	
	
	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	
effectsList

		word	effectArpeggio			;0
		word	effectPortaUp			;1
		word	effectPortaDown			;2
		word	effectTonePortamento		;3
		word	effectVibrato			;4
		word	effectTonePlusVolSlide		;5
		word	effectVibratoPlusVolSlide	;6
		word	effectDefault	;7
		word	effectDefault	;8
		word	effectDefault	;9
		word	effectDefault	;a
		word	effectDefault	;b
		word	effectDefault	;c
		word	effectDefault	;d
		word	effectECommands			;e
		word	effectDefault	;f	
	
	
	
;******************************
;*
;* modSetPeriode 
;*
;* r0 = current channel struct
;* r6 = mode struct
;*	

modSetPeriode

	push	r5
	push	r6
	push	r7
	
	;
	
	push	r0
	push	r6
	
	;
	
	or	r5,r0,r0	;r5 = channel struct
	nop
	rqldi	r5,channelStNote
	rqldi	r5,channelStFineTune
	nop
	ld	r0
	ld	r1
	
	 ; currentChannel.n_periode = searchPeriode(currentChannel.n_note, currentChannel.n_fineTune);
	 
	gpci	r7,2
	br	periodeSearch
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot		;return: 	r0 = periode
	nop		;delay slot		;		r1 = fine tune (0..7 -8..-1)
	
	ssto	channelStPeriode
	stwo	r5,r0
	
	;dump

	;if (effect_ext(currentChannel.n_cmd) != 0xd) // is not note delay  
	 
	rqldi	r5,channelStCmd
	nop
	nop
	ld	r1	;get cmd
	nop
	lsri	r1,4	;0CXY -> 00CX
	nop
	cmpeqi	r1,$ed	;note delay no periode setup
	brts	noteDelaySkipPeriodeSetup
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
				          
                ; if (((currentChannel.n_wavecontrol >> 2) & 1) != 0) // clear vibrato pos if enabled
                ; {
                    ; currentChannel.n_vibratopos = 0;
                ; }

                ; if (((currentChannel.n_wavecontrol >> 6) & 1) != 0) // clear tremelo pos if enabled
                ; {
                    ; currentChannel.n_tremolopos = 0;
                ; }
            
	 ; // now real setup ... (check repeat setup) 

	  ; // search periode
	 
	gpci	r7,2 
	br	modUpdateChannel
	or	r6,r5,r5	;channel struct		delay slot
	nop			;			delay slot
	nop			;			delay slot
	nop			;			delay slot
	
noteDelaySkipPeriodeSetup	        	
        ; }
	
	rqpop
	rqpop
	nop
	pop	r6
	pop	r0
	
	gpci	r7,2
	br	modCheckMoreEffects		; pt_CheckMoreEffects(currentChannel);    // check effects	
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot

	;
	
	rqpop
	rqpop
	rqpop
	pop	r7
	pop	r6
	pop	r5
	
	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot	
	
;******************************
;*
;* modUpdateBPM
;*
;* r6 = mode struct
;*
;* NOTE! Not IRQ save should only called in IRSR
;*	

modUpdateBPM	

	push	r0
	push	r1
	push	r2
	
	
	movei	r0,$6d
	movei	r1,$bb
	rqldi	r6,modBpm
	moveih	r0,$e4
	moveih	r1,$1f		;532407405 = (106481481 * 5) = 0x1fbbe46d
	ld	r2		;get bpm
	
	udivinit	31	;32 bit division (-1)
	add	r2,r2,r2	;bpm * 2
	udivsdd		r0	;
	udivsddh	r1	;divident
	udivsdv		r2	;divider
	
	movei	r2,7	;(7+1)*4 = 32
	nop
	
bpmToILoop	
	subi	r2,1
	brts	bpmToILoop
	udivstep	;delay slot	
	udivstep        ;delay slot
	udivstep        ;delay slot
	udivstep        ;delay slot
	
	dexti	>UcTimer2LowValue
	movei	r2,UcTimer2LowValue
	
	udivgq	r0      ;low timer result	
	udivgqh	r1      ;high timer result
	
	stinc	r2,r0		;low
	movei	r0,5		;start with auto reloead
	stinc	r2,r1		;high		(timer will reload value after next hit)
	nop
	stinc	r2,r0		;write config	
	
	rqpop
	rqpop
	rqpop
	pop	r2
	pop	r1
	pop	r0

	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot	
	
	
;******************************
;*
;* modUpdateChannel
;*
;* r6 = channel struct
;*
;* NOTE! Not IRQ save should only called in IRSR
;*	
	
modUpdateChannel

	push	r0
	push	r7
	
	; currentChannel.setHWSampleStart(currentChannel.n_start);        // start position
	 
	dexti	>channelSetSampleStart
	movei	r0,channelSetSampleStart
	gpci	r7,2
	jmpi	r0,0	
	rqldi	r6,channelStStart	;delay slot	
	nop				;delay slot
	nop				;delay slot	
	ld	r0			;sample start	delays lot
	
	 
	 ; currentChannel.setHWSampleLength(currentChannel.n_length);      // length
	 
	dexti	>channelSetSampleLength
	movei	r0,channelSetSampleLength
	gpci	r7,2
	jmpi	r0,0	
	rqldi	r6,channelStLength	;delay slot
	nop				;delay slot
	nop				;delay slot
	ld	r0			;sample length	delays lot

	 
	 ; currentChannel.setHWPeriode(currentChannel.n_periode);          // periode   
	 
	dexti	>channelSetPeriode
	movei	r0,channelSetPeriode
	gpci	r7,2
	jmpi	r0,0
	rqldi	r6,channelStPeriode	;delay slot	 
	nop				;delay slot
	nop				;delay slot
	ld	r0			;sample periode	delays lot

	 ; currentChannel.setRepeatStart(currentChannel.n_repeatStart);    // repeat start
	 
	 
	dexti	>channelSetRepeatStart
	movei	r0,channelSetRepeatStart
	gpci	r7,2
	jmpi	r0,0		
	rqldi	r6,channelStRepeatStart	;delay slot
	nop				;delay slot
	nop				;delay slot
	ld	r0			;sample repeat start	delays lot
	 
	 ; currentChannel.setRepeatLength(currentChannel.n_repeatLength);  // repeat length
	 
	dexti	>channelSetRepeatLength
	movei	r0,channelSetRepeatLength
	gpci	r7,2
	jmpi	r0,0	
	rqldi	r6,channelStRepeatLength	;delay slot		
	nop					;delay slot
	nop					;delay slot 
	ld	r0	;sample repeat length	delays slot	

	rqpop
	rqpop
	nop
	pop	r7	
	pop	r0	
	
	jmpi	r7,0
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot
	nop		;delay slot	
	