; --------------------------------------------------------------------------
; ---------------------------- I2S Registers --------------------------------
; --------------------------------------------------------------------------
CS_A     		*	0

STBY			*	1 :SHL: 25
SYNC			*	1 :SHL: 24
DMAEN			*	1 :SHL: 9
TXCLR			*	1 :SHL: 3
TXON			*	1 :SHL: 2 ;4
EN			*	1

; ----

FIFO     		*	4
Mode_A   		*	8
RXC_A    		*	&C
TXC_A    		*	&10
DREQ_A   		*	&14
Inten_A  		*	&18
Intstc_A 		*	&1C
GRAY    		*	&20

BIT24			*	&1000000
BIT19			*	&80000
; ---------------------------------------------------------------------------

; ---

; --------------------------------------------------------------------------
; ------------------------------ GPIO SWIs ---------------------------------
; --------------------------------------------------------------------------
GPIO_WriteMode		*	0x58F90
GPIO_WriteOE		*	0x58F83
GPIO_WriteData		*	0x58F81
; --------------------------------------------------------------------------

HALDeviceBus_Ser        *       4 :SHL: 28
HALDeviceSerBus_IIS     *       2 :SHL: 24 ; Inter IC sound
HALDeviceSerBus_IIC     *       1 :SHL: 24 ; Inter IC
HALDeviceType_Audio     *       2 :SHL: 8
                        ^       1
HALDeviceAudio_AudC     #       1      ; 16-bit sound input/output controller
HALDeviceAudio_Mixer    #       1      ; Sound I/O mixer

; --------------------------------------------------------------------------

DeviceNoIRQ		 *	55	   ; passed to OS_ClaimDeviceVector
LOG_ChanNo 		 *	2	   ; use DMA channel 2?
MixerChCount    	 * 	1
HALDevice_Audio_Size_1	 *	128	   ; bytes
HALDevice_Mixer_Size_0_1 *	88         ; bytes

; --------------------------------------------------------------------------

        GET     ListOpts
        GET     Macros
        GET     System
        GET     ModHand


; --------------------------------------------------------------------------


; ------------------------------- Workspace ---------------------------------

                     ^ 0, wp
AudioDevice           	# HALDevice_Audio_Size_1   ; 128 bytes
Space		      	# 16
MixerDevice		# HALDevice_Mixer_Size_0_1 ; 88 bytes
I2S_Log_Base		# 4			   ; base memory of I2S
I2S_PI_Phy_Base		# 4			   ; pi=20203000 pi3=3F203000
MixSettings             # 8
WSSize                	* :INDEX: @
; ------------------------------- Workspace ---------------------------------

        ; Assembler modules are conventionally, but not necessarily,
        ; position-independent code. Area name |!| is guaranteed to appear
        ; first in link order, whatever your other areas are named.
        AREA    |!|, CODE, READONLY, PIC

        ENTRY

        DCD     0 ; Start
        DCD     Init - |!|
        DCD     Final - |!|
        DCD     0; Service call handler
        DCD     Title - |!|
        DCD     Help - |!|
        DCD     0 ; Keyword table
        DCD     0 ; SWI chunk
        DCD     0 ; SWI handler
        DCD     0 ; SWI table
        DCD     0 ; SWI decoder
        DCD     0 ; Messages
        DCD     Flags - |!|




Title   =       "PI_I2S", 0
Help    =       "PI I2S audio 0.10 (01 May 2019)", 0

        ALIGN
Flags   &       ModuleFlag_32bit


; ---------------------------------------------------------------------------
        ALIGN
AudioDevice_Desc
        DCB     "PI I2S audio", 0
        ALIGN
MixerDevice_Desc
        DCB     "PI I2Saudio mixer", 0
        ALIGN
; ---------------------------------------------------------------------------

; ---


I2S_Phy_Base	DCD	0x20203000

PI3_CPU_ID	DCD	0x410FD034

        ALIGN
