movf T2L,w ;
subwf T1L,f ;
movf T2H,w ;
subwfb T1H,f ;
nop
movf T2L,w ;
subwf T1L,w
movwf T3L ;
movf T2H,w ;
subwfb T1H,w ;
movwf T3H
nop
;Author: ©JPANHALT
;Date: May 22,2016
list p=16f1829 ; list directive to define processor
#include <p16f1829.inc> ; processor specific variable definitions
errorlevel -302,-305
RADIX DEC
__CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
cblock 0x20
T1U
T1H
T1L
T2U
T2H
T2L
count
resultL
resultH
endc
org 0x0000
goto Start
Start
;T1(24bit)/T2(16bit)
movlw high(881)
movwf T2H
movlw low(881)
movwf T2L
call Refresh
clrf count
clrf T2U
clrf resultL
clrf resultH
nop
Kenyan
incf count,f
movf T2L,w
subwf T1L,f
movf T2H,w
subwfb T1H,f
movf T2U,w
subwfb T1U,f
btfss STATUS,0
goto Calculate
lslf T2L
rlf T2H
rlf T2U
goto Kenyan
Calculate
call Refresh
Cycle
;T1 registers are destroyed during subtraction. When the subtrahend is too
;big, which results in a zero being rotated into the result, those registers
;must be recovered. Back-up registers can be used; however, several steps are
;required to restore them. Doing a trial subtraction and preserving the
;minuend registers was slightly faster.
movf T2L,w
subwf T1L,w
movf T2H,w
subwfb T1H,w
movf T2U,w
subwfb T1U,w
btfss STATUS,0 ;subtrahend too big divide by 2 and repeat
goto Result
movf T2L,w ;subtractand OK, repeat subtraction w/saves in f
subwf T1L,f
movf T2H,w
subwfb T1H,f
movf T2U,w
subwfb T1U,f ;carry will be set
Result
rlf resultL,f ;carry bit is set or clear correctly from above
rlf resultH,f
decfsz count,f
goto DivideT2
goto Finish
DivideT2
lsrf T2U
rrf T2H
rrf T2L
goto Cycle
Finish
nop ;answer in resultH and resultL
;Subroutine
Refresh
movlw upper(55536) ;(673312)
movwf T1U
movlw high(55536) ;(673312)
movwf T1H
movlw low(55536) ;(673312)
movwf T1L
return
end
; 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
No. Actually in the simplest version of the algorithm, the lookup table is simply the values of 2^32/FREF multiplied by the digits 0-9. If we refer to the value 2^32/FREF as constant k, and the tuning control word as W, then:Bob, is the lookup table working the same way it does when you do trig using the cordic method.
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
You got there just in the nick of time. I think I only had that page up for a couple of weeks before I rewrote the PIC program so that it no longer needed lookup tables. Since the tables were gone, I removed the link to the spreadsheet file. Maybe I should put it back again.I found your website...
; take 1234 from 4321
TEST
banksel val1
pagesel TEST
movlw 0x43
movwf val1+1
movlw 0x21
movwf val1
movlw 0x12
movwf val2+1
movlw 0x34
movwf val2
movlw 0x99 ; convert BCD to 9's complement
movwf temp
movfw val1
subwf temp,w
movwf val1
movfw val1+1
subwf temp,w
movwf val1+1
movfw val1
addwf val2,w
subwf temp,w
movwf val1 ; val1 ends up with result
clrw
btfss STATUS,DC
movlw 0x06 ; low digit adjust
btfsc STATUS,C
goto NEXT1
incf val1+1,f ; borrow from next digit, is add because took from 9
iorlw 0x60 ; high digit adjust
NEXT1
subwf val1,f ; apply adjust
movfw val1+1
addwf val2+1,w
subwf temp,w
movwf val1+1
clrw
btfss STATUS,DC
movlw 0x06
btfsc STATUS,C
goto NEXT2
incf val1+2,f
iorlw 0x60
NEXT2
subwf val1+1,f
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?