* Add current progress of the project. The code compiles and should be able to execu...
authorunknown <s0042331@.dynamic.ewi.utwente.nl>
Thu, 27 Mar 2008 11:40:54 +0000 (12:40 +0100)
committerunknown <s0042331@.dynamic.ewi.utwente.nl>
Thu, 27 Mar 2008 11:40:54 +0000 (12:40 +0100)
FFT.h [new file with mode: 0644]
FFT.mc [new file with mode: 0644]
FFT_support.cpp [new file with mode: 0644]
main.cpp [new file with mode: 0644]
simulate.py [new file with mode: 0644]

diff --git a/FFT.h b/FFT.h
new file mode 100644 (file)
index 0000000..cb4cdf1
--- /dev/null
+++ b/FFT.h
@@ -0,0 +1,79 @@
+#include "libmontiumc.h"\r
+#ifndef FFT_H_INCLUDED\r
+#define FFT_H_INCLUDED\r
+\r
+#define BIT_SIZE 3\r
+#define SIZE (1<<BIT_SIZE)\r
+\r
+/* Change these: */\r
+/* 2log of number of tiles */\r
+#define q 2\r
+/** 2log of total FFT size */\r
+#define n 4\r
+\r
+/* But don't change these: */\r
+/* Number of tiles */\r
+#define Q (1 << q)\r
+/** Total FFT size */\r
+#define N (1 << n)\r
+/** FFT size on each tile */\r
+#define N_t (N / Q)\r
+/** 2log of FFT size on each tile */\r
+#define n_t (n - q)\r
+\r
+#ifndef __MONTIUMCC__\r
+       void pre_run();\r
+       void post_run();\r
+#endif \r
+       /**\r
+        * Support structure to store the result of a butterfly.\r
+        */\r
+       struct bf_out {\r
+               word a_re;\r
+               word a_im;\r
+               word b_re;\r
+               word b_im;\r
+       };\r
+       \r
+       /**\r
+        * Support structure to store teh inputs for a butterfly.\r
+        */\r
+       struct bf_in {\r
+                       word a_re;\r
+                       word a_im;\r
+                       word b_re;\r
+                       word b_im;\r
+                       word W_re;\r
+                       word W_im;\r
+       };\r
+       \r
+       /**\r
+        * A struct to hold all the used memories. We put these in\r
+        * a struct, so we can store them in a local variable and \r
+        * pass them around in arguments, so we can change the memories\r
+        * allocated to each on ever stage (MontiumC doesn't support\r
+        * reassigning global mem variables).\r
+        */\r
+       struct mems {\r
+               mem input_a_re, input_a_im, input_b_re, input_b_im, output_a_re, output_a_im, output_b_re, output_b_im, twiddle_re, twiddle_im;\r
+       };\r
+       \r
+       void init();\r
+       INLINE struct bf_out butterfly(struct bf_in in);\r
+       void run(void); \r
+       \r
+       /* Values for the second_half argument */\r
+#define FIRST_HALF 0\r
+#define SECOND_HALF 1\r
+       \r
+       /* Values for the stage_odd argument */\r
+#define EVEN_STAGE 0\r
+#define ODD_STAGE 1\r
+       \r
+       /* Values for the cycle_odd argument */\r
+#define EVEN_CYCLE 0\r
+#define ODD_CYCLE 1\r
+\r
+\r
+       \r
+#endif // !FFT_H_INCLUDED\r
diff --git a/FFT.mc b/FFT.mc
new file mode 100644 (file)
index 0000000..e58d2fa
--- /dev/null
+++ b/FFT.mc
@@ -0,0 +1,234 @@
+#ifndef __MONTIUMCC__\r
+#include <memory.h>\r
+#include <math.h>\r
+#include <stdio.h>\r
+#endif\r
+\r
+#include "FFT.h"\r
+\r
+       word in_a_re, in_a_im, in_b_re, in_b_im, in_W_re, in_W_im;\r
+       //out_a_re, out_a_im, out_b_re, out_b_im;\r
+       //mem input_a_re, input_a_im, input_b_re, input_b_im, output_a_re, output_a_im, output_b_re, output_b_im, twiddle_re, twiddle_im; \r
+\r
+void init()\r
+{\r
+\r
+}\r
+\r
+\r
+\r
+/*void update_gpi() {\r
+  set_gpi(0, 1);\r
+}*/\r
+\r
+INLINE struct bf_out butterfly(struct bf_in in) {\r
+       struct bf_out out;\r
+       /* ALU 0 & 1 */\r
+               /* im(W) * im(b) */\r
+               aluexp Wixbi = west(fmul(rd1(in.W_im), rb1(in.b_im)));\r
+               /* re(W * b) = re(W) * re(b) - im(W) * im(b) */\r
+               aluexp Wxbr  = ssub_acc(fmul(rc1(in.W_re), ra1(in.b_re)), Wixbi);\r
+               \r
+               /* re(out_a) = re(a) + re(W * b) */\r
+               out.a_re =   p0o0(sadd_bf(rb1(in.a_re), Wxbr));\r
+               /* re(out_b) = re(a) - re(W * b) */\r
+               out.b_re = p0o1(ssub_bf(rb1(in.a_re), Wxbr));\r
+               \r
+       /* ALU 2 & 3 */ \r
+               /* im(W) * re(b) */\r
+               aluexp Wixbr = west(fmul(rd1(in.W_im), rb1(in.b_re)));\r
+               /* im(W * b) = re(W) * im(b) + im(W) * re(b) */\r
+               aluexp Wxbi  = sadd_acc(fmul(rc1(in.W_re), ra1(in.b_im)), Wixbr);\r
+               \r
+               /* im(out_a) = im(a) + im(W * b) */\r
+               out.a_im =   p2o0(sadd_bf(rb1(in.a_im), Wxbi));\r
+               /* im(out_b) = im(a) - im(W * b) */\r
+               out.b_im = p2o1(ssub_bf(rb1(in.a_im), Wxbi));\r
+               \r
+               return out;\r
+}\r
+\r
+INLINE void write_output_regular(struct mems m, struct bf_out res, bool second_half) {\r
+       add_offset(m.output_a_re, 2);\r
+       add_offset(m.output_a_im, 2);\r
+       add_offset(m.output_b_re, 2);\r
+       add_offset(m.output_b_im, 2);\r
+       \r
+       if (second_half) {\r
+               write_mem(m.output_a_re, res.a_re);\r
+               write_mem(m.output_a_im, res.a_im);\r
+               write_mem(m.output_b_re, res.b_re);\r
+               write_mem(m.output_b_im, res.b_im);\r
+       } else {\r
+               /* Write a results to memory b and v.v. */\r
+               write_mem(m.output_a_re, res.b_re);\r
+               write_mem(m.output_a_im, res.b_im);\r
+               write_mem(m.output_b_re, res.a_re);\r
+               write_mem(m.output_b_im, res.a_im);\r
+       }\r
+}\r
+\r
+/**\r
+ * Reads four inputs and two twiddle factors from memory. \r
+ * Also increases memory offsets by 1 after reading.\r
+ * @param    stage_odd Is this an odd stage? If so, read from the left\r
+ *                     memories, else read from the right memories\r
+ *                     (not implemented yet).\r
+ * @param    cycle_odd Is this an odd cycle within the stage? If so, \r
+ *                     read input a from memory b and v.v. If not, \r
+ *                     simply read a from memory a and b from memory b.\r
+ */\r
+INLINE struct bf_in read_input_regular(struct mems m, bool cycle_odd, bool stage_odd) {\r
+       struct bf_in in;\r
+       /* TODO: Select left or right memories */\r
+       if (cycle_odd) {\r
+               in.a_re = read_mem(m.input_a_re);\r
+               in.a_im = read_mem(m.input_a_im);\r
+               in.b_re = read_mem(m.input_b_re);               \r
+               in.b_im = read_mem(m.input_b_im);\r
+       } else {\r
+               in.b_re = read_mem(m.input_a_re);\r
+               in.b_im = read_mem(m.input_a_im);\r
+               in.a_re = read_mem(m.input_b_re);               \r
+               in.a_im = read_mem(m.input_b_im);\r
+       }\r
+       in.W_re = read_mem(m.twiddle_re);\r
+       in.W_im = read_mem(m.twiddle_im);\r
+       \r
+\r
+       add_offset(m.input_a_re, 1);\r
+       add_offset(m.input_a_im, 1);\r
+       add_offset(m.input_b_re, 1);\r
+       add_offset(m.input_b_im, 1);\r
+       /* TODO: Update twiddle offsets */\r
+       return in;\r
+}\r
+\r
+/**\r
+ *  Initializes the addresses for the various memories.\r
+ * @param stage_odd   True if this is an odd stage.\r
+ *@param second_half True if we are initing halfway a stage.\r
+ */ \r
+INLINE void init_input_addresses_regular(struct mems m, bool stage_odd) {\r
+       /* TODO: Select left or right memories */\r
+       set_base(m.input_a_im, 0);\r
+       set_base(m.input_b_re, 0);\r
+       set_base(m.input_b_im, 0);\r
+       set_base(m.twiddle_re, 0);\r
+       set_base(m.twiddle_im, 0);\r
+       \r
+       set_offset(m.input_a_re, 0);\r
+       set_offset(m.input_a_im, 0);\r
+       set_offset(m.input_b_re, 0);\r
+       set_offset(m.input_b_im, 0);\r
+       set_offset(m.twiddle_re, 0);\r
+       set_offset(m.twiddle_im, 0);\r
+}\r
+       \r
+       \r
+INLINE void init_output_addresses_regular(struct mems m, bool stage_odd, bool second_half) {\r
+       /* \r
+        * For the second half of the stage, the starting addresses are \r
+        * reversed. write_output_regular above will also swap the output\r
+        * memories.\r
+        * TODO: Better comments :-)\r
+        */\r
+\r
+       set_base(m.output_a_re, 0);\r
+       set_base(m.output_a_im, 0);\r
+       set_base(m.output_b_re, 0);\r
+       set_base(m.output_b_im, 0);\r
+       \r
+       /* We subtract two from every address, since write_output_regular \r
+        * adds two to the offset before writing the first (and every other) \r
+        * result. */\r
+       if (second_half) {\r
+               set_offset(m.output_a_re, 1-2);\r
+               set_offset(m.output_a_im, 1-2);\r
+               set_offset(m.output_b_re, 0-2);\r
+               set_offset(m.output_b_im, 0-2);\r
+       } else {\r
+               set_offset(m.output_a_re, 1-2);\r
+               set_offset(m.output_a_im, 1-2);\r
+               set_offset(m.output_b_re, 0-2);\r
+               set_offset(m.output_b_im, 0-2);\r
+       }\r
+}\r
+\r
+INLINE void do_half_regular_stage(struct mems m, bool stage_odd, bool second_half){\r
+       struct bf_in in = read_input_regular(m, EVEN_CYCLE, stage_odd);\r
+       struct bf_out out = butterfly(in);\r
+       \r
+       /* Now, do a single stage. That means N_t / 2 cycles. Since we do 2\r
+        * cycles on every iteration, plus one before and after the loop,\r
+        * we will loop N_t / 4 - 1 times. */\r
+       init_loop(LC2, (N_t / 4) - 1);\r
+       do {\r
+               init_output_addresses_regular(m, stage_odd, second_half);\r
+               write_output_regular(m, out, second_half);\r
+\r
+               in = read_input_regular(m, ODD_CYCLE, second_half);\r
+               out = butterfly(in);\r
+               next_cycle();\r
+               write_output_regular(m, out, second_half);\r
+\r
+               in = read_input_regular(m, EVEN_CYCLE, second_half);\r
+               out = butterfly(in);\r
+       } while (loop_next(LC2));\r
+       \r
+       write_output_regular(m, out, second_half);\r
+       in = read_input_regular(m, ODD_CYCLE, second_half);\r
+       out = butterfly(in);\r
+       \r
+       next_cycle();\r
+       write_output_regular(m, out, second_half);\r
+}\r
+\r
+INLINE struct mems init_mem_mapping(bool stage_odd){\r
+       struct mems res;\r
+       if (stage_odd) {\r
+               res.input_a_re   = alloc_mem(P0M1);\r
+               res.input_a_im   = alloc_mem(P1M1);\r
+               res.input_b_re   = alloc_mem(P2M1);\r
+               res.input_b_im   = alloc_mem(P3M1);\r
+               res.output_a_re  = alloc_mem(P0M0);\r
+               res.output_a_im  = alloc_mem(P1M0);\r
+               res.output_b_re  = alloc_mem(P2M0);\r
+               res.output_b_im  = alloc_mem(P3M0);\r
+       } else {\r
+               res.input_a_re   = alloc_mem(P0M0);\r
+               res.input_a_im   = alloc_mem(P1M0);\r
+               res.input_b_re   = alloc_mem(P2M0);\r
+               res.input_b_im   = alloc_mem(P3M0);\r
+               res.output_a_re  = alloc_mem(P0M1);\r
+               res.output_a_im  = alloc_mem(P1M1);\r
+               res.output_b_re  = alloc_mem(P2M1);\r
+               res.output_b_im  = alloc_mem(P3M1);\r
+       }\r
+       \r
+       res.twiddle_re   = alloc_mem(P4M0);\r
+       res.twiddle_im   = alloc_mem(P4M1);\r
+       \r
+       return res;\r
+}\r
+void run() {\r
+#ifdef __MONTIUMCC__\r
+       /* main.cpp will call init before pre_run(), so only need to call init for MontiumCC */\r
+       init();\r
+#endif\r
+       do { freeze(); } while (gpi(0) == 0);\r
+       struct mems m;\r
+       \r
+       m = init_mem_mapping(EVEN_STAGE);\r
+       init_input_addresses_regular(m, EVEN_STAGE);\r
+       /* do_half_regular_stage will init output addresses */\r
+       next_cycle();\r
+       do_half_regular_stage(m, EVEN_STAGE, FIRST_HALF);\r
+       do_half_regular_stage(m, EVEN_STAGE, SECOND_HALF);\r
+       next_cycle();\r
+       init_input_addresses_regular(m, ODD_STAGE);\r
+       m = init_mem_mapping(ODD_STAGE);\r
+       next_cycle();\r
+       do_half_regular_stage(m, ODD_STAGE, FIRST_HALF);\r
+       do_half_regular_stage(m, ODD_STAGE, SECOND_HALF);\r
+}\r
diff --git a/FFT_support.cpp b/FFT_support.cpp
new file mode 100644 (file)
index 0000000..1876e36
--- /dev/null
@@ -0,0 +1,93 @@
+#include "FFT.h"\r
+#include <cstdio>\r
+#include <cmath>\r
+\r
+\r
+/* Didn't the Montium use Q15 instead of Q14? */\r
+#define FIXED_POINT 14\r
+#define WORD_SIZE   16\r
+\r
+#define WORDS_PER_LINE 4\r
+#define WORDS_PER_GROUP 1\r
+\r
+extern         mem input_a_re, input_a_im, input_b_re, input_b_im, output_a_re, output_a_im, output_b_re, output_b_im, twiddle_re, twiddle_im; \r
+\r
+\r
+\r
+int to_fixed(float n)\r
+{\r
+       int res = (int)(n * (1 << FIXED_POINT));\r
+       /* Crop results */\r
+       if (res > (1 << WORD_SIZE - 1) - 1)\r
+               return (1 << WORD_SIZE - 1) - 1;\r
+       if (res < -(1 << WORD_SIZE - 1))\r
+               return -(1 << WORD_SIZE - 1);\r
+       return res;\r
+}\r
+\r
+float from_fixed(int n)\r
+{\r
+       return n / (float)(1<<FIXED_POINT);\r
+}\r
+\r
+void print_mem(mem m, int offset, int size, bool fixed)\r
+{\r
+       int i;\r
+       for(i = offset;i<offset+size;i++)\r
+       {\r
+               if (fixed)\r
+                       printf("%0.4f", from_fixed(get_mem(m->id, i)));\r
+               else\r
+                       printf("%04hx", (short)get_mem(m->id, i));\r
+               if ((i + 1) % WORDS_PER_LINE == 0)\r
+                       printf("\n");\r
+               else if ((i + 1) % WORDS_PER_GROUP == 0)\r
+                       printf(" ");\r
+       }\r
+       if (i % WORDS_PER_LINE != 0)\r
+               printf("\n");\r
+}\r
+\r
+\r
+void pre_run()\r
+{\r
+       int i;\r
+\r
+       /* TODO: Init memory and twiddles */\r
+       for (i=0;i<SIZE/2;i++)\r
+       {\r
+               set_mem(twiddle_re->id, i, to_fixed(cos(2*M_PI/SIZE*i)));\r
+               set_mem(twiddle_im->id, i, to_fixed(sin(2*M_PI/SIZE*i)));\r
+       }\r
+       \r
+       for (i=0;i<SIZE;i++)\r
+       {\r
+               int value = to_fixed(sin((float)i/SIZE*2*2*M_PI));\r
+               if (i<SIZE/2)\r
+               {\r
+                       set_mem(input_a_re->id, i, value);\r
+                       set_mem(input_a_im->id, i, 0);\r
+               }\r
+               else\r
+               {\r
+                       set_mem(input_a_re->id, i - SIZE / 2, value);\r
+                       set_mem(input_a_im->id, i - SIZE / 2, 0);\r
+               }\r
+       }\r
+}\r
+\r
+void post_run()\r
+{\r
+       printf("re(W)\n");\r
+       print_mem(twiddle_re, 0, SIZE, true);\r
+       printf("im(W)\n");\r
+       print_mem(twiddle_im, 0, SIZE, true);\r
+       printf("re(in_a)\n");\r
+       print_mem(input_a_re, 0, SIZE, true);\r
+       printf("re(in_b)\n");\r
+       print_mem(input_b_re, 0, SIZE, true);\r
+       printf("re(out_a)\n");\r
+       print_mem(output_a_re, 0, SIZE, true);\r
+       printf("im(out_a)\n");\r
+       print_mem(output_a_im, 0, SIZE, true);\r
+}\r
diff --git a/main.cpp b/main.cpp
new file mode 100644 (file)
index 0000000..4fd8803
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,24 @@
+/*\r
+int main() {\r
+  init();\r
+  pre_run();\r
+  update_gpi();\r
+  run();\r
+  post_run();\r
+  return 0;\r
+}(*/\r
+#include "FFT.h"\r
+\r
+int main(int argc, char* argv[]) {\r
+       //CCU ccu;\r
+       //FileInputStream input(ccu, SI3, "input/input.bin");\r
+       //FileOutputStream output(ccu, SO3, "output_exe/output.bin");\r
+       //FFT fft(ccu);\r
+       init();\r
+       pre_run();\r
+    set_gpi(0, 1);\r
+       run();\r
+       post_run();\r
+       return 0;\r
+}\r
+\r
diff --git a/simulate.py b/simulate.py
new file mode 100644 (file)
index 0000000..9cf3ce6
--- /dev/null
@@ -0,0 +1,10 @@
+import os\r
+import sys\r
+\r
+base_path = os.path.split(sys.argv[0])[0]\r
+\r
+binary_name = "Montium\FFT.mb"\r
+\r
+simulate(os.path.join(base_path, binary_name))\r
+\r
+runUntilNotHold()
\ No newline at end of file