; ---------------------------------------------------------------------------
; --------------------- HALDeviceAudio_AudC Template ------------------------
; ---------------------------------------------------------------------------
AudioDeviceTemplate
	DCW	HALDeviceType_Audio + HALDeviceAudio_AudC	; type
	DCW	0						; id
        DCD     HALDeviceBus_Ser + HALDeviceSerBus_IIS
        DCD     &10000                  			; ver - 1.0
        DCD     AudioDevice_Desc
        DCD     0                       			; Add - N/A
        %       12                      			; Reserved
        DCD     AudioDevice_Activate
        DCD     AudioDevice_Deactivate
        DCD     AudioDevice_Reset
        DCD     AudioDevice_Sleep
        DCD     -1; DeviceNoIRQ					; 55 not used
        DCD     0 ; TestIRQ					; no testIRQ
        DCD     0 ; ClearIRQ
        %       4						; reserved
; ----- Device Discriptor ends here
        DCD     0 ; MixerDeviceTemplate                       	; Mixer
        DCD     1                      				; Outputs
        DCD     0                       			; Inputs
; ----- Device API 0 ends here (HALDevice_Audio_Size)
        DCD     0                       			; DMA R0 flag
	DCD     LOG_ChanNo            				; DMA R1
        DCD     0                       			; cycle speed
        DCD     2                       			; TX byte
        DCD     0      						; write add
; ----- dmaparams ends here
        DCD     AudioDevice_PreEnable
        DCD     AudioDevice_PostEnable
        DCD     AudioDevice_PreDisable
        DCD     AudioDevice_PostDisable
        DCD     AudioDevice_IRQHandle
	DCD	(AudioRateTable_End-AudioRateTable)/8
	DCD	AudioRateTable
        DCD     AudioDevice_SetRate

; ------ API 1 ends here

; ---------------------------------------------------------------------------

; ---
        ALIGN
; ---------------------------------------------------------------------------
; --------------------- HALDeviceAudio_Mixer Template -----------------------
; ---------------------------------------------------------------------------
MixerDeviceTemplate
        DCW     HALDeviceType_Audio + HALDeviceAudio_Mixer	; type
	DCW	3						; id
  	DCD     HALDeviceBus_Ser + HALDeviceSerBus_IIC

        DCD     &0000                   			; API ver 0.0
        DCD     MixerDevice_Desc
        DCD     0                       			; Add - N/A
        %       12                      			; Reserved
        DCD     MixerDevice_Activate
        DCD     MixerDevice_Deactivate
        DCD     MixerDevice_Reset
        DCD     MixerDevice_Sleep
        DCD     -1                      			; Int N/A
        DCD     0
        %       8
; ----- Device Discriptor ends here
        DCD     AudioDeviceTemplate                       	; AudC
        DCD     MixerChCount            			; Chans
        DCD     MixerDevice_GetFeatures
        DCD     MixerDevice_SetMix
        DCD     MixerDevice_GetMix
 ;      DCD     MixerDevice_GetMixLimits (not used)


; ---------------------------------------------------------------------------
; --------------- R1 = WSpace address of device Audio / Mixer ---------------
; --------------- R0 = Address of routine -----------------------------------
; ---------------------------------------------------------------------------


Insert_Offsets_Into_WS
        Push    "R0-R12,lr"


	ADR	R1,AudioDevice+12
	ADR	R0,AudioDevice_Desc
	STR	R0,[R1]

	ADR	R1,AudioDevice+32
	ADR	R0,AudioDevice_Activate
	STR	R0,[R1]

	ADR	R1,AudioDevice+36
	ADR	R0,AudioDevice_Deactivate
	STR	R0,[R1]

	ADR	R1,AudioDevice+40
	ADR	R0,AudioDevice_Reset
	STR	R0,[R1]

	ADR	R1,AudioDevice+44
	ADR	R0,AudioDevice_Sleep
	STR	R0,[R1]

	ADR	R1,AudioDevice+52
	ADR	R0,TestIRQ
	STR	R0,[R1]

	ADR	R1,AudioDevice+56
	ADR	R0,ClearIRQ
	STR	R0,[R1]


	ADR	R1,AudioDevice+64
	ADR	R0,MixerDevice
	STR	R0,[R1]

; -------------- Fifo Address -------------
	ADR	R0,I2S_PI_Phy_Base
	LDR	R0,[R0]			; get value
	ADD	R0,R0,#FIFO		; + fifo value
	ADR 	R1,AudioDevice+92       ; store in audio template in WS
	STR 	R0,[R1]
