702 lines
16 KiB
NASM
702 lines
16 KiB
NASM
;------------------------------------------------------------------------------------------------------------------------
|
|
; Copyright (c) 2007, Mukunda Johnson
|
|
;
|
|
; All rights reserved.
|
|
;
|
|
; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
;
|
|
; * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
; * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
; * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
;
|
|
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
;-----------------------------------------------------------------------------------
|
|
|
|
.equ REG_APUI00 $2140
|
|
.equ REG_APUI01 $2141
|
|
.equ REG_APUI02 $2142
|
|
.equ REG_APUI03 $2143
|
|
|
|
.include "memmap.inc" ; replace with your memory definitions
|
|
|
|
.MACRO SPX_RECEIVE_MESSAGE
|
|
sta spx_message
|
|
and #15
|
|
jsl MessageReceived ; SET THIS TO YOUR MESSAGE HANDLER
|
|
.ENDM
|
|
|
|
.define SPX_STACK_SIZE $10 ; increase stack size if neccesary
|
|
|
|
.define SPX_XMSOFFSET $2100
|
|
|
|
.MACRO SPX_SYNC
|
|
lda spx_validation ; load validation
|
|
- cmp REG_APUI03 ; sync
|
|
bne -
|
|
.ENDM
|
|
|
|
.ramsection "spx_var" BANK 0 SLOT 1
|
|
spx_spvar: db
|
|
spx_validation: db
|
|
spx_package_adr: dsb 3
|
|
|
|
spx_stack: dsb SPX_STACK_SIZE*4 ; FIFO stack
|
|
spx_stack_r: dw ; stack read position
|
|
spx_stack_w: dw ; stack write position
|
|
|
|
spx_var1: dw
|
|
spx_var2: dw
|
|
spx_var3: dw
|
|
spx_var4: dw
|
|
|
|
spx_message: db
|
|
|
|
ddd: db
|
|
|
|
.ends
|
|
|
|
.bank 0
|
|
.SECTION "SPX_SNES"
|
|
|
|
spx_binary:
|
|
.incbin "spx_binaries\spx_core.bin"
|
|
spx_lft:
|
|
.incbin "spx_binaries\spx_lft.bin"
|
|
spx_aft:
|
|
.incbin "spx_binaries\spx_aft.bin"
|
|
spx_aftf:
|
|
.incbin "spx_binaries\spx_aftf.bin"
|
|
|
|
.INDEX 16
|
|
|
|
;----------------------------------------------------------------------------------------------------
|
|
BootSPC:
|
|
ldx #spx_binary
|
|
lda #:spx_binary
|
|
|
|
; x = source address (word) 16-BIT INDEX
|
|
; a = bank (byte) 8-BIT AKKU
|
|
|
|
sei ; disable interrupts during upload
|
|
|
|
stx spx_var1 ; store source address in var1
|
|
sta spx_var1+2 ; store bank
|
|
|
|
REP #$20 ; 16-bit akku
|
|
lda #$BBAA ; Check if SPC is ready
|
|
- cmp REG_APUI00 ;
|
|
bne - ;
|
|
|
|
SEP #$20 ; 8-bit akku
|
|
ldy #0 ; reset data counter
|
|
lda #0 ; reset port0 data (for protocol)
|
|
xba ; swap out
|
|
|
|
; load first block
|
|
lda #$01 ; port1 = NOT 0
|
|
sta REG_APUI01 ;
|
|
|
|
REP #$20 ; 16-bit akku
|
|
lda [spx_var1], y ; load data transfer address
|
|
iny ; increase data pointer
|
|
iny ;
|
|
sta REG_APUI02 ; ports2/3 = TRANSFER ADDRESS
|
|
|
|
SEP #$20 ; 8-bit akku
|
|
lda #$CC ; port0 = $CC (protocol)
|
|
sta REG_APUI00 ;
|
|
|
|
- cmp REG_APUI00 ; wait for SPC reply
|
|
bne - ;
|
|
|
|
REP #$20 ; 16-bit akku
|
|
lda [spx_var1], y ; load data LENGTH
|
|
tax ; transfer to X
|
|
SEP #$20 ; 8-bit akku
|
|
iny ; increase data pointer
|
|
iny ;
|
|
lda [spx_var1], y ; load first byte (real data)
|
|
iny ; increase pointer
|
|
sta REG_APUI01 ; port1 = data
|
|
|
|
lda #0 ; port0 = 0 (start sending data)
|
|
sta REG_APUI00 ;
|
|
|
|
- cmp REG_APUI00 ; wait for SPC reply
|
|
bne - ;
|
|
|
|
dex ; prepare loop
|
|
xba ; swap counter/data
|
|
|
|
scr_data_loop:
|
|
lda [spx_var1], y ; load byte
|
|
iny ; inc pointer
|
|
xba ; swap to counter
|
|
|
|
- cmp REG_APUI00 ; check/wait for SPC reply
|
|
bne - ;
|
|
|
|
ina ; increase counter
|
|
REP #$20 ; port1 = data
|
|
sta REG_APUI00 ; port0 = counter
|
|
SEP #$20 ;
|
|
|
|
xba ; swap to data
|
|
|
|
dex ; decrease loop counter
|
|
bne scr_data_loop ; loop
|
|
|
|
xba ; swap to counter
|
|
|
|
- cmp REG_APUI00 ; check/wait for SPC reply
|
|
bne - ;
|
|
|
|
xba ; swap to data
|
|
|
|
REP #$20 ; 16-bit akku
|
|
pha ; preserve
|
|
lda [spx_var1], y ; load next block size
|
|
tax ; transfer to X
|
|
pla ; restore
|
|
SEP #$20 ; 8-bit akku
|
|
|
|
iny ; increase data pointer
|
|
iny ;
|
|
cpx #0 ; load another block? (if block size is 0, then no)
|
|
beq scr_terminate ; ...
|
|
|
|
REP #$20 ; yes..
|
|
pha ; preserve
|
|
lda [spx_var1], y ; load something
|
|
tax ; transfer to X
|
|
pla ; restore
|
|
SEP #$20 ; 8-bit akku
|
|
|
|
iny ; increase pointer
|
|
iny ;
|
|
lda #1 ; port1 = NOT 0
|
|
sta REG_APUI01 ;
|
|
stx REG_APUI02 ; port2/3 = transfer address
|
|
xba ; swap to counter
|
|
ina ; counter += 2, != 0
|
|
- ina ;
|
|
beq - ;
|
|
|
|
sta REG_APUI00 ; store in port0
|
|
|
|
- cmp REG_APUI00 ; wait for SPC reply
|
|
bne - ;
|
|
bra scr_data_loop ; jump to data loop
|
|
|
|
scr_terminate: ; no...
|
|
stz REG_APUI01 ; port1 = 0
|
|
REP #$20 ; 16-bit akku
|
|
pha ; preserve
|
|
lda [spx_var1], y ; load program start address
|
|
tax ; transfer to X
|
|
pla ; restore
|
|
SEP #$20 ; 8-bit akku
|
|
|
|
stx REG_APUI02 ; port2/3 = program start address
|
|
xba ; swap to counter
|
|
ina ; counter += 2, != 0
|
|
- ina ;
|
|
beq - ;
|
|
|
|
sta REG_APUI00 ; port0 = counter
|
|
- cmp REG_APUI00 ; wait for SPC reply
|
|
bne - ;
|
|
; TRANSFER COMPLETE.
|
|
cli ; enable interrupts
|
|
|
|
jmp SPX_Init ; Initialize
|
|
;-----------------------------------------------------------------------------------------------------
|
|
SPX_Init:
|
|
lda #0 ; reset validation
|
|
sta spx_validation
|
|
sta spx_stack_w ; reset stack read/write
|
|
sta spx_stack_r
|
|
|
|
REP #$20
|
|
lda #$FEED ; initial sync
|
|
- cmp REG_APUI00 ;
|
|
bne -
|
|
SEP #$20
|
|
RTL
|
|
|
|
;-----------------------------------------------------------------------------------------------------
|
|
SPX_Transfer_XMS:
|
|
; ayy = 24-bit address
|
|
sty spx_var1 ; save address
|
|
sta spx_var2
|
|
rep #$20 ; 16bit everything
|
|
rep #$10
|
|
lda [spx_var1] ; load length
|
|
tax ; x = length/3
|
|
ldy #SPX_XMSOFFSET
|
|
lda spx_var1
|
|
pha
|
|
sep #$20
|
|
lda spx_var2
|
|
jsl SPX_Transfer
|
|
|
|
ply
|
|
rtl
|
|
;-----------------------------------------------------------------------------------------------------
|
|
.accu 8
|
|
SPX_Transfer_LFT:
|
|
sep #$20 ; 8-bit akku
|
|
rep #$10 ; 16-bit index
|
|
ldx #(768/3) ; set transfer length (bytes/3)
|
|
ldy #(spx_lft & 65535) ; load snes offset
|
|
phy ; push
|
|
ldy #$300 ; $300-$5FF = linear frequency LUT
|
|
lda #:spx_lft ; get bank#
|
|
|
|
JSL SPX_Transfer ; transfer data
|
|
|
|
ply ; free stack
|
|
|
|
lda.b #$1C ; set table
|
|
sta REG_APUI02 ;
|
|
stz REG_APUI01 ;
|
|
JSL SPX_SEND ;
|
|
|
|
RTL ; return
|
|
|
|
;-----------------------------------------------------------------------------------------------------
|
|
SPX_Transfer_AFT:
|
|
sep #$20 ; 8-bit akku
|
|
rep #$10 ; 16-bit index
|
|
ldx #(768/3) ; set transfer length (bytes/3)
|
|
ldy #(spx_aft & 65535) ; load snes offset
|
|
phy ; push
|
|
ldy #$300 ; $300-$5FF = amiga period LUT
|
|
lda #:spx_aft ; get bank#
|
|
JSL SPX_Transfer ; transfer data
|
|
ply ; free stack
|
|
|
|
ldx #1365 ; 4096/3, rounded down
|
|
ldy #(spx_aftf & 65535) ; load snes offset
|
|
phy ; push
|
|
ldy #$F000 ; $F000-$FFFF = amiga->freq LUT
|
|
lda #:spx_aftf ; get bank#
|
|
JSL SPX_Transfer ; transfer data
|
|
ply ; free stack
|
|
lda #$1C ; set table
|
|
sta REG_APUI02 ;
|
|
lda #$01 ;
|
|
sta REG_APUI01 ;
|
|
JSL SPX_SEND ;
|
|
RTL ; return
|
|
|
|
;-----------------------------------------------------------------------------------------------------
|
|
.INDEX 16
|
|
.ACCU 8
|
|
|
|
.MACRO SPX_TRANSFER_INCPOINTER
|
|
iny ; increase pointer
|
|
iny ;
|
|
bpl ++ ; check for overflow
|
|
cpy #$8001 ; check for an overflow reading
|
|
bne + ; fix data if so
|
|
dey ;
|
|
dey ;
|
|
lda [spx_var1], y ; read low byte
|
|
sta REG_APUI00 ; store
|
|
ldy #$0000 ; read high byte
|
|
inc spx_var1+2 ; next bank
|
|
lda [spx_var1], y ;
|
|
sta REG_APUI01 ;
|
|
iny ;
|
|
lda spx_validation ;
|
|
xba ;
|
|
bra ++ ;
|
|
+ ; if not just increase bank#
|
|
inc spx_var1+2 ; increase bank#
|
|
ldy #$0000 ; reset counter
|
|
++
|
|
.ENDM
|
|
|
|
SPX_Transfer_SAMP:
|
|
sei ; $14 = SAMPLE TRANSFER
|
|
sta spx_var1+2 ;
|
|
SPX_SYNC ;
|
|
lda #$14 ;
|
|
jmp SPX_TRANSFER_MOD;
|
|
|
|
SPX_Transfer:
|
|
; SPX_Transfer
|
|
; parameters:
|
|
; a = file bank :8
|
|
; x = length/4 :16
|
|
; y = spc offset :16
|
|
; stack:1 = snes_offset :16
|
|
|
|
; types
|
|
; 0 = xms
|
|
; 1 = freq table
|
|
|
|
sei ; disable interrupts
|
|
|
|
sta spx_var1+2 ; store bank#
|
|
|
|
SPX_SYNC ; sync with spc
|
|
|
|
lda #$1A ; $1A = GENERIC TRANSFER
|
|
SPX_TRANSFER_MOD:
|
|
sta REG_APUI02 ; set message type
|
|
|
|
REP #$20 ; set spc write position
|
|
tya ;
|
|
SEP #$20 ;
|
|
sta REG_APUI00 ;
|
|
xba ;
|
|
sta REG_APUI01 ;
|
|
|
|
lda spx_validation ; validate data
|
|
eor #128 ;
|
|
ora #1
|
|
sta REG_APUI03 ;
|
|
- cmp REG_APUI03 ; wait for spc to respond
|
|
bne -
|
|
|
|
; eor #128 ; prepare transfer mode
|
|
|
|
sta spx_validation ; save
|
|
|
|
REP #$20 ; 16-bit akku
|
|
lda 4, S ; load file offset sp+4
|
|
|
|
sec ; set carry
|
|
sbc #$8000 ; subtract
|
|
tay ; transfer to y
|
|
SEP #$20 ; 8-bit akku
|
|
lda #$80 ; set offset in var1
|
|
stz spx_var1 ; reset mem pointers
|
|
sta spx_var1+1 ;
|
|
|
|
REP #$20 ; 16-bit akku
|
|
|
|
_stf_start: ; loop:
|
|
|
|
lda [spx_var1], y ; load data
|
|
sta spx_var3 ; save
|
|
|
|
SPX_TRANSFER_INCPOINTER
|
|
|
|
sep #$20
|
|
lda [spx_var1], y ; get third byte
|
|
|
|
iny ; increase pointer
|
|
bpl +
|
|
ldy #$0000
|
|
inc spx_var1+2
|
|
+
|
|
sta spx_spvar ; store
|
|
lda spx_validation ; get validation
|
|
eor #128 ;
|
|
sta spx_validation ; update
|
|
eor #128 ; reverse
|
|
|
|
phx ; preserve
|
|
ldx spx_spvar ; get ready
|
|
|
|
- cmp REG_APUI03 ; sync with spc
|
|
bne - ;
|
|
|
|
lda spx_var3 ; load byte1
|
|
sta REG_APUI00 ; store byte1
|
|
lda spx_var3+1 ; load byte2
|
|
sta REG_APUI01 ; store byte2
|
|
stx REG_APUI02 ; store byte3/validation
|
|
plx ; restore
|
|
rep #$20
|
|
|
|
dex ; decrease counter
|
|
bne _stf_start ; loop until finished
|
|
|
|
sep #$20
|
|
|
|
stz REG_APUI03 ; send 0
|
|
stz spx_validation
|
|
lda #0
|
|
- cmp REG_APUI03 ; wait for reply
|
|
bne -
|
|
|
|
cli ; enable interrupts
|
|
RTL ; return --make sure higher function frees stack space
|
|
|
|
;--------------------------------------------------------------------------------------------------------
|
|
.index 16
|
|
SPX_Queue:
|
|
; a = $00/$01 message
|
|
; x = $02/$03 params
|
|
; accumulator can be 8 or 16 bit, do not read anything with it
|
|
ldy spx_stack_w ; load stack position
|
|
sta spx_stack, y ; store bytes0/1
|
|
iny ; increase pointer
|
|
iny
|
|
txa ; get high word
|
|
sta spx_stack, y ; store bytes 2/3
|
|
iny ; increase pointer
|
|
iny
|
|
cpy #SPX_STACK_SIZE*4 ; wrap to stack size
|
|
bcc +
|
|
ldy #0
|
|
+
|
|
sty spx_stack_w ; save stack position
|
|
rtl
|
|
|
|
;---------------------------------------------------------------------------------------------------------
|
|
.accu 8
|
|
SPX_Routine:
|
|
; get messages
|
|
lda REG_APUI00 ; check if port0 is different
|
|
cmp spx_message
|
|
beq +
|
|
SPX_RECEIVE_MESSAGE ; if so then a message was received
|
|
+
|
|
lda spx_validation ; check if spc has processed last message
|
|
cmp REG_APUI03
|
|
beq +
|
|
rtl ; not ready
|
|
+
|
|
ldy spx_stack_r ; load stack read position
|
|
cpy spx_stack_w ; exit function if it equals write position (no messages)
|
|
bne +
|
|
rtl
|
|
+
|
|
lda spx_stack, y ; load byte0
|
|
sta REG_APUI00 ; store
|
|
iny
|
|
lda spx_stack, y ; load byte1
|
|
sta REG_APUI01 ; store
|
|
iny
|
|
lda spx_stack, y ; load byte2
|
|
sta REG_APUI02 ; store
|
|
iny
|
|
lda spx_stack, y ; load byte3
|
|
lda spx_validation ; add validation
|
|
and #128
|
|
eor #128
|
|
ora spx_stack, y ; store
|
|
sta REG_APUI03 ; message dispatched
|
|
sta spx_validation ; save validation
|
|
|
|
iny
|
|
|
|
cpy #SPX_STACK_SIZE*4 ; wrap read counter to stack size
|
|
bcc +
|
|
ldy #0
|
|
+
|
|
sty spx_stack_r ; save
|
|
|
|
rtl
|
|
|
|
SPX_Flush: ; flushes queue
|
|
jsl SPX_Routine ; call routine
|
|
ldy spx_stack_r ; check for more messages
|
|
cpy spx_stack_w
|
|
bne SPX_Flush ; loop
|
|
rtl ; exit
|
|
|
|
SPXM_Play:
|
|
ldx #$1E ; $1E = play message
|
|
jmp SPX_Queue
|
|
|
|
SPXM_BuildDir:
|
|
ldx #$1B ; $1B = build directory
|
|
jmp SPX_Queue
|
|
|
|
SPXM_Reset: ; blocking function
|
|
ldx #$1D ; $1D = RESET XMS
|
|
jmp SPX_Queue
|
|
|
|
SPXM_SetVol:
|
|
; a = volume
|
|
ldx #$18 ; $18 = set XM playback volume
|
|
jmp SPX_Queue
|
|
|
|
SPX_SetVol:
|
|
; a = volume L } 16bit akku
|
|
; b = volume R } resets afterwards
|
|
ldx #$19 ; $19 = change main volume
|
|
jmp SPX_Queue
|
|
|
|
.accu 8
|
|
.index 16
|
|
SPXS_Play:
|
|
; a = volume [llllrrrr]
|
|
; x = sample#/priority/frequency [0ccfffffssssssss]
|
|
|
|
pha ; rearrange data
|
|
rep #$20
|
|
txa
|
|
sep #$20
|
|
pha
|
|
rep #$20
|
|
and #$FF00
|
|
ora #$20 ; $20 = play sample
|
|
tax
|
|
sep #$20
|
|
pla
|
|
xba
|
|
pla
|
|
rep #$20
|
|
|
|
jsl SPX_Queue
|
|
sep #$20
|
|
rtl
|
|
|
|
SPXS_SetParam:
|
|
; a = index
|
|
; x = param
|
|
xba ; rearrange data
|
|
tax
|
|
xba
|
|
rep #$20
|
|
ldx #$21 ; $21 = message
|
|
jsl SPX_Queue ; queue
|
|
sep #$20
|
|
rtl
|
|
|
|
SPX_SEND: ; blocking send
|
|
lda spx_validation ; get validation
|
|
eor #128 ; change
|
|
sta REG_APUI03 ; set port data
|
|
sta spx_validation ; save validation
|
|
- cmp REG_APUI03 ; wait for spc reply
|
|
bne -
|
|
|
|
RTL ; exit
|
|
|
|
SPXP_InstallPackage:
|
|
; x = address (16-bit) ;
|
|
; a = bank#
|
|
stx spx_package_adr ; store offset
|
|
sta spx_package_adr+2 ; store bank
|
|
rtl
|
|
|
|
SPXP_LoadSong:
|
|
; x = index (16-bit)
|
|
|
|
sep #$20 ; 8bit akku
|
|
txa ; a=x
|
|
sta $4202 ; multiply a*3
|
|
lda #3 ;
|
|
sta $4203 ; 8 cycles... ; ...
|
|
|
|
; setup send
|
|
rep #$20 ; read package address
|
|
|
|
lda #$10
|
|
nop
|
|
nop
|
|
nop ; small delay
|
|
clc
|
|
adc $4216 ; add multiplication result
|
|
tay ; y=result
|
|
|
|
lda spx_package_adr ; read package address
|
|
adc [spx_package_adr], y ; add song offset
|
|
ora #$8000 ;
|
|
pha ; save result
|
|
sep #$20 ; 8bit akku
|
|
lda spx_package_adr+2 ; load bank#
|
|
iny
|
|
iny
|
|
adc [spx_package_adr], y ; add song offset
|
|
ply ; restore address
|
|
|
|
jsl SPX_Transfer_XMS ; transfer song
|
|
|
|
; transfer samples
|
|
|
|
SPX_SYNC
|
|
|
|
lda #$17 ; ask for sample requests
|
|
sta REG_APUI02
|
|
jsl SPX_SEND
|
|
--
|
|
|
|
; message received
|
|
lda REG_APUI02 ; satisfy request
|
|
cmp #$9C ; 9c = no more samples
|
|
beq +
|
|
ldx REG_APUI00
|
|
ldy #0
|
|
jsl SPXP_LoadSample ; send sample
|
|
|
|
jsl SPX_SEND ; sync
|
|
|
|
jmp --
|
|
+
|
|
rtl
|
|
|
|
SPXP_LoadSample:
|
|
; x = index (16-bit)
|
|
; y = spc address, 0=use next available
|
|
|
|
rep #$20 ; 16-bit akku
|
|
txa ; a=x
|
|
sta spx_var1 ; save
|
|
asl ; shift
|
|
adc spx_var1 ; add (a = index*3 now)
|
|
phy
|
|
ldy #4
|
|
adc [spx_package_adr],y ; add sample table offset
|
|
|
|
tay
|
|
clc
|
|
lda spx_package_adr
|
|
adc [spx_package_adr], y
|
|
ora #$8000 ; wrap around ROM area if overflow
|
|
sta spx_var1
|
|
|
|
sep #$20
|
|
lda spx_package_adr+2
|
|
iny
|
|
iny
|
|
adc [spx_package_adr], y
|
|
adc #0 ; increase on overflow
|
|
sta spx_var2
|
|
|
|
rep #$20
|
|
|
|
lda [spx_var1] ; load sample size/3
|
|
tax ; transfer to x
|
|
|
|
lda spx_var1 ; load snes address
|
|
|
|
ply
|
|
pha
|
|
sep #$20 ; 8-bit akku
|
|
lda spx_var2 ; load bank#
|
|
|
|
jsl SPX_Transfer_SAMP ; transfer data
|
|
ply ; restore stack
|
|
|
|
lda spx_validation ; get sample #
|
|
eor #128
|
|
sta REG_APUI03
|
|
- cmp REG_APUI03
|
|
bne -
|
|
sta spx_validation
|
|
|
|
lda REG_APUI00
|
|
|
|
rtl ; return
|
|
|
|
.ENDS
|