当前位置:   article > 正文

基于System Verilog的8点FFT实现_8点蝶形运算

8点蝶形运算

我们采用system verilog实现一个8点的基于蝶形运算单元的FFT变换,如下图,是蝶形运算单元的示意图。

然后,由于FFT涉及复数运算,因此,我们编写如下复数类型以及运算符的一个包:

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2021/07/22 11:57:16
  7. // Design Name:
  8. // Module Name: complex_type
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. package complex_type;
  22. parameter DATA_WIDTH = 32;
  23. //复数结构体类型
  24. typedef struct {
  25. logic signed [DATA_WIDTH-1:0] r;
  26. logic signed [DATA_WIDTH-1:0] i;
  27. } Complex;
  28. //复数运算函数
  29. //定义复数乘法
  30. function Complex complex_mul(Complex a,Complex b); //(a.r+i*a.i)x(b.r+i*b.i)
  31. Complex res;
  32. //为防止溢出,扩展到64位再进行乘法
  33. logic [2*DATA_WIDTH-1:0] expand_a_r;
  34. logic [2*DATA_WIDTH-1:0] expand_a_i;
  35. logic [2*DATA_WIDTH-1:0] expand_b_r;
  36. logic [2*DATA_WIDTH-1:0] expand_b_i;
  37. // $display("a=(%d,%d),b=(%d,%d)",a.r,a.i,b.r,b.i);
  38. expand_a_r={{32{a.r[31]}},a.r};
  39. expand_a_i={{32{a.i[31]}},a.i};
  40. expand_b_r={{32{b.r[31]}},b.r};
  41. expand_b_i={{32{b.i[31]}},b.i};
  42. res.r=(expand_a_r*expand_b_r-expand_a_i*expand_b_i)>>>16;
  43. res.i=(expand_a_r*expand_b_i+expand_a_i*expand_b_r)>>>16;
  44. // $display("res=(%d,%d)",res.r,res.i);
  45. return res;
  46. endfunction
  47. //定义复数加法
  48. function Complex complex_add(Complex a,Complex b);
  49. Complex res;
  50. res.r=a.r+b.r;
  51. res.i=a.i+b.i;
  52. return res;
  53. endfunction
  54. //定义复数减法
  55. function Complex complex_sub(Complex a,Complex b);
  56. Complex res;
  57. res.r=a.r-b.r;
  58. res.i=a.i-b.i;
  59. return res;
  60. endfunction
  61. endpackage

 然后是我们的FFT模块:

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2021/07/22 09:50:53
  7. // Design Name:
  8. // Module Name: FFT
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. import complex_type::* ;
  22. module FFT
  23. #(parameter DATA_WIDTH = 32,
  24. parameter N = 8,
  25. parameter STAGE = 3)
  26. (
  27. input logic clk,
  28. input logic rst,
  29. input logic valid,
  30. input Complex data_in [0:N-1],
  31. output Complex data_out [0:N-1],
  32. output logic ready
  33. );
  34. logic valid_ff1;
  35. logic valid_ff2;
  36. logic valid_ff3;
  37. //定义旋转因子常量
  38. Complex WN0 = '{65536,0};
  39. Complex WN1 = '{46340,-46340};
  40. Complex WN2 = '{0,-65535};
  41. Complex WN3 = '{-46340,-46341};
  42. //中间结果
  43. Complex tmp [0:STAGE][0:N-1]; //STAGE=log2(N),为蝶形运算单元的级数
  44. //蝶形运算
  45. //第1级 tmp[0]-->tmp[1]
  46. always_ff@(posedge clk) //第一级,蝶形单元跨度为1=2^0
  47. for(int i=0;i<N;i+=2)
  48. begin
  49. tmp[1][i]<=complex_add(tmp[0][i],complex_mul(tmp[0][i+1],WN0));
  50. tmp[1][i+1]<=complex_sub(tmp[0][i],complex_mul(tmp[0][i+1],WN0));
  51. // $write("mult=%d,%d\n",complex_mul(tmp[0][1],WN0).r,complex_mul(tmp[0][1],WN0).i);
  52. // for(int j=0;j<2;j++)
  53. // $write("i=%d,%d,%d\n",i+j,tmp[1][i+j].r>>>16,tmp[1][i+j].i>>>16);
  54. end
  55. //第2级 tmp[1]-->tmp[2]
  56. always_ff@(posedge clk)
  57. for(int i=0;i<N;i+=4) //第二级,蝶形单元跨度为2=2^1
  58. begin
  59. tmp[2][i]<=complex_add(tmp[1][i],complex_mul(tmp[1][i+2],WN0));
  60. tmp[2][i+1]<=complex_add(tmp[1][i+1],complex_mul(tmp[1][i+3],WN2));
  61. tmp[2][i+2]<=complex_sub(tmp[1][i],complex_mul(tmp[1][i+2],WN0));
  62. tmp[2][i+3]<=complex_sub(tmp[1][i+1],complex_mul(tmp[1][i+3],WN2));
  63. end
  64. //第3级 tmp[2]-->tmp[3]
  65. always_ff@(posedge clk)
  66. for(int i=0;i<N;i+=8) //第三级,蝶形单元跨度为4=2^2 第i级span=2^(i-1)
  67. begin
  68. tmp[3][i]<=complex_add(tmp[2][i],complex_mul(tmp[2][i+4],WN0));
  69. tmp[3][i+1]<=complex_add(tmp[2][i+1],complex_mul(tmp[2][i+5],WN1));
  70. tmp[3][i+2]<=complex_add(tmp[2][i+2],complex_mul(tmp[2][i+6],WN2));
  71. tmp[3][i+3]<=complex_add(tmp[2][i+3],complex_mul(tmp[2][i+7],WN3));
  72. tmp[3][i+4]<=complex_sub(tmp[2][i],complex_mul(tmp[2][i+4],WN0));
  73. tmp[3][i+5]<=complex_sub(tmp[2][i+1],complex_mul(tmp[2][i+5],WN1));
  74. tmp[3][i+6]<=complex_sub(tmp[2][i+2],complex_mul(tmp[2][i+6],WN2));
  75. tmp[3][i+7]<=complex_sub(tmp[2][i+3],complex_mul(tmp[2][i+7],WN3));
  76. end
  77. //data_out
  78. always_comb
  79. begin
  80. for(int i=0;i<N;i++)
  81. data_out[i]=tmp[3][i];
  82. end
  83. //data_in,bit reverse
  84. always_ff@(posedge clk)
  85. begin
  86. tmp[0][0]<=data_in[0];
  87. tmp[0][1]<=data_in[4];
  88. tmp[0][2]<=data_in[2];
  89. tmp[0][3]<=data_in[6];
  90. tmp[0][4]<=data_in[1];
  91. tmp[0][5]<=data_in[5];
  92. tmp[0][6]<=data_in[3];
  93. tmp[0][7]<=data_in[7];
  94. end
  95. //ready,延迟为4个周期,一个周期bit reverse,3个周期计算
  96. always_ff@(posedge clk)
  97. {ready,valid_ff3,valid_ff2,valid_ff1}<={valid_ff3,valid_ff2,valid_ff1,valid};
  98. endmodule