; -------------- Fifo Address -------------

	ADR	R1,AudioDevice+96
	ADR	R0,AudioDevice_PreEnable
	STR	R0,[R1]

	ADR	R1,AudioDevice+100
	ADR	R0,AudioDevice_PostEnable
	STR	R0,[R1]

	ADR	R1,AudioDevice+104
	ADR	R0,AudioDevice_PreDisable
	STR	R0,[R1]

	ADR	R1,AudioDevice+108
	ADR	R0,AudioDevice_PostDisable
	STR	R0,[R1]

	ADR	R1,AudioDevice+112
	ADR	R0,AudioDevice_IRQHandle
	STR	R0,[R1]

	ADR	R1,AudioDevice+120
	ADR	R0,AudioRateTable
	STR	R0,[R1]

	ADR	R1,AudioDevice+124
	ADR	R0,AudioDevice_SetRate
	STR	R0,[R1]

;--------- mixer

	ADR	R1,MixerDevice+12
	ADR	R0,MixerDevice_Desc
	STR	R0,[R1]

	ADR	R1,MixerDevice+32
	ADR	R0,MixerDevice_Activate
	STR	R0,[R1]

	ADR	R1,MixerDevice+36
	ADR	R0,MixerDevice_Deactivate
	STR	R0,[R1]

	ADR	R1,MixerDevice+40
	ADR	R0,MixerDevice_Reset
	STR	R0,[R1]

	ADR	R1,MixerDevice+44
	ADR	R0,MixerDevice_Sleep
	STR	R0,[R1]

	ADR	R1,MixerDevice+64
	ADR	R0,AudioDevice
	STR	R0,[R1]

	ADR	R1,MixerDevice+72
	ADR	R0,MixerDevice_GetFeatures
	STR	R0,[R1]

	ADR	R1,MixerDevice+76
	ADR	R0,MixerDevice_SetMix
	STR	R0,[R1]

	ADR	R1,MixerDevice+80
	ADR	R0,MixerDevice_GetMix
	STR	R0,[R1]

	ADR	R1,MixerDevice+84
	ADR	R0,MixerDevice_GetMixLimits
	STR	R0,[R1]



   	Pull    "R0-R12,pc"

; --------------------------------------------------------------

ClearIRQ

	MOV	pc,lr

; --------------------------------------------------------------

TestIRQ
        MOV	pc,lr
; ---------------------------------------------------------------------------
; ------------------- Device Driver activate Entry Point --------------------
; ---------------------------------------------------------------------------

AudioDevice_Activate ROUT
; AudioDevice_Activate
; => a1 = audio device
; <= a1 = success when TRUE

        Push    "R1-R12, lr" 	; R9=sb register
        MOV     a1, #1
        Pull    "R1-R12, pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ----------------- Device Driver Deactivate Entry Point --------------------
; ---------------------------------------------------------------------------
AudioDevice_Deactivate ROUT
        MOV     pc, lr

; ---------------------------------------------------------------------------
; --------------------- Device Driver Reset Entry Point ---------------------
; ---------------------------------------------------------------------------
AudioDevice_Reset ROUT
        MOV     pc, lr

; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; --------------------- Device Driver Sleep Entry Point ---------------------
; ---------------------------------------------------------------------------
AudioDevice_Sleep ROUT
        MOV     a1, #0
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; --------------------- Device Driver PreEnable Entry Point -----------------
; ---------------------------------------------------------------------------
AudioDevice_PreEnable
; AudioDevice_PreEnable
; => a1 = audio device
;    a2 = DMA buffer byte size
;    Audio DMA not running, IRQs enabled
        Push    "R0-R12,lr"


        ADD     R12, a1, #:INDEX:AudioDevice	; make R12 point to Wspace

; ---------------------------------------------------------------------------
; ------------ Fill FIFO buffer until full before turning on TX -------------
; ---------------------------------------------------------------------------
Fill_FIFO
	ADR	R3,I2S_Log_Base		; an offset from Wspace
	LDR	R0,[R3]			; load vaue
	ADD	R0,R0,#CS_A		; normally &F9203000+CS_A
	LDR 	R1,[R0]		        ; load value in CS_A register
	ORR	R1,R1,#EN       	; Enable I2S Interface
	STR 	R1,[R0]		        ; update value in CS_A register

	AND	R1,R1,#BIT19		; get bit 19
	CMP	R1,#0                   ; is it 0?
	BEQ	Filled                  ; if yes exit

	LDR	R0,[R3]			; load vaue
	ADD	R0,R0,#FIFO		; normally &F9203000+FIFO
	MOV	R1,#0			; load dummy data for FIFO
	STR 	R1,[R0]		        ; load value in FIFO register
	B	Fill_FIFO


