2 \ see CORDICforDummies.pdf
6 \ compile FAST-FORTH with at least these options: ASSEMBLER, CONDCOMP, FIXPOINT_INPUT, LOWERCASE.
8 \ TARGET Current Selection (used by preprocessor GEMA to load the pattern: \config\gema\TARGET.pat)
9 \ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989
10 \ MSP_EXP430FR2433 MSP_EXP430FR2355 CHIPSTICK_FR2433
12 [DEFINED] {CORDIC} [IF] {CORDIC} [THEN] \ remove {CORDIC}
16 [UNDEFINED] {FIXPOINT} [IF] \ define words to display angle as Q15.16 number.
18 \ https://forth-standard.org/standard/core/HOLDS
19 \ Adds the string represented by addr u to the pictured numeric output string
20 \ compilation use: <# S" string" HOLDS #>
21 \ free chars area in the 32+2 bytes HOLD buffer sized for a 32 bits {hexa,decimal,binary} number = {26,23,2}.
22 \ (2 supplementary bytes are room for sign - and decimal point)
28 BEGIN SUB #1,X \ 1 src-1
30 U>= WHILE SUB #1,Y \ 1 dst-1
34 MOV @IP+,PC \ 4 15 words
37 \ F#S Qlo Qhi u -- Qhi 0 convert fractionnal part of Q15.16 fixed point number with u digits
39 MOV 2(PSP),X \ -- Qlo Qhi u X = Qlo
40 MOV @PSP,2(PSP) \ -- Qhi Qhi u
41 MOV X,0(PSP) \ -- Qhi Qlo u
44 BEGIN MOV @PSP,&MPY \ Load 1st operand
45 MOV &BASE,&OP2 \ Load 2nd operand
46 MOV &RES0,0(PSP) \ -- Qhi RESlo x low result on stack
47 MOV &RES1,TOS \ -- Qhi RESlo REShi high result in TOS
48 CMP #10,TOS \ digit to char
51 MOV.B TOS,HOLDS_ORG(S) \ -- Qhi RESlo char char to string
53 CMP T,S \ count=limit ?
54 0= UNTIL MOV #0,0(PSP) \ -- Qhi 0 REShi
55 MOV T,TOS \ -- Qhi 0 limit
56 SUB #2,PSP \ -- Qhi 0 x len
57 MOV #HOLDS_ORG,0(PSP) \ -- Qhi 0 addr len
61 CODE F. \ display a Q15.16 number with 4/5/16 digits after comma
63 MOV #4,T \ T = 4 preset 4 digits for base 16 and by default
67 ADD #1,T \ T = 5 set 5 digits
71 MOV #16,T \ T = 16 set 16 digits
74 PUSHM #3,IP \ R-- IP sign #digit
76 <# DABS \ -- uQlo uQhi R-- IP sign #digit
77 R> F#S \ -- uQhi 0 R-- IP sign
78 $2C HOLD \ $2C = char ','
80 R> SIGN #> \ -- addr len R-- IP
84 [THEN] \ end of [UNDEFINED] {FIXPOINT}
87 \ OPERATION | MODE | INITIALIZE x y z | DIRECTION | RESULT | post operation
88 \ --------------|-----------|-----------------------|---------------|-------------------|
89 \ sine, cosine | Rotation | x=1, y=0, z=angle | Reduce z to 0 | cos=x*Gi,sin=y*Gi | mutiply by 1/Gi
90 \ --------------|-----------|-----------------------|---------------|-------------------|
91 \ Polar to Rect | Rotation | x=magnit, y=0, Z=angle| Reduce z to 0 | X=x*Gi, Y=y*Gi | mutiply by 1/Gi
92 \ --------------|-----------|-----------------------|---------------|-------------------|
93 \ Rotation | Rotation | x=X, y=Y, z=angle | Reduce z to 0 | X'=x*Gi,Y'=y*Gi | <=== not implemented
94 \ --------------|-----------|-----------------------|---------------|-------------------|
95 \ Rect to Polar | Vector | x=X, y=Y, z=0 | Reduce y to 0 | hyp=x*Gi, angle=z | mutiply hyp by 1/Gi
96 \ --------------|-----------|-----------------------|---------------|-------------------|
97 \ Gi = CORDIC gain for i iterations; Gi < 1
100 CREATE T_ARCTAN \ ArcTan table
102 6801 , \ 256 * 26.565
103 3593 , \ 256 * 14.036
117 CREATE T_SCALE \ 1/Gi table
118 46340 , \ = 65536 * cos(45)
119 41448 , \ = 65536 * cos(45) * cos(26.565)
120 40211 , \ = 65536 * cos(45) * cos(26.565) * cos(14.036)
121 39900 , \ = 65536 * cos(45) * cos(26.565) * cos(14.036) * ...
135 CODE POL2REC \ u f -- X Y
136 \ input ; u = module {1000...16384}, f = angle (15Q16 number) in degrees {1,0...89,0}
138 \ TOS = fhi, 0(PSP) = flo, 2(PSP) = u
139 PUSH IP \ save IP before use
140 MOV @PSP+,Y \ Y = flo
145 BIS Y,TOS \ -- module angle*256
146 \ =====================
147 \ CORDIC 16 bits engine
148 \ =====================
149 MOV #-1,IP \ IP = i-1
152 BEGIN \ i loops with init i = 0
154 MOV X,S \ S = Xi to be right shifted
155 MOV Y,T \ T = Yi to be right shifted
162 FW1 CMP IP,W \ W = i ?
163 0= UNTIL \ loop back if W < i
164 ADD W,W \ W = 2i = T_SCALE displacement
166 0>= IF \ TOS >= 0 : Rotate clockwise
167 SUB T,X \ Xi+1 = Xi - ( Yi >> i)
168 ADD S,Y \ Yi+1 = Yi + ( Xi >> i)
170 ELSE \ TOS < 0 : Rotate counter-clockwise
171 ADD T,X \ Xi+1 = Xi + ( Yi >> i)
172 SUB S,Y \ Yi+1 = Yi - ( Xi >> i)
175 CMP #0,TOS \ if angle*256 = 0 quit loop
176 0<> WHILE \ search "Extended control-flow patterns" in https://forth-standard.org/standard/rationale
179 THEN \ search "Extended control-flow patterns" in https://forth-standard.org/standard/rationale
180 \ multiply cos by factor scale
181 MOV X,&MPY \ 3 Load 1st operand
182 MOV T_SCALE(W),&OP2 \ 3 Load 2nd operand
183 MOV &RES1,0(PSP) \ 3 hi result = cos
184 \ multiply sin by factor scale
185 MOV Y,&MPY \ 3 Load 1st operand
186 MOV T_SCALE(W),&OP2 \ 3 Load 2nd operand
187 MOV &RES1,TOS \ 3 hi result = sin
189 \ endof CORDIC engine \ X = cos, Y = sin
196 10000 89,0 POL2REC . . ; sin, cos -->
197 10000 75,0 POL2REC . . ; sin, cos -->
198 10000 60,0 POL2REC . . ; sin, cos -->
199 10000 45,0 POL2REC . . ; sin, cos -->
200 10000 30,0 POL2REC . . ; sin, cos -->
201 10000 15,0 POL2REC . . ; sin, cos -->
202 10000 1,0 POL2REC . . ; sin, cos -->
203 \ module phase -- X Y
204 16384 30,0 POL2REC SWAP . . ; x, y -->
205 16384 45,0 POL2REC SWAP . . ; x, y -->
206 16384 60,0 POL2REC SWAP . . ; x, y -->
211 \ REC2POL version with inputs scaling, to increase the accuracy of the angle:
213 \ input : X < 16384, |Y| < 16384
214 \ output ; u = hypothenuse, f = angle (15Q16 number) in degrees
215 \ rounded hypothenuse, 1 mn accuracy angle
216 CODE REC2POL \ X Y -- u f
219 \ normalize X Y to 16384 maxi
220 \ 1- calculate T = |Y|
227 \ 2- abort if null inputs
228 MOV #-1,TOS \ set TOS TRUE for the two ABORT" below
236 \ 3- select max of X,|Y|
241 \ 4- abort if X or |Y| >= 16384
245 ABORT" x or |y| >= 16384"
248 \ 5- multiply inputs by 2^n scale factor
249 MOV #1,S \ init scale factor
250 RLAM #3,T \ test bit 2^13
255 ADD S,S \ scale factor *2
256 ADD T,T \ to test next bit 2^(n-1)
258 U>= UNTIL \ until carry set
259 \ 6- save IP and scale factor n
260 PUSHM #2,IP \ push IP,S
264 MOV #-1,IP \ IP = i-1, X = Xi, Y = Yi
265 MOV #0,TOS \ init z=0
266 BEGIN \ i loops with init: i = 0
268 MOV X,S \ S = Xi to be right shifted
269 MOV Y,T \ T = Yi to be right shifted
270 MOV #0,W \ W = right shift loop count
276 FW1 CMP IP,W \ W = i ?
278 ADD W,W \ W = 2i = T_SCALE displacement
280 0>= IF \ Y >= 0 : Rotate counter-clockwise
281 ADD T,X \ Xi+1 = Xi + ( Yi >> i)
282 SUB S,Y \ Yi+1 = Yi - ( Xi >> i)
284 ELSE \ Y < 0 : Rotate clockwise
285 SUB T,X \ Xi+1 = Xi - ( Yi >> i)
286 ADD S,Y \ Yi+1 = Yi + ( Xi >> i)
289 CMP #0,Y \ if Y = 0 quit loop
290 0<> WHILE \ if Y = 0 goto THEN
294 \ multiply x by CORDIC gain
295 MOV X,&MPY \ 3 Load 1st operand
296 MOV T_SCALE(W),&OP2 \ 3 CORDIC Gain * 65536
297 MOV &RES1,X \ 3 hi result = hypothenuse
299 \ endof CORDIC engine \ X = hypothenuse, TOS = 256*angle
301 \ divide x by scale factor
302 POPM #2,IP \ S = scale factor, restore IP
305 RRA X \ divide x by 2
306 FW1 RRA S \ shift right scale factor
307 U>= UNTIL \ until carry set
309 \ multiply z by 256 to display it as a Q15.16 number
310 MOV TOS,Y \ Y = future fractional part of f
313 SXT TOS \ integer part of f
317 MOV Y,0(PSP) \ fractional part of f
323 2 1 REC2POL F. . ; phase module -->
324 2 -1 REC2POL F. . ; phase module -->
325 20 10 REC2POL F. . ; phase module -->
326 20 -10 REC2POL F. . ; phase module -->
327 200 100 REC2POL F. . ; phase module -->
328 100 -100 REC2POL F. . ; phase module -->
329 2000 1000 REC2POL F. . ; phase module -->
330 1000 -1000 REC2POL F. . ; phase module -->
331 16000 8000 REC2POL F. . ; phase module -->
332 16000 -8000 REC2POL F. . ; phase module -->
333 16000 0 REC2POL F. . ; phase module -->
334 0 16000 REC2POL F. . ; phase module -->
335 \16384 -8192 REC2POL F. . ; --> abort
336 \0 0 REC2POL F. . ; --> abort
339 10000 89,0 POL2REC REC2POL ROT . F.
340 10000 75,0 POL2REC REC2POL ROT . F.
341 10000 60,0 POL2REC REC2POL ROT . F.
342 10000 45,0 POL2REC REC2POL ROT . F.
343 10000 30,0 POL2REC REC2POL ROT . F.
344 10000 26,565 POL2REC REC2POL ROT . F.
345 10000 15,0 POL2REC REC2POL ROT . F.
346 10000 14,036 POL2REC REC2POL ROT . F.
347 10000 7,125 POL2REC REC2POL ROT . F.
348 10000 1,0 POL2REC REC2POL ROT . F.
352 POL2REC REC2POL \ 1000 loops
356 10000 89,0 2000CORDIC ROT . F.
357 10000 75,0 2000CORDIC ROT . F.
358 10000 60,0 2000CORDIC ROT . F.
359 10000 45,0 2000CORDIC ROT . F.
360 10000 30,0 2000CORDIC ROT . F.
361 10000 26,565 2000CORDIC ROT . F.
362 10000 15,0 2000CORDIC ROT . F.
363 10000 14,036 2000CORDIC ROT . F.
364 10000 7,125 2000CORDIC ROT . F.
365 10000 1,0 2000CORDIC ROT . F.