Appendix 7

Listing for AFM Realtime.asm

nolist

include 'DSPInit.asm'

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

;Memory Map :

;- See how the C compiler organizes the data and variables

; and we will hand code the asm file generated

;

;- We will use the load a sine table into locations Y:256 through Y:511 of the

; extrenal Y data RAM and a exponential table into locations X:256 through X:511 of the

; external X data RAM of the DSP56000

; we need the set Data Rom Enable, DE = 0, in the Operating Mode Register (OMR)

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

ProgramStart EQU $0040

;General variables used in the algorithm

Pi EQU 3.1415926536

TwoPi EQU 2.0*Pi

Factor EQU 0.017453292

PointOne EQU 0.1

PointZOne EQU 0.01

PointZZOne EQU 0.001

PointZZZOne EQU 0.0001

PointFive EQU 0.5

One EQU 1.0

Two EQU 2.0

;Memory locations for general and common usage

FLAGS EQU $0001

DELAY EQU $0002

CYCLE_A EQU $0003

CYCLE_B EQU $0004

CYCLE_C EQU $0005

SINE_TABLE_START EQU $0006

SINE_TABLE_END EQU $0007

SINE_TABLE_SIZE EQU $0008

COSINE_TABLE_START EQU $0009

COSINE_TABLE_END EQU $000A

COSINE_TABLE_SIZE EQU $000B

SINE_COSINE_OFFSET EQU $000C

EXP_TABLE_START EQU $000D

EXP_TABLE_END EQU $000E

EXP_TABLE_SIZE EQU $000F

ZERO EQU $0010

CYCLE_C_LENGTH EQU $0011

ENVELOPE EQU $0012 ;start address of envelope table

ONE EQU $0013

TEMP_A EQU $00F0

TEMP_B EQU $00F1

TEMP_C EQU $00F2

TEMP_D EQU $00F3

COSINE_PHASE EQU $00F4

RATIO EQU $00F5

ONEBYRATIO EQU $00F6

;Parameters for Operator 1

CARRIER1_FREQ EQU $0020

MODULATOR1_FREQ EQU $0021

MODULATION1_INDEX EQU $0022

RATIO1 EQU $0023

NORMALIZATION1 EQU $0024

CARRIER1_PHASE EQU $0025

MODULATOR1_PHASE EQU $0026

EXP1_PHASE EQU $0027

IR1_PLUS EQU $0028 ;start address of ir1plus

IR1_MINUS EQU $0029 ;start address of ir1minus

AMP1 EQU $002A ;start address of amp1

;Parameters for Operator 2

CARRIER2_FREQ EQU $0040

MODULATOR2_FREQ EQU $0041

MODULATION2_INDEX EQU $0042

RATIO2 EQU $0043

NORMALIZATION2 EQU $0044

CARRIER2_PHASE EQU $0045

MODULATOR2_PHASE EQU $0046

EXP2_PHASE EQU $0047

IR2_PLUS EQU $0048 ;start address of ir2plus

IR2_MINUS EQU $0049 ;start address of ir2minus

AMP2 EQU $004A ;start address of amp2

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

;Host Command Jump Table

;This is where we assign the interrupt vectors to the labels (addresses)

;of the various subroutines

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

ORG P:Reset

JMP ProgramStart

ORG P:SSITxInt

JSR TxInterrupt

ORG P:SSITxEx

JSR SSIException

ORG P:HostCmdInt0

JSR hcOutputWave

ORG P:HostCmdInt13

JSR RxDataInterrupt

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

;Main Program

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

ORG P:ProgramStart

MOVEP #$0000,X:M_BCR ;no wait states

BCLR #M_HF3,X:M_HCR ;HF3 = 0 ie handshake to Mac indicating now not in play mode

;This is where we usually set up various constants in memory, initialize pointers, etc...

;that stay the same between running of the algorithm. REMEMBER that if you request a card

;that has your algorithm already loaded into it, code that lives here WILL NOT BE RUN again

;because the driver will just say heres your card and it's already loaded so don't put

;stuff here that changes after or while you run your algorithm. Put stuff like that in a

;host command called initialize or at the start of your generic do it host command. See

;the filter module in DSPWorkshop for an example.

;NOTE: The following lines set up the various on chip and on card hardware. Generally you should

;just cut and paste from here and/or DSPWorkshop to get things the way you want them. The order

;is important so don't change it unless you know what your doing. See the white binder for

