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