这是一个全流水的FFT计算模块,II=1个时钟周期,ready信号为高时表示结果有效。延迟为4个周期,第一个周期进行bit reverse操作,第2,3,4个周期,则是FFT蝶形运算的3个stage。

最后,是testbench:(本FFT模块采用32位有符号定点数实现,小数部分占16位)

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2021/07/22 12:31:14
  7. // Design Name:
  8. // Module Name: test
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. import complex_type::*;
  22. module test;
  23. parameter N = 8;
  24. Complex IN [0:N-1];
  25. Complex OUT [0:N-1];
  26. logic clk;
  27. logic rst;
  28. logic valid;
  29. logic ready;
  30. initial begin
  31. clk=0;
  32. forever begin
  33. #5 clk=~clk;
  34. end
  35. end
  36. initial begin
  37. rst=1;
  38. #20
  39. rst=0;
  40. end
  41. initial begin
  42. for(int i=0;i<N;i++)
  43. begin
  44. IN[i].r=(i<<12);
  45. IN[i].i=0;
  46. end
  47. end
  48. initial begin
  49. valid=1;
  50. #10
  51. valid=0;
  52. end
  53. always_ff@(posedge clk)
  54. if(ready)
  55. begin
  56. for(int i=0;i<N;i++)
  57. $display("data_out[%d]=%f+%f*i",i,integer'(OUT[i].r)/65536.0,integer'(OUT[i].i)/65536.0);
  58. end
  59. FFT U(
  60. .clk(clk),
  61. .rst(rst),
  62. .data_in(IN),
  63. .data_out(OUT),
  64. .valid(valid),
  65. .ready(ready)
  66. );
  67. endmodule

仿真结果如下:

 

其中,观察定点数的值可以通过如下方式实现:右键波形--->Radix---->RealSettings,然后选择定点数以及小数位数。

最后是C++的运行结果,可以看到,和仿真结果是一致的。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/534756
推荐阅读
相关标签
  

闽ICP备14008679号