; Code for generating Frequency Control Word for AD9850 and AD9851
;
; R. Weaver, 2017-08-01
;
; Assembler directives to allow for different reference frequencies
; #define RefOsc180MHz ;Comment out this line for 125MHz reference osc (AD9850)
#define LeftShifts 1 ; Set this value according to the following table:
; Ref Osc Freq LeftShifts
; ------------ ----------
; 19-37 MHz 3
; 38-75 MHz 2
; 76-150 MHz 1
; 151-200 MHz 0
;
; ****
; Note that for a reference frequency other than 125 or 180 MHz
; Changes must be made to the lookup table code.
; ****
;Macro definitions
bank0 macro
bcf STATUS,RP0
endm
bank1 macro
bsf STATUS,RP0
endm
;More intuitive skip definitions
skpeq macro
btfss status,z
endm
skpneq macro
btfsc status,z
endm
skpneg macro
btfsc status,c
endm
skppos macro
btfss status,c
endm
SaveAccHi macro rName ;Store 4 high bytes of acc to spec'd register set
movlw rName
call SaveAccHiInd
endm
SaveAccLo macro rName ;Store 4 low bytes of acc to spec'd register set
movlw rName
call SaveAccLoInd
endm
LoadAccHi macro rName ;Load 4 high bytes of acc from spec'd register set
movlw rName
call LoadAccHiInd
endm
LoadAccLo macro rName ;Load 4 low bytes of acc from spec'd register set
movlw rName
call LoadAccLoInd
endm
LoadRLo macro rName ;Load 4 low bytes of aux reg from spec'd register set
movlw rName
call LoadRxLoInd
endm
LoadRHi macro rName ;Load 4 high bytes of aux reg from spec'd register set
movlw rName
call LoadRxHiInd
endm
ClearNregisters macro nReg, rName ;Clear nReg registers starting at rName
movlw nReg
movwf xfrCount
movlw rName
call ClearNregistersInd
endm
ShiftUpNregisters macro nReg, rName ;Shift nReg registers starting at rName
movlw nReg
movwf xfrCount
movlw rName
call ShiftUpNregistersInd
endm
;
;variable memory area
cblock 0x20
; DDS variables:
freqDigits:8 ;8 digit (decimal) frequency in Hz, F(0) is LSB, F(7) is MSB
; Math Library variables
acc0,acc1,acc2,acc3,acc4,acc5,acc6,acc7 ;accumulator for 32/64 bit math
R0,R1,R2,R3,R4,R5,R6,R7 ; 32/64 bit math aux. registers
; misc temporary registers
count,temp
xfrCount ;used to count registers moved by the load, save & clear routines
endc
;Lookup tables for DDS frequency ctrl word
#ifdef RefOsc180MHz ;Lookup tables for 180MHz ref frequency
Mpy_B0 ;Least significant byte
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0xE1
retlw 0xC1
retlw 0xA2
retlw 0x82
retlw 0x63
retlw 0x44
retlw 0x24
retlw 0x05
retlw 0xE5
Mpy_B1
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0xDE
retlw 0xBD
retlw 0x9C
retlw 0x7B
retlw 0x5A
retlw 0x39
retlw 0x18
retlw 0xF7
retlw 0xD5
Mpy_B2
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x65
retlw 0xCB
retlw 0x31
retlw 0x97
retlw 0xFD
retlw 0x63
retlw 0xC9
retlw 0x2E
retlw 0x94
Mpy_B3
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0xDC
retlw 0xB8
retlw 0x95
retlw 0x71
retlw 0x4D
retlw 0x2A
retlw 0x06
retlw 0xE3
retlw 0xBF
Mpy_B4 ;Most significant byte
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x17
retlw 0x2F
retlw 0x47
retlw 0x5F
retlw 0x77
retlw 0x8F
retlw 0xA7
retlw 0xBE
retlw 0xD6
#else ;Lookup tables for 125 MHz reference oscillator
Mpy_B0 ;Least significant byte
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x27
retlw 0x4E
retlw 0x75
retlw 0x9B
retlw 0xC2
retlw 0xE9
retlw 0x10
retlw 0x37
retlw 0x5E
Mpy_B1
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0xE8
retlw 0xD0
retlw 0xB8
retlw 0xA0
retlw 0x88
retlw 0x70
retlw 0x59
retlw 0x41
retlw 0x29
Mpy_B2
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x0B
retlw 0x17
retlw 0x23
retlw 0x2F
retlw 0x3B
retlw 0x47
retlw 0x53
retlw 0x5F
retlw 0x6B
Mpy_B3
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x2E
retlw 0x5C
retlw 0x8A
retlw 0xB8
retlw 0xE6
retlw 0x14
retlw 0x42
retlw 0x70
retlw 0x9E
Mpy_B4 ;Most significant byte
andlw 0x0F
addwf pcl,f
retlw 0x00
retlw 0x11
retlw 0x22
retlw 0x33
retlw 0x44
retlw 0x55
retlw 0x67
retlw 0x78
retlw 0x89
retlw 0x9A
#endif
;
;
;
MakeCtlWd ;Generate DDS frequency control word
call clrAcc64 ; Init the acc to zero
movlw freqDigits+7 ;load addr of frequency digits array
MakeWdEntry
movwf FSR ; and store in indirect ptr reg
movlw 0x08 ; load count of digits
movwf count
; call clrAcc64 ; Init the acc to zero
goto LoopMCWenter ;skip the x10 for the 1st digit
LoopMCW
call AccTimes10
LoopMCWenter
movf indf,w
call AddDigit
decf fsr,f
decfsz count,f
goto LoopMCW
;
;All digits have been processed.
;If Ref freq is 150MHz or lower then do left shift here
;
if LeftShifts != 0
movlw LeftShifts
call AccLShiftN
endif
btfsc acc3,7 ; Check fractional part to see if round up is req'd
incfsz acc4,f ;Yes, so increment integer part, and propagate carries.
goto MCWshiftWord
incfsz acc5,f
goto MCWshiftWord
incfsz acc6,f
goto MCWshiftWord
incf acc7,f
MCWshiftWord ;move the result from acc4..acc7 to acc0..acc3
LoadAccLo acc4
return ;Frequency/sweep Control Word is in acc0..acc3
AddDigit ; Add next frequency digit to acc and mpy by 10
movwf temp
call mpy_B0
movwf R0
movf temp,w
call mpy_B1
movwf R1
movf temp,w
call mpy_B2
movwf R2
movf temp,w
call mpy_B3
movwf R3
movf temp,w
call mpy_B4
movwf R4
clrf R5
clrf R6
clrf R7
call Add64
return
AccTimes10 ;Multiply acc x 10
;copy acc to aux reg.
call AccToR ;move acc contents to aux reg
movlw 0x02
call accLShiftN ;Shift left twice to get x4
call Add64 ; add the saved value back to the acc to get x5
movlw 0x01
call accLShiftN ;shift left once more to get x10
return
AccLShiftN ;Shift acc left N times where N is in Wreg
movwf count1
LoopALSN
bcf status,c
rlf acc0,f
rlf acc1,f
rlf acc2,f
rlf acc3,f
rlf acc4,f
rlf acc5,f
rlf acc6,f
rlf acc7,f
decfsz count1,f
goto LoopALSN
return
;
;Start of general purpose multi-byte math routines
;
clrAcc64 ;clear 64 bit accumulator registers acc and r
ClearNregisters d'16',acc0
return
SaveAccHiInd ; Save high 4 bytes of acc to reg indirect
movwf fsr ;start address is in w
movf acc4,w
movwf indf
movf acc5,w
incf fsr,f
movwf indf
movf acc6,w
incf fsr,f
movwf indf
movf acc7,w
incf fsr,f
movwf indf
return
SaveAccLoInd ; Save low 4 bytes of acc to reg indirect
movwf fsr ;start address is in w
movf acc0,w
movwf indf
movf acc1,w
incf fsr,f
movwf indf
movf acc2,w
incf fsr,f
movwf indf
movf acc3,w
incf fsr,f
movwf indf
return
LoadAccHiInd ; Load high 4 bytes of acc from reg indirect
movwf fsr ;start address is in w
movf indf,w
movwf acc4
incf fsr,f
movf indf,w
movwf acc5
incf fsr,f
movf indf,w
movwf acc6
incf fsr,f
movf indf,w
movwf acc7
return
LoadAccLoInd ; Load low 4 bytes of acc from reg indirect
movwf fsr ;start address is in w
movf indf,w
movwf acc0
incf fsr,f
movf indf,w
movwf acc1
incf fsr,f
movf indf,w
movwf acc2
incf fsr,f
movf indf,w
movwf acc3
return
LoadRxLoInd ; Load low 4 bytes of aux reg r0 from reg indirect
movwf fsr ;start address is in w
movf indf,w
movwf r0
incf fsr,f
movf indf,w
movwf r1
incf fsr,f
movf indf,w
movwf r2
incf fsr,f
movf indf,w
movwf r3
return
LoadRxHiInd ; Load low 4 bytes of aux reg r0 from reg indirect
movwf fsr ;start address is in w
movf indf,w
movwf r4
incf fsr,f
movf indf,w
movwf r5
incf fsr,f
movf indf,w
movwf r6
incf fsr,f
movf indf,w
movwf r7
return
ClearNregistersInd
;Clear specified number of contiguous registers where number is in xfrCount
;and start register address is in w
movwf fsr
LoopCNRI
clrf indf
incf fsr
decfsz xfrCount,f
goto LoopCNRI
return
ShiftUpNregistersInd
;Shift bytes up across N registers
;highest register is in w
movwf fsr
LoopSUNRI
decf fsr,f
movf indf,w
incf fsr,f
movwf indf
decf fsr,f
decfsz xfrCount,f
goto LoopSUNRI
return
AccToR ;move acc contents to aux reg.
;No indirects here, so that calling code can use FSR without it
;getting corrupted here.
movf acc0,w
movwf R0
movf acc1,w
movwf R1
movf acc2,w
movwf R2
movf acc3,w
movwf R3
movf acc4,w
movwf R4
movf acc5,w
movwf R5
movf acc6,w
movwf R6
movf acc7,w
movwf R7
return
add32 ;32 bit add routine
movf R0,w
addwf acc0,f
btfsc status,c
call carry1
movf R1,w
addwf acc1,f
btfsc status,c
call carry2
movf R2,w
addwf acc2,f
btfsc status,c
incf acc3,f
movf R3,w
addwf acc3,f
return
neg32 ;Negate the accumulator
comf acc0,f
comf acc1,f
comf acc2,f
comf acc3,f
incfsz acc0,f ;increment and check for carry
return ;no carry, so return
carry1
incfsz acc1,f
return
carry2
incfsz acc2,f
return
incf acc3,f
return
add64 ;64 bit add routine
movf R0,w
addwf acc0,f
btfsc status,c
call carry64_1
movf R1,w
addwf acc1,f
btfsc status,c
call carry64_2
movf R2,w
addwf acc2,f
btfsc status,c
call carry64_3
add40 ;Entry point for 40 bit add
movf R3,w
addwf acc3,f
btfsc status,c
call carry64_4
movf R4,w
addwf acc4,f
btfsc status,c
call carry64_5
movf R5,w
addwf acc5,f
btfsc status,c
call carry64_6
movf R6,w
addwf acc6,f
btfsc status,c
incf acc7,f
movf R7,w
addwf acc7,f
return
carry64_1 ;Chained skips to propagate carries
incfsz acc1,f
return
carry64_2
incfsz acc2,f
return
carry64_3
incfsz acc3,f
return
carry64_4
incfsz acc4,f
return
carry64_5
incfsz acc5,f
return
carry64_6
incfsz acc6,f
return
incf acc7,f
return
NegDecimal ; Negate 8-digit unpacked decimal number in acc0..7
movlw 0x08
movwf count
movlw acc0
movwf fsr
LoopND
movf indf,w
sublw 0x09
movwf indf
incf fsr,f
decfsz count
goto LoopND
;Acc now contains nines complement. Now increment to get tens complement
ClearNregisters 8,r0
incf r0,f
;continue to AddDecimal to
AddDecimal ; Eight digit unpacked BCD add; operands in acc0..7 and r0..7
call Add64 ; add the two 8-digit numbers
;fsr indf
;Now adjust digits for carry
LoopAD2
movlw 0xF6
movwf r0
movwf r1
movwf r2
movwf r3
movwf r4
movwf r5
movwf r6
movwf r7
;new code
movlw acc0
movwf fsr
movlw 0x08
movwf count
LoopAD1
movf indf,w
sublw 0x09
rrf temp,f ; save carry bit
incf fsr,f
decfsz count,f
goto LoopAD1
comf temp,f ;
btfsc status,z
return ;no adjustment required
movlw r0
movwf fsr
movlw 0x08
movwf count
LoopAD3
rrf temp,f
btfss status,c
clrf indf
incf fsr
decfsz count,f
goto LoopAD3
call Add64
goto LoopAD2