;more info on all the card controll logic and chapter 11 in the red book for the SSI etc...

;The I/O-interrupts on the 56k are quite complicated so mess with these initial 'magic' bit settings

;at your own risk and only after consulting the white binder and the red book.

MOVE #>$001377,X0 ;standard STEREO_ON_CARD_PLAYBACK (see white book)

MOVEM X0,P:CTL_LATCH ;set I/O control latch (see white book for details)

MOVEP #$2400,X:M_IPR ;set ssi ipl = 1, host port ipl = 0

MOVEP #$4006,X:M_CRA ;prescale = 1,const = 6,wl = 16 bits ie 44.1kHz

;sets SSI's on chip baud rate - see chap 11 in red book

BTST #4,X:M_SR ;read SSI SR to clear TUE bit so we don't get intrrupted??

MOVEP #0,X:M_TX ;send out zero sample, in conjunction with last line clrs TUE

MOVEP #$531E,X:M_CRB ;RIE = disable,RE = disable, TIE = enable,TE = enable

;SCKD = 0(ext clk),OF1 =1(stereo),OF0 = 0(ext clk)

MOVEP #$0005,X:M_PCDDR ;always!! set to this value so PAL's on card don't

;get conflicting pin directions on expansion port

MOVEP #$0001,X:M_PCD ;Oncard clock source,enable expansion port

; transmit it's a good idea to always enable the expansion port

;transmit so that someone using external DAC,I/O boxes etc...

;can get hold of the data your program generates

;The following three lines must be in this order and next to each other.

MOVEP #$01F8,X:M_PCC ;set port c to SSI mode, disable SCI

BSET #M_HCIE,X:M_HCR ;enable host command data interrupts

ANDI #$FC,MR ;enable interrupts ie set interrupt level to 0

;remember, reseting and loading code into the card

;starts you our at level 3 so you can set up the I/O

;stuff.

ORI #$FF,OMR ;set to mode 0 and set DE = 0 to disable use of ROM table

; ANDI #$0C,OMR ;

ANDI #$08,OMR ;

WtHost WAIT ;wait for mac/host to say start

JMP WtHost

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

;

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

hcOutputWave

BSET #M_HF3,X:M_HCR ;set HF3 to 1 to let host know code is running

BCLR #M_OF0,X:M_CRB ;OF0 = 0 external clock, OF0 = 1 internal clock

BCLR #M_OF1,X:M_CRB

BCLR #M_SCD0,X:M_CRB ;SCD0,SCD1,SCD2 must be set to 1

BSET #M_SCD1,X:M_CRB ;

BSET #M_SCD2,X:M_CRB ;

BCLR #M_SCKD,X:M_CRB ;SCKD = 0 external clock, SCKD = 1 internal clock

BSET #M_FSL,X:M_CRB

BSET #M_SYN,X:M_CRB

BCLR #M_GCK,X:M_CRB

BCLR #M_MOD,X:M_CRB

BSET #M_STE,X:M_CRB

BCLR #M_SRE,X:M_CRB

; BCLR #M_STIE,X:M_CRB

BCLR #M_SRIE,X:M_CRB

;Start of algorithm

CLR A

MOVE A0,Y:OUTPUT ;clear the output register

MOVE X:SINE_TABLE_START,A0

MOVE A0,X:CARRIER1_PHASE

MOVE X:SINE_TABLE_START,A0

MOVE A0,X:MODULATOR1_PHASE

MOVE X:SINE_TABLE_START,A0

MOVE A0,X:CARRIER2_PHASE

MOVE X:SINE_TABLE_START,A0

MOVE A0,X:MODULATOR2_PHASE

MOVE X:EXP_TABLE_START,A0

CLR B

MOVE X:EXP_TABLE_SIZE,B0

ASR B

ADD B,A

MOVE A0,X:EXP1_PHASE

MOVE A0,X:EXP2_PHASE

BSET #M_STIE,X:M_CRB ;switch DAC on

DO X:CYCLE_A,_EndCycle_A

DO X:CYCLE_B,_EndCycle_B

;

; For First AFM operator

;

MOVE X:ONE,N1

MOVE X:IR1_PLUS,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:IR1_PLUS

MOVE X:ONE,N1

MOVE X:IR1_MINUS,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:IR1_MINUS

MOVE X:ONE,N1

MOVE X:MODULATION1_INDEX,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:MODULATION1_INDEX

; CLR A

; MOVE X:RATIO1,A0

; MOVE #1,X0

