compiler/ lib/ examples/ std/ arch/ rv64/ tests/ abi.sizes.rad 3.4 KiB aggregate.return.rad 4.0 KiB arith.assignment.rad 580 B arith.basic.rad 176 B arith.modulo.rad 96 B arith.subword.rad 3.8 KiB arith.sum.rad 177 B arith.w64.rad 4.1 KiB array.assign.rad 221 B array.bounds.check.rad 321 B array.index.assign.rad 367 B array.index.rad 249 B array.length.rad 262 B array.math.rad 1.2 KiB array.nested.assign.rad 319 B array.nested.rad 325 B array.record.elements.rad 1.7 KiB array.repeat.edge.rad 548 B array.repeat.rad 828 B array.return.rad 330 B array.slice.empty.rad 108 B array.slice.gen.end.rad 126 B array.slice.gen.index.rad 139 B array.slice.gen.open.rad 125 B array.slice.gen.start.end.rad 127 B array.slice.gen.start.rad 126 B array.slice.rad 759 B as.precedence.rad 212 B assert.basic.rad 387 B assert.fail.rad 138 B assert.false.rad 140 B assert.true.rad 100 B assign.mutable.rad 6.1 KiB assign.rad 129 B assign.shadow.mutable.rad 461 B binop.bitwise.rad 1.2 KiB binop.cmp.rad 426 B bool.comparison.array.rad 688 B bool.comparison.nested.gen.rad 1.0 KiB bool.comparison.opt.rad 905 B bool.comparison.record.gen.rad 1.0 KiB bool.comparison.record.rad 1.1 KiB bool.comparison.slice.gen.rad 157 B bool.comparison.slice.rad 4.1 KiB bool.comparison.slice.record.gen.rad 2.0 KiB bool.comparison.slice.union.gen.rad 2.5 KiB bool.comparison.union.ctor.rad 690 B bool.comparison.union.gen.rad 1.2 KiB bool.comparison.union.record.gen.rad 1.5 KiB bool.comparison.union.simple.gen.rad 281 B bool.operators.complex.rad 384 B bool.operators.rad 831 B bool.short.circuit.rad 2.3 KiB bool.simple.rad 194 B bool.values.rad 772 B builtin.size.align.rad 1.3 KiB builtin.sliceof.mut.rad 606 B builtin.sliceof.rad 505 B call.arg.clobber.rad 717 B call.basic.rad 241 B call.clobber.rad 462 B cast.same.size.rad 1.0 KiB casting.numbers.rad 1.5 KiB char.literal.rad 165 B compound.assign.field.rad 285 B compound.assign.rad 1.1 KiB cond.assign.rad 723 B cond.expr.aggregate.rad 1.1 KiB cond.expr.rad 1.8 KiB cond.for.else.break.rad 326 B cond.for.indexed.rad 238 B cond.for.rad 165 B cond.for.range.indexed.rad 526 B cond.for.range.rad 171 B cond.for.unsigned.range.rad 644 B cond.forever.break.continue.rad 182 B cond.forever.break.rad 232 B cond.fused.rad 926 B cond.if.case.rad 2.2 KiB cond.if.else.min.rad 143 B cond.if.else.rad 225 B cond.if.elseif.rad 420 B cond.if.noelse.rad 120 B cond.if.rad 865 B cond.match.fallthrough.rad 369 B cond.match.guard.rad 1.4 KiB cond.match.guard.regalloc.rad 1.3 KiB cond.while.else.break.rad 282 B cond.while.rad 119 B const.array.copy.mutate.rad 386 B const.array.rad 195 B const.basic.rad 325 B const.char.rad 159 B const.fn.array.rad 664 B const.record.array.rad 1.2 KiB const.record.array.simple.rad 523 B const.record.ctor.rad 170 B const.record.fn.rad 353 B const.record.rad 182 B const.slice.param.rad 333 B const.union.payload.ctor.rad 349 B const.union.record.literal.rad 359 B data.array.rad 767 B data.bool.rad 216 B data.i16.rad 261 B data.i32.rad 281 B data.i8.rad 248 B data.record.rad 561 B data.simple.rad 436 B data.u16.rad 220 B data.u32.rad 240 B data.u8.rad 208 B data.union.rad 886 B debug.tag.rad 557 B edge.cases.2.rad 337 B edge.cases.3.rad 594 B edge.cases.4.rad 1.2 KiB edge.cases.5.rad 1.0 KiB edge.cases.6.rad 2.6 KiB edge.cases.7.addr.bug.rad 224 B edge.cases.8.bug.rad 508 B edge.cases.rad 223 B error.basic.rad 159 B error.catch.rad 1.6 KiB error.division.zero.rad 164 B error.modulo.zero.rad 162 B error.multi.basic.rad 672 B error.multi.catch.rad 772 B error.multi.catch.typed.binding.rad 791 B error.multi.catch.typed.catchall.rad 1.0 KiB error.multi.catch.typed.rad 1.1 KiB error.multi.propagate.multi.rad 953 B error.multi.propagate.rad 825 B error.multi.try.optional.rad 507 B error.slice.bounds.rad 219 B error.try.bang.success.rad 370 B error.try.catch.binding.rad 2.0 KiB error.try.optional.rad 1.8 KiB error.try.rad 4.0 KiB fn.block.scope.rad 508 B fn.callback.nested.rad 1.2 KiB fn.default.rad 131 B fn.local.rad 140 B fn.recursion.2.rad 239 B fn.void.rad 150 B for.else.continue.rad 1.1 KiB frame.large.rad 567 B if-let-mut.rad 1.1 KiB iflet.shadow.leak.rad 317 B integer.bitwise.basic.rad 693 B integer.overflow.rad 1.8 KiB large.blit.store.rad 2.1 KiB let.guard.rad 1.9 KiB literal.w64.rad 1.7 KiB loc.addr.offset.bug.rad 410 B loc.addr.opt.to.opt.rad 433 B loc.addr.optional.assign.rad 408 B loc.addr.record.assign.rad 443 B loop.complex.flow.rad 1007 B loop.sealblock.rad 911 B match.array.rad 3.4 KiB match.char.rad 1.6 KiB match.multi.seal.rad 987 B match.multi.survive.rad 1.6 KiB match.mutref.push.rad 1.0 KiB match.mutref.union.rad 662 B match.nested.call.rad 1.7 KiB match.nested.deep.rad 2.2 KiB match.nested.deref.rad 3.7 KiB match.nested.guard.rad 1.6 KiB match.nested.iflet.guard.rad 1.6 KiB match.nested.iflet.rad 1.4 KiB match.nested.letelse.rad 813 B match.nested.letelse.union.rad 1.3 KiB match.nested.literal.rad 3.1 KiB match.nested.multi.rad 2.4 KiB match.nested.pattern.rad 5.2 KiB match.nested.record.rad 2.0 KiB match.nested.union.rad 2.3 KiB match.nested.whilelet.rad 2.4 KiB match.string.rad 1.8 KiB match.value.copy.rad 2.0 KiB match.void.then.or.rad 1.6 KiB memzero.result.bug.rad 806 B memzero.union.bug.rad 576 B mutref.loop.bug.rad 1.8 KiB opt.assignment.bug.rad 1.3 KiB opt.bug.test.rad 1.4 KiB opt.if.let.complex.rad 6.2 KiB opt.if.let.guard.rad 809 B opt.if.let.rad 956 B opt.nil.check.rad 1.5 KiB opt.record.eq.rad 842 B opt.record.rad 655 B opt.return.array.rad 289 B opt.return.nested.rad 797 B opt.return.record.rad 344 B opt.slice.npo.rad 2.8 KiB opt.type.rad 200 B opt.while.let.complex.rad 404 B panic.rad 111 B placeholder.basic.rad 133 B placeholder.comprehensive.rad 562 B pointer.copy.edge.case.rad 1.3 KiB pointer.slice.index.rad 269 B pointer.slice.store.rad 881 B prog.ackermann.rad 5.0 KiB prog.bignum.rad 9.4 KiB prog.binsearch.rad 2.4 KiB prog.bubblesort.rad 2.0 KiB prog.cordic.rad 6.9 KiB prog.crc32.rad 2.7 KiB prog.dijkstra.rad 7.7 KiB prog.eval.rad 6.2 KiB prog.hanoi.rad 3.8 KiB prog.huffman.rad 9.3 KiB prog.hybridsort.rad 3.0 KiB prog.linkedlist.rad 5.8 KiB prog.lzw.rad 6.7 KiB prog.matmul.rad 2.9 KiB prog.mersenne.rad 5.2 KiB prog.nqueens.rad 3.4 KiB prog.rbtree.rad 8.2 KiB prog.regex.rad 10.2 KiB prog.sha256.rad 7.0 KiB prog.sieve.rad 2.8 KiB prog.symtab.rad 10.1 KiB prog.tokenizer.rad 13.8 KiB prog.vm.rad 17.4 KiB ptr.assign.rad 137 B ptr.deref.rad 622 B ptr.eq.rad 966 B ptr.mutate.rad 244 B ptr.opaque.rad 1.4 KiB record.access.rad 285 B record.alignment.rad 179 B record.array.elements.rad 1.7 KiB record.copy.rad 2.0 KiB record.field.assign.rad 184 B record.nested.calls.2.rad 612 B record.nested.calls.3.rad 734 B record.param.lit.rad 353 B record.ptr.access.rad 227 B record.ptr.mutate.rad 243 B record.shorthand.rad 1.5 KiB record.unlabeled.rad 407 B ref.if.bug.rad 519 B ref.immut.loop.bug.rad 670 B ref.mut.ptr.rad 261 B regalloc.callee.save.rad 1.5 KiB regalloc.spill.reuse.rad 473 B reserve.loop.rad 392 B result.void.success.rad 716 B slice.alloc.loop.rad 788 B slice.append.rad 3.3 KiB slice.cap.rad 941 B slice.delete.rad 971 B slice.of.rad 460 B slice.subslice.rad 1.4 KiB spill.blockarg.clobber.rad 3.5 KiB spill.loop.rad 1.6 KiB stack.local.corrupt.rad 320 B static.array.mutate.rad 387 B static.basic.rad 327 B static.fn.array.rad 628 B static.record.array.rad 503 B static.slice.index.assign.rad 408 B static.slice.offset.rad 668 B string.basic.rad 149 B string.escape.rad 349 B string.index.rad 116 B switch.blockargs.clobber.rad 1.3 KiB trait.aggregate.ret.rad 1.5 KiB trait.array.optional.rad 1.7 KiB trait.basic.rad 565 B trait.control.flow.rad 1.1 KiB trait.fn.param.rad 1.6 KiB trait.multiple.methods.rad 1.2 KiB trait.multiple.traits.rad 1.2 KiB trait.multiple.types.rad 1.3 KiB trait.supertrait.rad 2.5 KiB trait.throws.rad 1.0 KiB trait.writer.rad 2.6 KiB type.unify.rad 4.5 KiB undefined.rad 417 B union-tag.rad 911 B union.bitfield.rad 1.2 KiB union.discriminant.cast.rad 389 B union.edge.case.2.rad 679 B union.edge.case.3.rad 608 B union.mixed.assign.rad 977 B union.payload.mutref.rad 1.4 KiB union.payload.rad 580 B union.record.forward.rad 1.3 KiB union.void.match.rad 403 B union.void.rad 824 B unsigned.compare.rad 1.9 KiB var.align.rad 1013 B var.infer.rad 549 B decode.rad 14.6 KiB emit.rad 24.4 KiB encode.rad 19.9 KiB isel.rad 41.1 KiB printer.rad 13.0 KiB tests.rad 15.7 KiB rv64.rad 13.0 KiB collections/ lang/ sys/ arch.rad 65 B collections.rad 36 B fmt.rad 3.8 KiB intrinsics.rad 206 B io.rad 1.2 KiB lang.rad 222 B mem.rad 2.2 KiB sys.rad 167 B testing.rad 2.4 KiB tests.rad 11.6 KiB vec.rad 3.1 KiB std.rad 231 B scripts/ seed/ test/ vim/ .gitignore 353 B .gitsigners 112 B LICENSE 1.1 KiB Makefile 3.1 KiB README 2.5 KiB std.lib 987 B std.lib.test 252 B
lib/std/arch/rv64/tests/prog.cordic.rad 6.9 KiB raw
1
//! CORDIC fixed-point trigonometry.
2
//! Implement sine and cosine using the CORDIC algorithm with 16-bit
3
//! fixed-point arithmetic (Q16.16 format). This is a classic embedded
4
//! systems / DSP benchmark that stress-tests shift, multiply, and
5
//! table-driven computation without floating point.
6
7
/// Fixed-point scale factor: 1.0 = 65536 (Q16.16).
8
const SCALE: i32 = 65536;
9
10
/// Number of CORDIC iterations (more = more precision).
11
const ITERATIONS: u32 = 16;
12
13
/// CORDIC gain factor in Q16.16. After 16 iterations, the gain is
14
/// approximately 1/K = 1/1.6468 = 0.60725 * 65536 = 39797.
15
const CORDIC_GAIN: i32 = 39797;
16
17
/// Pi in Q16.16: 3.14159 * 65536 = 205887
18
const PI: i32 = 205887;
19
20
/// Pi/2 in Q16.16.
21
const HALF_PI: i32 = 102944;
22
23
/// Result record for cos and sin.
24
record CosSin {
25
    cos: i32,
26
    sin: i32,
27
}
28
29
/// CORDIC rotation mode: compute cos(angle) and sin(angle).
30
/// Input angle in Q16.16 radians, must be in [-pi/2, pi/2].
31
fn cordicRotate(angle: i32, atanTable: *[i32]) -> CosSin {
32
    let mut x: i32 = CORDIC_GAIN;
33
    let mut y: i32 = 0;
34
    let mut z: i32 = angle;
35
36
    let mut i: u32 = 0;
37
    while i < ITERATIONS {
38
        let dx: i32 = x >> i as i32;
39
        let dy: i32 = y >> i as i32;
40
41
        if z >= 0 {
42
            x -= dy;
43
            y += dx;
44
            z -= atanTable[i];
45
        } else {
46
            x += dy;
47
            y -= dx;
48
            z += atanTable[i];
49
        }
50
        i += 1;
51
    }
52
53
    return CosSin { cos: x, sin: y };
54
}
55
56
/// Compute cos and sin for any angle by reducing to [-pi/2, pi/2].
57
fn cosSin(angle: i32, atanTable: *[i32]) -> CosSin {
58
    let mut a: i32 = angle;
59
60
    // Reduce to [-pi, pi].
61
    while a > PI {
62
        a -= 2 * PI;
63
    }
64
    while a < 0 - PI {
65
        a += 2 * PI;
66
    }
67
68
    // If in [pi/2, pi], use cos(a) = -cos(pi-a), sin(a) = sin(pi-a).
69
    if a > HALF_PI {
70
        let r: CosSin = cordicRotate(PI - a, atanTable);
71
        return CosSin { cos: 0 - r.cos, sin: r.sin };
72
    } else if a < 0 - HALF_PI {
73
        // If in [-pi, -pi/2], use cos(a) = -cos(-pi-a), sin(a) = sin(-pi-a)
74
        let r: CosSin = cordicRotate(0 - PI - a, atanTable);
75
        return CosSin { cos: 0 - r.cos, sin: r.sin };
76
    } else {
77
        return cordicRotate(a, atanTable);
78
    }
79
}
80
81
/// Absolute value.
82
fn abs(x: i32) -> i32 {
83
    if x < 0 {
84
        return 0 - x;
85
    }
86
    return x;
87
}
88
89
/// Fixed-point multiply: (a * b) >> 16, using half-word decomposition
90
/// to avoid 32-bit overflow.
91
fn fpmul(a: i32, b: i32) -> i32 {
92
    // Determine sign and work with magnitudes.
93
    let neg: bool = (a < 0) != (b < 0);
94
    let mut ua: u32 = a as u32;
95
    if a < 0 {
96
        ua = (0 - a) as u32;
97
    }
98
    let mut ub: u32 = b as u32;
99
    if b < 0 {
100
        ub = (0 - b) as u32;
101
    }
102
103
    // Split into 16-bit halves: ua = ah:al, ub = bh:bl.
104
    let al: u32 = ua & 0xFFFF;
105
    let ah: u32 = ua >> 16;
106
    let bl: u32 = ub & 0xFFFF;
107
    let bh: u32 = ub >> 16;
108
109
    // Product = ah*bh*2^32 + (ah*bl + al*bh)*2^16 + al*bl
110
    // We need the result >> 16, so:
111
    //   (al*bl) >> 16  +  (ah*bl + al*bh)  +  ah*bh*2^16
112
    let ll: u32 = al * bl;
113
    let mid: u32 = ah * bl + al * bh;
114
    let hh: u32 = ah * bh;
115
116
    let result: u32 = (ll >> 16) + mid + (hh << 16);
117
    if neg {
118
        return 0 - result as i32;
119
    }
120
    return result as i32;
121
}
122
123
/// Test cos(0) = 1, sin(0) = 0.
124
fn testZero(atanTable: *[i32]) -> i32 {
125
    let r: CosSin = cosSin(0, atanTable);
126
    // cos(0) should be close to 65536 (1.0 in Q16.16).
127
    let cosErr: i32 = abs(r.cos - SCALE);
128
    let sinErr: i32 = abs(r.sin);
129
130
    // Allow error of ~1% = 655.
131
    assert cosErr <= 655;
132
    assert sinErr <= 655;
133
    return 0;
134
}
135
136
/// Test cos(pi/2) = 0, sin(pi/2) = 1.
137
fn testHalfPi(atanTable: *[i32]) -> i32 {
138
    let r: CosSin = cosSin(HALF_PI, atanTable);
139
    let cosErr: i32 = abs(r.cos);
140
    let sinErr: i32 = abs(r.sin - SCALE);
141
142
    assert cosErr <= 655;
143
    assert sinErr <= 655;
144
    return 0;
145
}
146
147
/// Test cos(pi) = -1, sin(pi) = 0.
148
fn testPi(atanTable: *[i32]) -> i32 {
149
    let r: CosSin = cosSin(PI, atanTable);
150
    let cosErr: i32 = abs(r.cos + SCALE);
151
    let sinErr: i32 = abs(r.sin);
152
153
    assert cosErr <= 655;
154
    assert sinErr <= 655;
155
    return 0;
156
}
157
158
/// Test Pythagorean identity: sin^2 + cos^2 = 1 for several angles.
159
fn testPythagorean(atanTable: *[i32]) -> i32 {
160
    // Test at 16 evenly spaced angles from 0 to 2*pi.
161
    let step: i32 = PI / 8;
162
    let mut i: i32 = 0 - PI;
163
164
    while i <= PI {
165
        let r: CosSin = cosSin(i, atanTable);
166
        // sin^2 + cos^2 in Q16.16.
167
        let sin2: i32 = fpmul(r.sin, r.sin);
168
        let cos2: i32 = fpmul(r.cos, r.cos);
169
        let sum: i32 = sin2 + cos2;
170
        let err: i32 = abs(sum - SCALE);
171
172
        // Allow ~2% error due to fixed-point precision.
173
        assert err <= 1311;
174
        i += step;
175
    }
176
    return 0;
177
}
178
179
/// Test symmetry: sin(-x) = -sin(x), cos(-x) = cos(x).
180
fn testSymmetry(atanTable: *[i32]) -> i32 {
181
    let angles: [i32; 5] = [16384, 32768, 51472, 65536, 81920];
182
183
    let mut i: u32 = 0;
184
    while i < 5 {
185
        let a: i32 = angles[i];
186
187
        let rPos: CosSin = cosSin(a, atanTable);
188
        let rNeg: CosSin = cosSin(0 - a, atanTable);
189
190
        // cos(-x) should equal cos(x).
191
        assert abs(rPos.cos - rNeg.cos) <= 655;
192
        // sin(-x) should equal -sin(x).
193
        assert abs(rPos.sin + rNeg.sin) <= 655;
194
        i += 1;
195
    }
196
    return 0;
197
}
198
199
/// Test specific known value: cos(pi/3) = 0.5, sin(pi/3) = 0.866.
200
fn testPiThird(atanTable: *[i32]) -> i32 {
201
    // pi/3 in Q16.16 = 68629.
202
    let piThird: i32 = 68629;
203
    let r: CosSin = cosSin(piThird, atanTable);
204
205
    // cos(pi/3) = 0.5 = 32768 in Q16.16.
206
    let cosErr: i32 = abs(r.cos - 32768);
207
    // sin(pi/3) = 0.866 = 56756 in Q16.16.
208
    let sinErr: i32 = abs(r.sin - 56756);
209
210
    // Allow ~2% error.
211
    assert cosErr <= 1311;
212
    assert sinErr <= 1311;
213
    return 0;
214
}
215
216
@default fn main() -> i32 {
217
    /// CORDIC arctangent table in Q16.16 fixed-point.
218
    let atanTable: [i32; 16] = [
219
        51472,  // atan(2^0)
220
        30386,  // atan(2^-1)
221
        16055,  // atan(2^-2)
222
        8150,   // atan(2^-3)
223
        4091,   // atan(2^-4)
224
        2047,   // atan(2^-5)
225
        1024,   // atan(2^-6)
226
        512,    // atan(2^-7)
227
        256,    // atan(2^-8)
228
        128,    // atan(2^-9)
229
        64,     // atan(2^-10)
230
        32,     // atan(2^-11)
231
        16,     // atan(2^-12)
232
        8,      // atan(2^-13)
233
        4,      // atan(2^-14)
234
        2       // atan(2^-15)
235
    ];
236
237
    let r1: i32 = testZero(&atanTable[..]);
238
    if r1 != 0 {
239
        return 10 + r1;
240
    }
241
242
    let r2: i32 = testHalfPi(&atanTable[..]);
243
    if r2 != 0 {
244
        return 20 + r2;
245
    }
246
247
    let r3: i32 = testPi(&atanTable[..]);
248
    if r3 != 0 {
249
        return 30 + r3;
250
    }
251
252
    let r4: i32 = testPythagorean(&atanTable[..]);
253
    if r4 != 0 {
254
        return 40 + r4;
255
    }
256
257
    let r5: i32 = testSymmetry(&atanTable[..]);
258
    if r5 != 0 {
259
        return 50 + r5;
260
    }
261
262
    let r6: i32 = testPiThird(&atanTable[..]);
263
    if r6 != 0 {
264
        return 60 + r6;
265
    }
266
267
    return 0;
268
}