// Kiwi Scientific Acceleration // With testbench from CHstone dfsin. // (C) 2014 DJ Greaves, University of Cambridge, Computer Laboratory. using System; using KiwiSystem; public class Cordic { const int iterations = 40; // This table generation is normally done offline, once and for all time. public static void Cordic_Table_Generate() { long [] ctab_new = new long [iterations]; double theta = 1.0; for (int i=0; i<iterations; i++) { ctab_new[i] = (long)(0.5 + 1e13 * Math.Atan(theta)); if (false) Console.WriteLine("Cordic table {0} is arctan {1} = {2}", i, theta, ctab_new[i]); theta = theta / 2.0; } } static readonly long [] ctab = new [] { 7853981633974, 4636476090008, 2449786631269, 1243549945468, 624188099960, 312398334303, 156237286205, 78123410601, 39062301320, 19531225165, 9765621896, 4882812112, 2441406201, 1220703119, 610351562, 305175781, 152587891, 76293945, 38146973, 19073486, 9536743, 4768372, 2384186, 1192093, 596046, 298023, 149012, 74506, 37253, 18626, 9313, 4657, 2328, 1164, 582, 291, 146, 73, 36, 18 }; public static long sin(long theta) { const bool vd = false; bool flip = false; const long int_pi = (long)(0.5 + Math.PI * 1e13); if (theta < 0) // Range reduction - make +ve { theta -= int_pi; flip = !flip; } while (theta >= int_pi * 2) // Range reduction - Take Mod 2.PI { theta -= int_pi * 2; Kiwi.Pause(); Kiwi.NoUnroll(); } if (theta >= int_pi) // Range reduction - Take Mod PI { theta -= int_pi; flip = !flip; } if (theta >= int_pi / 2) // Range reduction - Reflect about PI/2 { theta = int_pi - theta; } const long x0 = (long) (6.07252935008962e14); /*prescaled constant for iterations=40*/ long x=x0, y=0; if (vd) Console.WriteLine("Starting value is {0}", x); for (int k=0; k<iterations; ++k) { long tx, ty; if (vd) Console.WriteLine(" {0} cf {1} y={2}", theta, ctab[k], y); if (theta >= 0) // All nice simple integer arithmetic { if (vd) Console.WriteLine(" k={0} ABOVE", k); tx = x - (y>>k); ty = y + (x>>k); theta -= ctab[k]; } else { if (vd) Console.WriteLine(" k={0} BELOW", k); tx = x + (y>>k); ty = y - (x>>k); theta += ctab[k]; } x = tx; y = ty; } long rv = (flip) ? -y: y; return rv; } } class CordicTestbench { [Kiwi.OutputBitPort("done")] static bool done = false; static void Cordic_Test_Generate() { for (int pass=0; pass<2; pass++) for (int i=0; i<36; i++) { double theta = (double)i * Math.PI * 0.1; double q = (pass==1) ? 1e15 * Math.Sin(theta): 1e13 *theta; long val = (long) q; Console.WriteLine(" {0} pp{1} {2}qq,", val, i, q); } } static readonly long [] cordic_test_in = // Angles in radians times 1e13 { 0, //0 0 3141592653589, //1 3141592653589.79 6283185307179, //2 6283185307179.59 9424777960769, //3 9424777960769.38 12566370614359, //4 12566370614359.2 15707963267948, //5 15707963267949 18849555921538, //6 18849555921538.8 21991148575128, //7 21991148575128.6 25132741228718, //8 25132741228718.3 28274333882308, //9 28274333882308.1 31415926535897, //10 31415926535897.9 34557519189487, //11 34557519189487.7 37699111843077, //12 37699111843077.5 40840704496667, //13 40840704496667.3 43982297150257, //14 43982297150257.1 47123889803846, //15 47123889803846.9 50265482457436, //16 50265482457436.7 53407075111026, //17 53407075111026.5 56548667764616, //18 56548667764616.3 59690260418206, //19 59690260418206.1 62831853071795, //20 62831853071795.9 65973445725385, //21 65973445725385.7 69115038378975, //22 69115038378975.4 72256631032565, //23 72256631032565.2 75398223686155, //24 75398223686155 78539816339744, //25 78539816339744.8 81681408993334, //26 81681408993334.6 84823001646924, //27 84823001646924.4 87964594300514, //28 87964594300514.2 91106186954104, //29 91106186954104 94247779607693, //30 94247779607693.8 97389372261283, //31 97389372261283.6 100530964914873, //32 100530964914873 103672557568463, //33 103672557568463 106814150222052, //34 106814150222053 109955742875642 //35 109955742875643 }; // 1e15*sin(test_in * 1e-13) static readonly long [] cordic_test_out = { 0, //0 0 309016994374947, //1 309016994374947 587785252292473, //2 587785252292473 809016994374947, //3 809016994374948 951056516295153, //4 951056516295154 1000000000000000, //5 1E+15 951056516295153, //6 951056516295154 809016994374947, //7 809016994374948 587785252292473, //8 587785252292473 309016994374947, //9 309016994374948 0, //10 0.122460635382238 -309016994374947, //11 -309016994374947 -587785252292473, //12 -587785252292473 -809016994374947, //13 -809016994374948 -951056516295153, //14 -951056516295154 -1000000000000000, //15 -1E+15 -951056516295153, //16 -951056516295154 -809016994374947, //17 -809016994374947 -587785252292473, //18 -587785252292473 -309016994374947, //19 -309016994374948 0, //20 -0.244921270764475 309016994374948, //21 309016994374948 587785252292472, //22 587785252292473 809016994374947, //23 809016994374947 951056516295153, //24 951056516295154 1000000000000000, //25 1E+15 951056516295153, //26 951056516295153 809016994374947, //27 809016994374948 587785252292473, //28 587785252292473 309016994374947, //29 309016994374948 0, //30 0.367381906146713 -309016994374947, //31 -309016994374947 -587785252292472, //32 -587785252292473 -809016994374948, //33 -809016994374948 -951056516295154, //34 -951056516295154 -1000000000000000 //35 -1E+15 }; [Kiwi.HardwareEntryPoint()] public static void Main() { if (false) Cordic_Test_Generate() ; if (false) Cordic.Cordic_Table_Generate(); bool verbosef = true; if (verbosef) Console.WriteLine("cordic: Testbench start"); int main_result; int i; main_result = 0; for (i = 0; i < cordic_test_in.Length; i++) { Kiwi.Pause(); long expected = cordic_test_out[i]; long result = Cordic.sin(cordic_test_in[i]); long error = Math.Abs(result-expected); main_result += (error <= 5000)?1:0; if (verbosef) { Console.WriteLine("Test: input={0} expected={1} output={2} ", cordic_test_in[i], expected, result); if (error > 5000) Console.WriteLine(" test {0} error={1}", i, error); } } if (verbosef) { Console.WriteLine ("Result: {0}/{1}", main_result, cordic_test_in.Length); if (main_result == 36) { Console.WriteLine("RESULT: PASS"); } else { Console.WriteLine("RESULT: FAIL"); } } if (verbosef) Console.WriteLine("cordic: Testbench finished"); done = true; Kiwi.Pause(); Kiwi.Pause(); } } // (* eof *)