; ADD X0,A

; MOVE A0,X:RATIO1

; CLR A

; MOVE X:NORMALIZATION1,A0

; MOVE #1,X0

; ADD X0,A

; MOVE A0,X:NORMALIZATION1

MOVE X:ONE,N1

MOVE X:AMP1,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:AMP1

;

; For Second AFM operator

;

MOVE X:ONE,N1

MOVE X:IR2_PLUS,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:IR2_PLUS

MOVE X:ONE,N1

MOVE X:IR2_MINUS,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:IR2_MINUS

MOVE X:ONE,N1

MOVE X:MODULATION2_INDEX,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:MODULATION2_INDEX

; CLR A

; MOVE X:RATIO2,A0

; MOVE #1,X0

; ADD X0,A

; MOVE A0,X:RATIO2

; CLR A

; MOVE X:NORMALIZATION2,A0

; MOVE #1,X0

; ADD X0,A

; MOVE A0,X:NORMALIZATION2

MOVE X:ONE,N1

MOVE X:AMP2,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:AMP2

MOVE X:ONE,N1

MOVE X:ENVELOPE,R1

NOP

LUA (R1)+N1,R2

NOP

MOVE R2,X:ENVELOPE

DO X:CYCLE_C,_EndCycle_C

.IF X:CARRIER1_PHASE <GT> X:SINE_TABLE_END

MOVE X:CARRIER1_PHASE,A0

MOVE X:SINE_TABLE_SIZE,B0

SUB B,A

MOVE A0,X:CARRIER1_PHASE

NOP

.ENDI

.IF X:MODULATOR1_PHASE <GT> X:SINE_TABLE_END

MOVE X:MODULATOR1_PHASE,A0

MOVE X:SINE_TABLE_SIZE,B0

SUB B,A

MOVE A0,X:MODULATOR1_PHASE

NOP

.ENDI

.IF X:CARRIER2_PHASE <GT> X:SINE_TABLE_END

MOVE X:CARRIER2_PHASE,A0

MOVE X:SINE_TABLE_SIZE,B0

SUB B,A

MOVE A0,X:CARRIER2_PHASE

NOP

.ENDI

.IF X:MODULATOR2_PHASE <GT> X:SINE_TABLE_END

MOVE X:MODULATOR2_PHASE,A0

MOVE X:SINE_TABLE_SIZE,B0

SUB B,A

MOVE A0,X:MODULATOR2_PHASE

NOP

.ENDI

;First AFM Operator

MOVE X:MODULATOR1_FREQ,N2

MOVE X:MODULATOR1_PHASE,R2

MOVE X:MODULATOR1_PHASE,A0

MOVE X:SINE_COSINE_OFFSET,B0

ADD B,A

MOVE A0,X:COSINE_PHASE

; MOVE X:IR1_PLUS,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:IR1_PLUS,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MOVE Y:(R2)+N2,X0

MPY X0,Y0,A ;A = (I/2) * (r + 1/r) * sin(Wm*t)

MOVE A1,N0

MOVE X:CARRIER1_PHASE,R1

MOVE X:CARRIER1_FREQ,N1

MOVE R1,R0

MOVE R2,X:MODULATOR1_PHASE

LUA (R0)+N0,R0

LUA (R1)+N1,R1

MOVE Y:(R0),A0

MOVE R1,X:CARRIER1_PHASE

MOVE A0,X:TEMP_A ;TEMP_A = sin(Wc*t + (I/2) * (r + 1/r) * sin(Wm*t))

;;;;

MOVE X:COSINE_PHASE,R2

; MOVE X:IR1_MINUS,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:IR1_MINUS,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MOVE Y:(R2),X0

MPY X0,Y0,A

MOVE A1,X:TEMP_B ;TEMP_B = (I/2) * (r - 1/r) * cos(Wm*t)

CLR A

MOVE X:TEMP_B,A0

; REP #12

; ASL A

;; MOVE #0,A0

CLR B

MOVE X:EXP1_PHASE,B0

; MOVE X:EXP_TABLE_START,B0

ADD B,A

MOVE A0,R0

MOVE X:TEMP_A,Y0

MOVE X:(R0),X0

MPY Y0,X0,A

MOVE A1,X:TEMP_C

;Second AFM Operator

MOVE X:MODULATOR2_FREQ,N2

MOVE X:MODULATOR2_PHASE,R2

MOVE X:MODULATOR2_PHASE,A0