Filled

        Pull    "R0-R12,pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; -------------------- Device Driver PostEnable Entry Point -----------------
; ---------------------------------------------------------------------------
AudioDevice_PostEnable
; AudioDevice_PostEnable
; => a1 = audio device
;    a2 = DMA buffer byte size
;    Audio DMA is running, IRQs enabled
        Push    "R0-R12,lr"

        ADD     R12, a1, #:INDEX:AudioDevice	; make R12 point to Wspace
	ADR	R0,I2S_Log_Base			; an offset from Wspace
	LDR	R0,[R0]				; load memory
	ADD	R0,R0,#CS_A			; normally &F9203000+CS_A

	LDR 	R1,[R0]				; load value in CS_A register
	ORR	R1,R1,#EN       		; Enable
	ORR	R1,R1,#STBY
	ORR	R1,R1,#SYNC
	ORR	R1,R1,#DMAEN			; Turn on DMA
	STR	R1,[R0]				; Store Back into register


	LDR 	R1,[R0]				; load value in CS_A register
	ORR	R1,R1,#TXCLR
	ORR	R1,R1,#SYNC			; set sync to 1
	STR	R1,[R0]				; Store Back into register

wait_for_sync1
	LDR 	R1,[R0]				; load value in CS_A register
	AND	R1,R1,#SYNC			; get sync bit
	CMP	R1,#0                   	; is it 0?
	BEQ	wait_for_sync1                  ; if yes goback


	LDR 	R1,[R0]				; load value in CS_A register
	ORR	R1,R1,#TXON     		; Turn on TX
	STR	R1,[R0]				; Store Back into register



        Pull    "R0-R12,pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; -------------------- Device Driver PreDisable Entry Point -----------------
; ---------------------------------------------------------------------------
AudioDevice_PreDisable
        Push    "R0-R9,lr"

        ADD     R12, a1, #:INDEX:AudioDevice	; make R12 point to Wspace
	ADR	R0,I2S_Log_Base			; an offset from Wspace
	LDR	R0,[R0]				; load memory
	ADD	R0,R0,#CS_A			; normally &F9203000+CS_A

	MOV	R1,#0				; CSA_A=0 turn off I2S
	STR	R1,[R0]				; Store Back into register

        Pull    "R0-R9,pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; -------------------- Device Driver PostEnable Entry Point -----------------
; ---------------------------------------------------------------------------
AudioDevice_PostDisable
        Push    "R0-R9,lr"
        Pull    "R0-R9,pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; -------------------- Device Driver IRQHandle Entry Point ------------------
; ---------------------------------------------------------------------------
AudioDevice_IRQHandle
        Push    "R1-R9,lr"
	MOV	R0,#0
        Pull    "R1-R9,pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ---------------- Mixer Device Driver activate Entry Point -----------------
; ---------------------------------------------------------------------------
MixerDevice_Activate ROUT
        Push    "R1-R9, lr" 	; R9=sb register
        MOV     a1, #1
        Pull    "R1-R9, pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; --------------- Mixer Device Driver Deactivate Entry Point ----------------
; ---------------------------------------------------------------------------
MixerDevice_Deactivate ROUT
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ------------------ Mixer Device Driver Reset Entry Point ------------------
; ---------------------------------------------------------------------------
MixerDevice_Reset ROUT
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ---------------- Mixer Device Driver Sleep Entry Point --------------------
; ---------------------------------------------------------------------------