MOVE X:SINE_COSINE_OFFSET,B0

ADD B,A

MOVE A0,X:COSINE_PHASE

; MOVE X:IR2_PLUS,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:IR2_PLUS,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MOVE Y:(R2)+N2,X0

MPY X0,Y0,A ;A = (I/2) * (r + 1/r) * sin(Wm*t)

MOVE A1,N0

MOVE X:CARRIER2_PHASE,R1

MOVE X:CARRIER2_FREQ,N1

MOVE R1,R0

MOVE R2,X:MODULATOR2_PHASE

LUA (R0)+N0,R0

LUA (R1)+N1,R1

MOVE Y:(R0),A0

MOVE R1,X:CARRIER2_PHASE

MOVE A0,X:TEMP_A ;TEMP_A = sin(Wc*t + (I/2) * (r + 1/r) * sin(Wm*t))

;;;;

MOVE X:COSINE_PHASE,R2

; MOVE X:IR2_MINUS,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:IR2_MINUS,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MOVE Y:(R2),X0

MPY X0,Y0,A

MOVE A1,X:TEMP_B ;TEMP_B = (I/2) * (r - 1/r) * cos(Wm*t)

CLR A

MOVE X:TEMP_B,A0

; REP #12

; ASL A

;; MOVE #0,A0

CLR B

MOVE X:EXP2_PHASE,B0

; MOVE X:EXP_TABLE_START,B0

ADD B,A

MOVE A0,R0

MOVE X:TEMP_A,Y0

MOVE X:(R0),X0

MPY Y0,X0,A

MOVE A1,X:TEMP_D

MOVE X:TEMP_C,X0

; MOVE X:AMP1,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:AMP1,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MPY X0,Y0,A

MOVE A0,X:TEMP_C

MOVE X:TEMP_D,X0

; MOVE X:AMP2,Y0 ;==

MOVE X:ZERO,N3 ;

MOVE X:AMP2,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MPY X0,Y0,A

MOVE A0,X:TEMP_D

CLR A

CLR B

MOVE X:TEMP_C,A0

MOVE X:TEMP_D,B0

ADD B,A

MOVE X:ZERO,N3 ;

MOVE X:ENVELOPE,R3 ;

NOP ;

MOVE X:(R3)+N3,Y0 ;

MOVE A0,X:TEMP_A

MOVE X:TEMP_A,X0

MPY X0,Y0,A

NOP

NOP

MOVE A0,Y:OUTPUT

DO X:DELAY,_EndDelay

NOP

_EndDelay

NOP ;needed because addresses between "end of do loops" cannot be less than 2

_EndCycle_C

NOP

_EndCycle_B

NOP

_EndCycle_A

nolist

BCLR #M_STIE,X:M_CRB ;switch DAC off

BCLR #M_HF3,X:M_HCR ;clear HF3 to let host know end of code running

RTI

nolist

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

;SSI transmit data

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

TxInterrupt

JSET #M_HF3,X:M_HCR,Playing ;see if we think we are playing

MOVEP #0,X:M_TX ;play a zero

RTI

Playing

MOVEP Y:OUTPUT,X:M_TX ;send the sample to SSI port (DAC)

JCLR #1,X:M_PCD,Done ;if we just played a right sample

Done RTI

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

;Handle a SSI transmit interrupt with underrun exception - tell Mac via HREQ interrupts

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

SSIException

BTST #4,X:M_SR ;read SSI SR to clear TUE bit

MOVEP Y:OUTPUT,X:M_TX ;transmit data to DAC (also needed to clear TUE)

RTI

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

;Interrupt to receive data from host to specific locations of X or Y memory

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

RxDataInterrupt

LoopRxa JCLR #M_HRDF,X:M_HSR,LoopRxa ;wait till MAC has sent the address over

MOVEP X:M_HRX,X0 ;read the xySelect into X0

LoopRxb JCLR #M_HRDF,X:M_HSR,LoopRxb ;wait till MAC has sent the address over

MOVEP X:M_HRX,R0 ;read the xyAddress into R0

LoopRxc JCLR #M_HRDF,X:M_HSR,LoopRxc ;wait till MAC has sent the value over

MOVEP X:M_HRX,Y0 ;read the xyValue into Y0

CLR B

ADD X0,B

JNE RxY

RxX MOVE Y0,X:(R0) ;put value into specified location in X memory

RTI

RxY MOVE Y0,Y:(R0) ;put value into specified location in Y memory

RTI

END