MixerDevice_Sleep ROUT
        MOV     a1, #0
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ---------------- Mixer Device Driver GetFeatures Entry Point --------------
; ---------------------------------------------------------------------------
MixerDevice_GetFeatures ROUT
        ADR     a1, MixerFeaturesTab
        LDR     a1, [a1, a2, LSL #2]
        MOV     pc, lr


; ---------------------------------------------------------------------------

; ---

MixerFeaturesTab
        DCW    0	; not fixed / not mono
        DCW    0	; system volume

        DCW    0
        DCW    -2

        DCW    0
        DCW    -3

        DCW    0
        DCW    0
        DCW    3

        DCW    0
        DCW    3
        DCW    -2

; ---------------------------------------------------------------------------
; ------------------ Mixer Device Driver SetMix Entry Point -----------------
; ---------------------------------------------------------------------------
; MixerDevice_SetMix
; => a1 = mixer device
;    a2 = channel
;    a3 = flags word
;    a4 = signed gain in 1/16th's dB

MixerDevice_SetMix ROUT
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ------------------ Mixer Device Driver GetMix Entry Point -----------------
; ---------------------------------------------------------------------------
; MixerDevice_GetMix
; => a1 = mixer device
;    a2 = channel
; <= a1 = flags word
;    a2 = signed gain in 1/16th's dB

MixerDevice_GetMix ROUT
        SUB     r12, a1, #:INDEX:MixerDevice
        ADR     a1, MixSettings
        ADD     a1, a1, a2, LSL #3
        LDMIA   a1, {a1, a2}

	MOV	a1,#0
	MOV	a2,#64    ; = 4.0  /16

        MOV     pc, lr

; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ------------- Mixer Device Driver GetMixLimits Entry Point ----------------
; ---------------------------------------------------------------------------
MixerDevice_GetMixLimits ROUT
        MOV     pc, lr
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
AudioRateTable


        DCD     8000*1024
	DCB	125               	;  8kHz     (125usec)  AC97/6
	DCB	0,0,0

        DCD     11025*1024
	DCB	91               	; 11.025kHz (~91 usec) CD/4
	DCB	0,0,0

        DCD     12000*1024
	DCB	83               	; 12kHz     (~83 usec) AC97/4
	DCB	0,0,0

        DCD     16000*1024
	DCB	63               	; 16kHz     (~63 usec) AC97/3
	DCB	0,0,0

        DCD     22050*1024
	DCB	45               	; 22.05kHz  (~45 usec) CD/2
	DCB	0,0,0

        DCD     24000*1024
	DCB	42               	; 24kHz     (~42 usec) AC97/2
	DCB	0,0,0

        DCD     32000*1024
	DCB	31               	; 32kHz     (~31 usec) AC97*2/3
	DCB	0,0,0

        DCD     44100*1024
	DCB	23               	; 44.1kHz   (~23 usec) CD/1
	DCB	0,0,0

        DCD     48000*1024
	DCB	21               ; 48kHz     (~21 usec) AC97/1
	DCB	0,0,0
AudioRateTable_End
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ------------------- Device Driver SetRate Entry Point --------------------
; ---------------------------------------------------------------------------
; AudioDevice_SetRate
; => a1 = audio device
;    a2 = rate table index
AudioDevice_SetRate ROUT
        Push    "R0-R12, lr" 	; R9=sb register
        Pull    "R0-R12, pc"
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; --------------------------- initilise module ------------------------------
; ---------------------------------------------------------------------------
; entry

Init    ROUT
        Push    "R0-R12,lr"

	MOV	R0,#6
	MOV	R3,#WSSize
	SWI	XOS_Module
        STR     r2, [r12]
	LDR	r12,[R12]


	BL	Initilise_GPIO

; ---------------------------------------------------------------------------
; ---------- clear WS and copy templates of Audio / Mixer devices -----------
; ---------------------------------------------------------------------------
	BL	Clr_Workspace

       	ADR     R1, AudioDevice
       	ADRL     R2, AudioDeviceTemplate
       	MOV     R3, # HALDevice_Audio_Size_1 / 4
       	BL      mymemcpy

       	ADR     R1, MixerDevice
       	ADR     R2, MixerDeviceTemplate
       	MOV     R3, # HALDevice_Mixer_Size_0_1 / 4
       	BL      mymemcpy
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; --------- Detect processor type and adjust PI_Phy_Base address ------------
; -------------------- R0 = PI3 BCM2836 ID (0x410FD034) ---------------------
; -------------------- R1 = Our Current Processor       ---------------------
; -------------------- R2 = I2S_Phy_Base (0x20203000)   ---------------------
; -------------------- R3=WS area to store PI_Phy_Base  ---------------------
; ------- PI_Phy_Base Contains 0x20203000 for PI or 0x3F203000 for PI3 ------; ---------------------------------------------------------------------------
	ADR	r3,I2S_PI_Phy_Base	;  where to store pi phy base
	ADRL	r0,PI3_CPU_ID		; load pointer to address
	LDR	r0,[r0]		      	; load actual PI3 address
	MRC 	p15,0,r1,c0,c0,0	; what processor are we on?
	ADRL 	r2,I2S_Phy_Base         ; pointer to I2S (0x20203000)
	LDR 	r2,[r2]                 ; load  with I2S pointer value
	CMP	r0,r1                   ; is it a pi 3
	ADDEQ	r2,r2,#&1F000000        ; if yes add #&1F000000
	STR	r2,[r3]			; store into I2S_PI_Phy_Base
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; -------- Obtain a logical base address from the PI_Phy_Base ---------------
; ---------------------------------------------------------------------------
	MOV 	r0,#13                  ; os_memory 13
	ADRL 	r1,I2S_PI_Phy_Base      ; pointer to I2S (0x20203000)
	LDR 	r1,[r1]                 ; load r1 with I2S  value
	MOV 	r2,#&100                ; (&100) 256 byte total to allocate
	SWI 	XOS_Memory              ; run

	ADR 	r5,I2S_Log_Base         ; where to store logical base memory
	STR 	r3,[r5]                 ; return logical address

; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ------------- Insert offsets to pre/post routines etc into WS -------------
; ---------------------------------------------------------------------------
	BL	Insert_Offsets_Into_WS
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ----------------------------- Register devices ----------------------------
; ---------------------------------------------------------------------------

	ADR	R0,MixerDevice
	MOV	R8,#2
	SWI	XOS_Hardware

 	ADR	R0,AudioDevice
	MOV	R8,#2
	SWI	XOS_Hardware

        Pull    "R0-R12,pc"
; exit
; ---------------------------------------------------------------------------

; ---

; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------

Final   ROUT
        Push    "R0-R8,lr"

	ADR	R0,AudioDevice
	MOV	R8,#3
	SWI	XOS_Hardware

	ADR	R0,MixerDevice
	MOV	R8,#3
	SWI	XOS_Hardware

        Pull    "R0-R8,pc"

; ---------------------------------------------------------------------------


mymemcpy
        Push    "R0-R11,lr"

mem_loop
	LDR	R0,[R2],#4
	STR	R0,[R1],#4
        SUBS	R3,R3,#1
 	BNE	mem_loop

   	Pull    "R0-R11,pc"

; ---------------------------------------------------------------------------

Clr_Workspace
        Push    "R0-R12,lr"

	MOV	R0,#0
	MOV	R1,wp
	MOV	R3,#WSSize /4
Clr_loop
	STR	R0,[R1],#4
        SUBS	R3,R3,#1
	BNE	Clr_loop

   	Pull    "R0-R12,pc"
; ---------------------------------------------------------------------------

; ---

Initilise_GPIO
        Push    "R0-R12,lr"

	MOV	R0,#18
	MOV	R1,#4
	SWI	GPIO_WriteMode		; set GPIO18 to Alt 0 (I2S PCM)
	MOV	R0,#19
	MOV	R1,#4
	SWI	GPIO_WriteMode		; set GPIO19 to Alt 0 (I2S LRCK)
	MOV	R0,#20
	MOV	R1,#4
	SWI	GPIO_WriteMode		; set GPIO20 to Alt 0 (I2S Din)
	MOV	R0,#21
	MOV	R1,#4
	SWI	GPIO_WriteMode		; set GPIO21 to Alt 0 (I2S Dout)

	MOV	R0,#5
	MOV	R1,#0
	SWI	GPIO_WriteOE		; set GPI05 to an output (HIFIberry)

	MOV	R0,#6
	MOV	R1,#0
	SWI	GPIO_WriteOE		; set GPI06 to an output (HIFIberry)

	MOV	R0,#5
	MOV	R1,#1
	SWI	GPIO_WriteData		; GPI05 high (HIFIberry Xtal select)

	MOV	R0,#6
	MOV	R1,#0
	SWI	GPIO_WriteData		; GPI06 low (HIFIberry Xtal select)


   	Pull    "R0-R12,pc"
        END
; ---------------------------------------------------------------------------
