├── .gitignore ├── APR ├── .gitignore ├── README.md ├── innovus │ ├── .gitignore │ └── work │ │ ├── .gitignore │ │ ├── fft_multimode.globals │ │ └── setup.tcl └── 多模式FFT处理器Innovus后端流程.pdf ├── LICENSE ├── README.md ├── docs └── README.md ├── figs ├── 128-point FFT output.png ├── 128-point iFFT output.png ├── 256-point FFT output.png ├── 256-point iFFT output.png ├── 512-point FFT output.png ├── 512-point iFFT output.png ├── 64-point FFT output.png ├── 64-point iFFT output.png ├── 64-point simulation wave.png ├── FFT processor arch.png ├── area report.png ├── layout.png └── setup timing report of DC.png ├── lint ├── .gitignore └── spyglass │ ├── .gitignore │ ├── Makefile │ └── run_sg.tcl ├── rtl ├── .gitignore ├── sim │ ├── common-sim-flags.mk │ ├── lib │ │ └── README.md │ ├── tb_src │ │ ├── fft_tb.v │ │ └── reoder_tb.v │ ├── test_vector │ │ ├── fft128_input_im.txt │ │ ├── fft128_input_re.txt │ │ ├── fft256_input_im.txt │ │ ├── fft256_input_re.txt │ │ ├── fft512_input_im.txt │ │ ├── fft512_input_re.txt │ │ ├── fft64_input_im.txt │ │ ├── fft64_input_re.txt │ │ ├── fft_output_im.txt │ │ ├── fft_output_re.txt │ │ ├── ifft128_input_im.txt │ │ ├── ifft128_input_re.txt │ │ ├── ifft256_input_im.txt │ │ ├── ifft256_input_re.txt │ │ ├── ifft512_input_im.txt │ │ ├── ifft512_input_re.txt │ │ ├── ifft64_input_im.txt │ │ └── ifft64_input_re.txt │ ├── vcs │ │ ├── .gitignore │ │ ├── Makefile │ │ └── vcs.mk │ ├── verilator │ │ └── Makefile │ └── xcelium │ │ ├── .gitignore │ │ ├── Makefile │ │ └── xcelium.mk └── src │ ├── bf_rdx2.v │ ├── complex_mult.v │ ├── fft16.v │ ├── fft_multimode.v │ ├── ifft_twiddle_rom.v │ ├── include │ └── .gitignore │ ├── memory │ ├── fft_reoder_sramsp16x256_maskoff.v │ └── sramsp_maskoff.v │ ├── reoder.v │ ├── reserve_bits.v │ ├── shiftreg.v │ ├── switch.v │ └── twiddle_rom.v ├── scripts ├── backup.sh └── clean.sh ├── software ├── README.md ├── bit_reverse.m ├── fft_fixed.m ├── fft_fixed_run.m ├── fft_float.m ├── fft_run.m ├── ifft_fixed.m ├── ifft_fixed_run.m ├── ifft_input_gen.m ├── input_gen.m ├── wave.py └── wn_gen.m └── syn ├── syn_asic ├── .gitignore ├── Makefile ├── README.md └── scripts │ ├── .synopsys_dc.setup │ ├── main.py │ ├── sdc.tcl │ └── synflow.tcl └── syn_fpga ├── .gitignore ├── quartus └── Makefile └── vivado ├── Makefile └── scripts ├── elaborate.tcl ├── impl.tcl └── synth.tcl /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !.gitignore 4 | !*.md 5 | !LICENSE 6 | !*.[cSh] 7 | !*.v 8 | !*.sv 9 | !*.py 10 | !*.cc 11 | !*.cpp 12 | !*.m 13 | !/docs/* 14 | !/lint/* 15 | !/rtl/* 16 | !/scripts/* 17 | !/software/* 18 | !/syn/* 19 | !/APR/* 20 | !/figs/** 21 | -------------------------------------------------------------------------------- /APR/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !*.[cSh] 7 | !*.v 8 | !*.py 9 | !*.cc 10 | !*.cpp 11 | !Makefile 12 | !*.mk 13 | !*.pdf 14 | !/innovus/* 15 | !*.txt 16 | -------------------------------------------------------------------------------- /APR/README.md: -------------------------------------------------------------------------------- 1 | Currently, only the Innovus process is available, and there may be errors in both the process and results. Please be aware of this!!!! 2 | 3 |
4 | 5 | TODO: 6 | 7 | - [ ] Add Foundry SRAM 8 | 9 | - [ ] Auto FloorPlan Script 10 | 11 | - [ ] ICC2 Flow 12 | 13 | ... 14 | -------------------------------------------------------------------------------- /APR/innovus/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !Makefile 7 | !*.mk 8 | !/work/* 9 | -------------------------------------------------------------------------------- /APR/innovus/work/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !.gitignore 4 | !setup.tcl 5 | !fft_multimode.globals 6 | -------------------------------------------------------------------------------- /APR/innovus/work/fft_multimode.globals: -------------------------------------------------------------------------------- 1 | set defHierChar {/} 2 | set locv_inter_clock_use_worst_derate false 3 | set init_oa_search_lib {} 4 | set lsgOCPGainMult 1.000000 5 | set init_verilog {../fft_multimode.v} 6 | set init_pwr_net {VDD} 7 | set init_lef_file {/tools/PDK/tsmc28nm/tn28clpr002e1_1_5a/N28_PRTF_Cad_v1d5a/PR_tech/Cadence/LefHeader/HVH/tsmcn28_10lm7X2RRDL.tlef /tools/PDK/tsmc28nm/TSMCHOME/digital/Back_End/lef/tcbn28hpcplusbwp40p140_110a/lef/tcbn28hpcplusbwp40p140.lef} 8 | set init_top_cell {fft_multimode} 9 | set fpIsMaxIoHeight 0 10 | set init_gnd_net {VSS} 11 | set timing_case_analysis_for_icg_propagation false 12 | 13 | -------------------------------------------------------------------------------- /APR/innovus/work/setup.tcl: -------------------------------------------------------------------------------- 1 | # By BriMonzZY 2 | 3 | 4 | set design_name fft_multimode 5 | set vars(design) $design_name 6 | set vars(rtl_design) $vars(design) 7 | set init_verilog "../fft_multimode.v" 8 | set vars(fp_file) "fft_multimode.fp" 9 | 10 | set init_lef_file "/tools/PDK/tsmc28nm/tn28clpr002e1_1_5a/N28_PRTF_Cad_v1d5a/PR_tech/Cadence/LefHeader/HVH/tsmcn28_10lm7X2ZRDL.tlef" 11 | set vars(lef_files) "/tools/PDK/tsmc28nm/tn28clpr002e1_1_5a/N28_PRTF_Cad_v1d5a/PR_tech/Cadence/LefHeader/HVH/tsmcn28_10lm7X2ZRDL.tlef \ 12 | /tools/PDK/tsmc28nm/TSMCHOME/digital/Back_End/lef/tcbn28hpcplusbwp40p140_110a/lef/tcbn28hpcplusbwp40p140.lef" 13 | set init_top_cell $vars(design) 14 | set init_gnd_net VSS 15 | set init_pwr_net VDD 16 | set vars(cts_cells) clk 17 | 18 | set vars(local_cpus) 8 19 | set vars(process) 28;# e.g. 16, 28 20 | 21 | set vars(rc_corners) "cworst_m40c cbest_125c ctyp_85c cworst_125c" 22 | set vars(delay_corners) "dc_slow_corner_cworst_m40c dc_typ_corner_ctyp_85c dc_fast_corner_cbest_125c" 23 | set vars(constraint_modes) "merged" ;# set vars(constraint_modes) "merged merged_1g" 24 | 25 | set slow_corner ssgnp_0p90v_m40c ;# e.g. ssgnp_0p72v_0c 26 | set typ_corner tt_1p00v_85c ;# e.g. tt_0p80v_85c 27 | set fast_corner ffgnp_1p05v_125c ;# e.g. ffgnp_0p88v_125c 28 | 29 | set vars(merged_slow_corner_cworst_m40c,delay_corner) [lindex $vars(delay_corners) 0] 30 | set vars(merged_fast_corner_cbest_125c,delay_corner) [lindex $vars(delay_corners) 2] 31 | set vars(merged_slow_corner_cworst_m40c,constraint_mode) [lindex $vars(constraint_modes) 0] 32 | set vars(merged_fast_corner_cbest_125c,constraint_mode) [lindex $vars(constraint_modes) 0] 33 | set vars(dc_fast_corner_cbest_125c,rc_corner) [lindex $vars(rc_corners) 1] 34 | set vars(dc_typ_corner_ctyp_85c,rc_corner) [lindex $vars(rc_corners) 2] 35 | set vars(dc_fast_corner_cbest_125c,library_set) $fast_corner 36 | set vars(dc_typ_corner_ctyp_85c,library_set) $typ_corner 37 | set vars(dc_slow_corner_cworst_m40c,library_set) $slow_corner 38 | set vars(dc_slow_corner_cworst_m40c,rc_corner) [lindex $vars(rc_corners) 0] 39 | 40 | set vars(setup_analysis_views) "merged_slow_corner_cworst_m40c" 41 | set vars(hold_analysis_views) "merged_fast_corner_cbest_125c" 42 | set vars(setup_analysis_views) "merged_slow_corner_cworst_m40c" 43 | set vars(hold_analysis_views) "merged_fast_corner_cbest_125c" 44 | 45 | set vars(default_setup_view) [lindex $vars(setup_analysis_views) 0] 46 | set vars(default_hold_view) [lindex $vars(hold_analysis_views) 0] 47 | set vars(active_setup_views) $vars(setup_analysis_views) 48 | set vars(active_hold_views) $vars(hold_analysis_views) 49 | 50 | set qrc_file(cworst) "/tools/PDK/tsmc28nm/RC_QRC_cln28hpc+_1p10m_5x2y2z_ut-alrdl_9corners_1.3a/RC_QRC_cln28hpc+_1p10m+ut-alrdl_5x2y2z_cworst_T/qrcTechFile" 51 | set qrc_file(cbest) "/tools/PDK/tsmc28nm/RC_QRC_cln28hpc+_1p10m_5x2y2z_ut-alrdl_9corners_1.3a/RC_QRC_cln28hpc+_1p10m+ut-alrdl_5x2y2z_cbest/qrcTechFile" 52 | set qrc_file(rcworst) "/tools/PDK/tsmc28nm/RC_QRC_cln28hpc+_1p10m_5x2y2z_ut-alrdl_9corners_1.3a/RC_QRC_cln28hpc+_1p10m+ut-alrdl_5x2y2z_rcworst_T/qrcTechFile" 53 | set qrc_file(rcbest) "/tools/PDK/tsmc28nm/RC_QRC_cln28hpc+_1p10m_5x2y2z_ut-alrdl_9corners_1.3a/RC_QRC_cln28hpc+_1p10m+ut-alrdl_5x2y2z_rcbest/qrcTechFile" 54 | set qrc_file(typical) "/tools/PDK/tsmc28nm/RC_QRC_cln28hpc+_1p10m_5x2y2z_ut-alrdl_9corners_1.3a/RC_QRC_cln28hpc+_1p10m+ut-alrdl_5x2y2z_typical/qrcTechFile" 55 | set vars(cworst_m40c,qx_tech_file) $qrc_file(cworst) 56 | set vars(cbest_125c,qx_tech_file) $qrc_file(cbest) 57 | set vars(ctyp_85c,qx_tech_file) $qrc_file(typical) 58 | set vars(cworst_125c,qx_tech_file) $qrc_file(cworst) 59 | 60 | set stdcell_library($fast_corner) "/tools/PDK/tsmc28nm/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn28hpcplusbwp40p140_180a/tcbn28hpcplusbwp40p140ffg0p88v0c.lib" 61 | set stdcell_library($slow_corner) "/tools/PDK/tsmc28nm/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn28hpcplusbwp40p140_180a/tcbn28hpcplusbwp40p140ffg0p88v0c.lib" 62 | set stdcell_library($typ_corner) "/tools/PDK/tsmc28nm/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn28hpcplusbwp40p140_180a/tcbn28hpcplusbwp40p140ffg0p88v0c.lib" 63 | 64 | set macro_ctl_list [list ] 65 | set macro(lef) [list ] 66 | set macro_library($slow_corner) [list ] 67 | set macro_library($typ_corner) [list ] 68 | set macro_library($fast_corner) [list ] 69 | set vars(library_sets) [list $slow_corner $typ_corner $fast_corner] 70 | set vars($slow_corner,timing) [concat $stdcell_library($slow_corner) $macro_library($slow_corner)] 71 | set vars($typ_corner,timing) [concat $stdcell_library($typ_corner) $macro_library($typ_corner)] 72 | set vars($fast_corner,timing) [concat $stdcell_library($fast_corner) $macro_library($fast_corner)] 73 | 74 | set vars(merged,pre_cts_sdc) "../fft_multimode.sdc" 75 | -------------------------------------------------------------------------------- /APR/多模式FFT处理器Innovus后端流程.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/APR/多模式FFT处理器Innovus后端流程.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 BriMonzZY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # multi-mode FFT processor 2 | 3 | Author: BriMonzZY 4 | 5 |
6 | 7 | *FOR STUDY ONLY* 8 | 9 | *I cannot guarantee that this design is correct, it is for reference only!* 10 | 11 |
12 | 13 | ## Introduction 14 | 15 | This repo is a configurable **Simple R2MDC DIF-FFT Processor** implementation from algorithm to GDSII, supporting 64/128/256/512-point Fast Fourier Transform (FFT) and Inverse FFT (IFFT) computations. The design features a complete implementation flow including RTL verification and ASIC synthesis. 16 | 17 |
18 | 19 | 20 | File hierarchy: 21 | 22 | ```txt 23 | . 24 | ├── README.md 25 | ├── software # algorithm and data gen 26 | ├── rtl 27 | | ├── src # design files 28 | | └── sim 29 | | ├── tb_src # testbench files 30 | | ├── vcs # run VCS simulation 31 | | ├── xcelium # run xcelium simulation 32 | | └── verilator # TODO 33 | ├── syn # Synthesis 34 | | ├── syn_asic 35 | | | └── scripts # ASIC synthesize scripts 36 | | └── syn_fpga # TODO 37 | ├── APR # Auto Placement & Router 38 | | └── innovus # run PnR flow with innovus 39 | ├── scripts # clean or backup scripts 40 | └── (backup) 41 | 42 | ``` 43 | 44 |
45 | 46 | ## Architecture 47 | 48 | Radix-2 MDC DIF-FFT: 49 | 50 | 51 | 52 |
53 | 54 | ## Quick Start 55 | 56 | Input and output ports of the FFT processor: 57 | 58 | | **name** | **in/out** | **width** | **description** | 59 | | --------- | ---------- | --------- | ------------------------------------------------------------ | 60 | | clk | I | 1 | system clock | 61 | | rst_n | I | 1 | System asynchronous reset, low level effective | 62 | | inv | I | 1 | Mode control, 0 represents FFT operation, 1 represents IFFT operation | 63 | | np | I | 2 | FFT/IFFT points: 0 represents 64 points, 1 represents 128 points, 2 represents 256 points, and 3 represents 512 points | 64 | | stb | I | 1 | Input data valid indication | 65 | | sop_in | I | 1 | The first valid data indicator for each set of input data (64 numbers) indicates that the high level is valid | 66 | | x_re | I | 16 | Input data real part, binary complement fixed-point format | 67 | | x_im | I | 16 | Input data imaginary part, binary complement fixed-point format | 68 | | valid_out | O | 1 | Effective indication of output data | 69 | | sop_out | O | 1 | The first valid data indicator for each set of output data (64 numbers) | 70 | | y_re | O | 16 | Output data real part, binary complement fixed-point format | 71 | | y_im | O | 16 | Output data imaginary part, binary complement fixed-point format | 72 | 73 |
74 | 75 | Edit `rtl/sim/test_vector/fft*_input_re.txt` to change the real part of FFT input data. 76 | 77 | Edit `rtl/sim/test_vector/fft*_input_im.txt` to change the imag part of FFT input data. 78 | 79 | Edit `rtl/sim/test_vector/ifft*_input_re.txt` to change the real part of IFFT input data. 80 | 81 | Edit `rtl/sim/test_vector/ifft*_input_im.txt` to change the imag part of IFFT input data. 82 | 83 | Edit the line (5 23 24 64 65) of file `rtl/sim/tb_src/fft_tb.v` to Change the input or the mode of processor. 84 | 85 | The simulation output will generated in `fft_output_re.txt `and `fft_output_im.txt` , you can draw a waveform of the output by using `python software/wave.py`. 86 | 87 | you can change the macro in file `fft_reoder_sramsp16x256_maskoff.v` to use Foundry SRAM or not. 88 | 89 |
90 | 91 | 92 | ### Simulation 93 | 94 | run simulation with Synopsys VCS: 95 | ```bash 96 | cd rtl/sim/vcs 97 | # make help 98 | make run 99 | ``` 100 | 101 | run simulation with Cadence XCELIUM: 102 | ```bash 103 | cd rtl/sim/xcelium 104 | # make help 105 | make simx 106 | ``` 107 | 108 | debug with Synopsys Verdi: 109 | ```bash 110 | cd rtl/sim/vcs 111 | make debug 112 | make rundebug 113 | make wave # show waveform using verdi 114 | ``` 115 | 116 |
117 | 118 | ### Synthesis 119 | 120 | run synthesis with Design Compiler: 121 | 122 | ```bash 123 | cd syn/syn_asic 124 | # make help 125 | make syn 126 | ``` 127 | 128 |
129 | 130 | ### APR 131 | 132 | run PnR with INNOVUS: 133 | 134 | see `APR/innovus/README.md`. 135 | 136 |
137 | 138 | ## Result of simulation 139 | 140 | Simulation waveform of 64-point FFT mode of our FFT processor: 141 | 142 | 143 | 144 |
145 | 146 |
147 | 148 | ### FFT 149 | 150 | We use 0.005*sin(t) for real input ( Q15 format ) and imag input to calculate FFT output. 151 | 152 | The following is the output of the FFT processor: 153 | 154 |
155 | 156 | 64-point FFT output: 157 | 158 | 159 | 160 | The maximum error output from the Matlab fixed-point model is 13 ( Q15 format ). 161 | 162 |
163 | 164 | 128-point FFT output: 165 | 166 | 167 | 168 | The maximum error output from the Matlab fixed-point model is 28 ( Q15 format ). 169 | 170 |
171 | 172 | 256-point FFT output: 173 | 174 | 175 | 176 | The maximum error output from the Matlab fixed-point model is 61 ( Q15 format ). 177 | 178 |
179 | 180 | 512-point FFT output: 181 | 182 | 183 | 184 | The maximum error output from the Matlab fixed-point model is 120 ( Q15 format ). 185 | 186 |
187 | 188 | ### iFFT 189 | 190 | We use n, n-1,n-2,..., 0 as raw input to calculate FFT as input of iFFT. 191 | 192 | The following is the output of the iFFT model of FFT processor: 193 | 194 |
195 | 196 | 64-point iFFT output: 197 | 198 | 199 | 200 | The maximum error output from the Matlab fixed-point model is 1 ( Q15 format ). 201 | 202 |
203 | 204 | 128-point iFFT output: 205 | 206 | 207 | 208 | The maximum error output from the Matlab fixed-point model is 1 ( Q15 format ). 209 | 210 |
211 | 212 | 256-point iFFT output: 213 | 214 | 215 | 216 | The maximum error output from the Matlab fixed-point model is 1 ( Q15 format ). 217 | 218 |
219 | 220 | 512-point iFFT output 221 | 222 | 223 | 224 | The output is **incorrect** due to the overflow of intermediate result bits within our current implementation. 225 | 226 |
227 | 228 | ## Result of Synthesis 229 | 230 | The FFT processor can run at **701.7 MHz** at TSMC N28, since we haven't optimized timing yet. 231 | 232 |
233 | 234 | setup timing report generated by Design Compiler: 235 | 236 | 237 | 238 | 239 | 240 |
241 | 242 | ## Result of PnR 243 | 244 |
245 | 246 | We use TSMC N28 to impl this project 247 | 248 | Area: 455x455=0.207mm^2 249 | 250 | Layout of FFT processor: 251 | 252 | 253 | 254 |
255 | 256 | ## Future Work 257 | 258 | 1. Using a larger bit width for intermediate calculations to reduce accuracy loss. 259 | 1. Multi-parallel MDC architecture. 260 | 2. Optimize timing and SRAM load/stroe. 261 | 3. Use Foundry ROM. 262 | 3. Add ICC2 flow. 263 | 4. Add STA and signoff flow. 264 | 265 |
266 | 267 | The design space for FFT hardware accelerators is still relatively large, and there are SDF MDF、SDC、MDC、SC、MSC、SFF、 There are even circuit architectures such as Radix-2 Combined SDC-SDF (R2CSS) and others; In terms of storage architecture, optimization can be achieved from aspects such as storage space and storage organizational structure There are also different combinations of Radix, choices of DIT and DIF, and so on. Different fields and applications require different characteristics and architectures. How FFT acceleration architecture performs Trade off is also a part that needs to be studied. 268 | 269 | In short, the current FFT processor design cannot be considered a future work. The current work is only a reproduction of the basic circuit structure that is easy to understand. 270 | 271 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/docs/README.md -------------------------------------------------------------------------------- /figs/128-point FFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/128-point FFT output.png -------------------------------------------------------------------------------- /figs/128-point iFFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/128-point iFFT output.png -------------------------------------------------------------------------------- /figs/256-point FFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/256-point FFT output.png -------------------------------------------------------------------------------- /figs/256-point iFFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/256-point iFFT output.png -------------------------------------------------------------------------------- /figs/512-point FFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/512-point FFT output.png -------------------------------------------------------------------------------- /figs/512-point iFFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/512-point iFFT output.png -------------------------------------------------------------------------------- /figs/64-point FFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/64-point FFT output.png -------------------------------------------------------------------------------- /figs/64-point iFFT output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/64-point iFFT output.png -------------------------------------------------------------------------------- /figs/64-point simulation wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/64-point simulation wave.png -------------------------------------------------------------------------------- /figs/FFT processor arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/FFT processor arch.png -------------------------------------------------------------------------------- /figs/area report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/area report.png -------------------------------------------------------------------------------- /figs/layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/layout.png -------------------------------------------------------------------------------- /figs/setup timing report of DC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/figs/setup timing report of DC.png -------------------------------------------------------------------------------- /lint/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !Makefile 7 | !*.tcl 8 | !/spyglass/* 9 | -------------------------------------------------------------------------------- /lint/spyglass/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !Makefile 7 | !*.tcl 8 | spyglass-1/ 9 | -------------------------------------------------------------------------------- /lint/spyglass/Makefile: -------------------------------------------------------------------------------- 1 | 2 | sg: 3 | sg_shell -tcl sg_lint.tcl 4 | 5 | help: 6 | sg_shell -help 7 | 8 | clean: 9 | rm -rf sg_shell_command.log spyglass-1 10 | -------------------------------------------------------------------------------- /lint/spyglass/run_sg.tcl: -------------------------------------------------------------------------------- 1 | set design_name "example" 2 | 3 | # read in files 4 | read_file -type sourcelist ./sim_common_files.f 5 | # read_file -type gateslib ../../lib/ 6 | # read_file -type sgdc ../../src/sdc/${design_name}.sgdc 7 | 8 | # setup 9 | set_option top ${design_name} 10 | # set_option sdc2sgdc yes 11 | current_goal Design_Read -top ${design_name} 12 | link_design -force 13 | 14 | # run lint 15 | current_goal lint/lint_rtl -top ${design_name} 16 | run_goal 17 | 18 | # save project 19 | save_project -force 20 | -------------------------------------------------------------------------------- /rtl/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !*.[cSh] 7 | !*.v 8 | !*.py 9 | !*.cc 10 | !*.cpp 11 | !Makefile 12 | !*.mk 13 | !/sim/* 14 | !/src/* 15 | !*.txt 16 | -------------------------------------------------------------------------------- /rtl/sim/common-sim-flags.mk: -------------------------------------------------------------------------------- 1 | ## Refer to Chipyard 2 | 3 | #---------------------------------------------------------------------------------------- 4 | # common gcc configuration/optimization 5 | #---------------------------------------------------------------------------------------- 6 | 7 | SIM_OPT_CXXFLAGS := -O3 8 | MAX_CPU := $(shell nproc) 9 | 10 | 11 | MODEL_NAME ?= fft_tb 12 | 13 | TB = $(MODEL_NAME) 14 | long_name = $(MODEL_NAME) 15 | 16 | 17 | SIM_CXXFLAGS = \ 18 | $(SIM_OPT_CXXFLAGS) \ 19 | -std=c++17 20 | 21 | CLOCK_PERIOD ?= 1.0 22 | RESET_DELAY ?= 777.7 23 | 24 | SIM_PREPROC_DEFINES = \ 25 | +define+CLOCK_PERIOD=$(CLOCK_PERIOD) \ 26 | +define+RESET_DELAY=$(RESET_DELAY) 27 | 28 | 29 | # rtl 30 | base_dir=$(abspath ../..) 31 | # rtl/sim/vcs 32 | sim_dir=$(abspath .) 33 | 34 | generated_src_name ?= generated-src 35 | gen_dir =$(sim_dir)/$(generated_src_name) 36 | build_dir =$(gen_dir)/$(long_name) 37 | output_dir=$(sim_dir)/output/$(long_name) 38 | 39 | ALL_MODS_FILELIST ?= $(build_dir)/top.all.f 40 | sim_files ?= $(build_dir)/sim_files.f 41 | sim_common_files ?= $(build_dir)/sim_common_files.f 42 | 43 | 44 | 45 | $(build_dir): 46 | mkdir -p $@ 47 | 48 | $(output_dir): 49 | mkdir -p $@ 50 | 51 | $(sim_files): | $(build_dir) 52 | touch $@ && find $(base_dir)/sim/tb_src -name "*.v" >> $@ 53 | 54 | $(ALL_MODS_FILELIST): | $(build_dir) 55 | touch $@ && find $(base_dir)/src -name "*.v" -o -name "*.h" -o -name "*.vh" -o -name "*.svh" >> $@ 56 | 57 | $(sim_common_files): $(sim_files) $(ALL_MODS_FILELIST) 58 | sort -u $(sim_files) $(ALL_MODS_FILELIST) | grep -v '.*\.\(svh\|h\)$$' >> $@ 59 | -------------------------------------------------------------------------------- /rtl/sim/lib/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/rtl/sim/lib/README.md -------------------------------------------------------------------------------- /rtl/sim/tb_src/fft_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module fft_tb(); 4 | 5 | parameter N = 512; 6 | localparam CLK_PERIOD = 10; 7 | 8 | reg clk, rst_n; 9 | reg [15:0] x_re; 10 | reg [15:0] x_im; 11 | reg inv; 12 | reg [1:0] np; 13 | reg stb; 14 | reg sop_in; 15 | wire valid_out; 16 | wire sop_out; 17 | wire [15:0] y_re; 18 | wire [15:0] y_im; 19 | 20 | reg [15:0] fft_input_re [0:N-1]; 21 | reg [15:0] fft_input_im [0:N-1]; 22 | initial begin 23 | $readmemh("../../../test_vector/fft512_input_re.txt", fft_input_re); 24 | $readmemh("../../../test_vector/fft512_input_im.txt", fft_input_im); 25 | end 26 | 27 | integer fft_output_re; 28 | integer fft_output_im; 29 | initial begin 30 | fft_output_re = $fopen("../../../test_vector/fft_output_re.txt", "w"); 31 | fft_output_im = $fopen("../../../test_vector/fft_output_im.txt", "w"); 32 | forever begin 33 | @(posedge clk); 34 | if(valid_out) begin 35 | if(y_re[15]) 36 | $fwrite(fft_output_re, "0x%h ", -$signed(y_re)); 37 | else 38 | $fwrite(fft_output_re, "0x%h ", y_re); 39 | if(y_im[15]) 40 | $fwrite(fft_output_im, "0x%h ", -$signed(y_im)); 41 | else 42 | $fwrite(fft_output_im, "0x%h ", y_im); 43 | end 44 | end 45 | end 46 | 47 | initial begin 48 | clk = 1'b0; 49 | forever #(CLK_PERIOD/2) clk = ~clk; 50 | end 51 | 52 | integer i; 53 | initial begin 54 | `ifdef DEBUG 55 | `ifdef FSDB 56 | $fsdbDumpfile("fft_tb.fsdb"); 57 | $fsdbDumpvars(0, fft_tb); 58 | $fsdbDumpMDA(0, fft_tb); 59 | `endif 60 | `endif 61 | 62 | // reset and clk 63 | rst_n <= 1'b0; 64 | inv <= 1'b0; 65 | np <= 2'b11; 66 | stb <= 1'b0; 67 | sop_in <= 1'b0; 68 | x_re <= 16'h0; 69 | x_im <= 16'h0; 70 | 71 | repeat (2) @(posedge clk); 72 | rst_n <= 1; 73 | repeat (3) @(posedge clk); 74 | 75 | stb <= 1'b1; 76 | sop_in <= 1'b1; 77 | x_re <= fft_input_re[0]; 78 | x_im <= fft_input_im[0]; 79 | @(posedge clk); 80 | sop_in <= 1'b0; 81 | for(i=1; i 5 | ## make run MODEL_NAME= 6 | ## make debug MODEL_NAME= 7 | ## make rundebug MODEL_NAME= 8 | ## make wave 9 | ## make clean 10 | ## 11 | 12 | help: 13 | @echo " - make simv MODEL_NAME=" 14 | @echo " - make run MODEL_NAME=" 15 | @echo " - make debug MODEL_NAME=" 16 | @echo " - make rundebug MODEL_NAME=" 17 | @echo " - make wave MODEL_NAME=" 18 | 19 | ######################################################################################### 20 | # vcs makefile 21 | ######################################################################################### 22 | # rtl 23 | base_dir=$(abspath ../..) 24 | # rtl/sim/vcs 25 | sim_dir=$(abspath .) 26 | 27 | ######################################################################################### 28 | # name of simulator (used to generate *.f arguments file) 29 | ######################################################################################### 30 | sim_name = vcs 31 | 32 | ######################################################################################### 33 | # vcs simulator types and rules 34 | ######################################################################################### 35 | sim_prefix = simv 36 | 37 | sim = $(sim_dir)/$(sim_prefix)-$(long_name) 38 | sim_debug = $(sim_dir)/$(sim_prefix)-$(long_name)-debug 39 | 40 | include $(sim_dir)/vcs.mk 41 | 42 | .PHONY: simv debug 43 | simv: $(sim) 44 | debug: $(sim_debug) 45 | 46 | ######################################################################################### 47 | # vcs binary and arguments 48 | ######################################################################################### 49 | VCS := vcs -full64 50 | 51 | VCS_OPTS = $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(SIM_PREPROC_DEFINES) $(VCS_PREPROC_DEFINES) 52 | 53 | ######################################################################################### 54 | # vcs build paths 55 | ######################################################################################### 56 | model_dir = $(build_dir)/$(long_name) 57 | model_dir_debug = $(build_dir)/$(long_name).debug 58 | 59 | ######################################################################################### 60 | # vcs simulator rules 61 | ######################################################################################### 62 | 63 | $(sim): $(sim_common_files) $(output_dir) 64 | rm -rf $(model_dir) 65 | $(VCS) $(VCS_OPTS) -o $@ -Mdir=$(model_dir) 66 | cp $(sim_prefix)-$(long_name) $(output_dir) && rm -rf $(sim_prefix)-$(long_name) 67 | cp -r $(sim_prefix)-$(long_name).daidir $(output_dir) && rm -rf $(sim_prefix)-$(long_name).daidir 68 | 69 | $(sim_debug): $(sim_common_files) $(output_dir) 70 | rm -rf $(model_dir_debug) 71 | $(VCS) $(VCS_OPTS) -o $@ -Mdir=$(model_dir_debug) \ 72 | +define+DEBUG -debug_access+all -kdb -lca 73 | cp $(sim_prefix)-$(long_name)-debug $(output_dir) && rm -rf $(sim_prefix)-$(long_name)-debug 74 | cp -r $(sim_prefix)-$(long_name)-debug.daidir $(output_dir) && rm -rf $(sim_prefix)-$(long_name)-debug.daidir 75 | 76 | run: $(sim) 77 | cd $(output_dir) && ./$(sim_prefix)-$(long_name) 78 | 79 | rundebug: $(sim_debug) 80 | cd $(output_dir) && ./$(sim_prefix)-$(long_name)-debug 81 | 82 | wave: $(sim_common_files) 83 | cd $(output_dir) && ./$(sim_prefix)-$(long_name)-debug && verdi +v2k -sv -f $(sim_common_files) -nologo -ssf $(TB).fsdb 84 | 85 | ######################################################################################### 86 | # general cleanup rules 87 | ######################################################################################### 88 | .PHONY: clean clean-sim clean-sim-debug 89 | 90 | clean: 91 | rm -rf $(gen_dir) $(sim_prefix)-* output ucli.key verdi_config_file 92 | 93 | clean-sim: 94 | rm -rf $(model_dir) $(build_dir)/vc_hdrs.h $(sim) $(sim).daidir output ucli.key 95 | 96 | clean-sim-debug: 97 | rm -rf $(model_dir_debug) $(build_dir)/vc_hdrs.h $(sim_debug) $(sim_debug).daidir output ucli.key 98 | -------------------------------------------------------------------------------- /rtl/sim/vcs/vcs.mk: -------------------------------------------------------------------------------- 1 | 2 | ifndef USE_VPD 3 | get_waveform_flag=+fsdbfile=$(1).fsdb 4 | else 5 | get_waveform_flag=+vcdplusfile=$(1).vpd 6 | endif 7 | 8 | CLOCK_PERIOD ?= 1.0 9 | RESET_DELAY ?= 777.7 10 | 11 | PLATFORM := linux64 12 | NOVAS_PATH := ${NOVAS_HOME}/share/PLI/VCS/$(PLATFORM) 13 | 14 | #---------------------------------------------------------------------------------------- 15 | # gcc configuration/optimization 16 | #---------------------------------------------------------------------------------------- 17 | include $(base_dir)/sim/common-sim-flags.mk 18 | 19 | VCS_CXXFLAGS = $(SIM_CXXFLAGS) 20 | 21 | VCS_CC_OPTS = \ 22 | -CFLAGS "$(VCS_CXXFLAGS)" 23 | 24 | VCS_NONCC_OPTS = \ 25 | -notice \ 26 | -line \ 27 | +lint=all,noVCDE,noONGS,noUI \ 28 | -error=PCWM-L \ 29 | -error=noZMMCM \ 30 | -timescale=1ns/10ps \ 31 | -quiet \ 32 | -q \ 33 | +rad \ 34 | +vcs+lic+wait \ 35 | +vc+list \ 36 | -f $(sim_common_files) \ 37 | -sverilog +systemverilogext+.sv+.svi+.svh+.svt -assert svaext +libext+.sv \ 38 | +v2k +verilog2001ext+.v95+.vt+.vp +libext+.v \ 39 | -debug_pp \ 40 | -top $(TB) \ 41 | +incdir+$(base_dir)/src/include 42 | # -P $(NOVAS_PATH)/novas.tab $(NOVAS_PATH)/pli.a \ 43 | 44 | 45 | VCS_PREPROC_DEFINES = \ 46 | +define+VCS 47 | 48 | ifndef USE_VPD 49 | VCS_PREPROC_DEFINES += +define+FSDB 50 | endif 51 | 52 | 53 | ## For TSMC28 SRAM verilog Model 54 | VCS_PREPROC_DEFINES += +define+UNIT_DELAY 55 | VCS_PREPROC_DEFINES += +define+no_warning 56 | VCS_PREPROC_DEFINES += +define+TSMC_INITIALIZE_MEM 57 | -------------------------------------------------------------------------------- /rtl/sim/verilator/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/rtl/sim/verilator/Makefile -------------------------------------------------------------------------------- /rtl/sim/xcelium/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !*.[cSh] 7 | !*.v 8 | !*.py 9 | !*.cc 10 | !*.cpp 11 | !Makefile 12 | !*.mk 13 | !*.txt 14 | /generated-src/** 15 | /output/** 16 | -------------------------------------------------------------------------------- /rtl/sim/xcelium/Makefile: -------------------------------------------------------------------------------- 1 | ## Refer to Chipyard 2 | 3 | ## by BriMon 4 | ## Email: zzybr@qq.com 5 | ## 6 | ## make simx MODEL_NAME= 7 | ## make run MODEL_NAME= 8 | ## make debug MODEL_NAME= 9 | ## make rundebug MODEL_NAME= 10 | ## make wave 11 | ## make clean 12 | ## 13 | 14 | help: 15 | @echo " - make simx MODEL_NAME=" 16 | @echo " - make debug MODEL_NAME=" 17 | @echo " - make indago MODEL_NAME=" 18 | @echo " - make vdebug MODEL_NAME=" 19 | 20 | 21 | ######################################################################################### 22 | # xcelium makefile 23 | ######################################################################################### 24 | # rtl 25 | base_dir=$(abspath ../..) 26 | # rtl/sim/vcs 27 | sim_dir=$(abspath .) 28 | 29 | sim_name = xrun 30 | 31 | ######################################################################################### 32 | # xcelium simulator types and rules 33 | ######################################################################################### 34 | sim_prefix = simx 35 | sim_workdir = $(build_dir)/xcelium.d 36 | sim_run_tcl = $(build_dir)/xcelium_run.tcl 37 | sim_debug_run_tcl = $(build_dir)/xcelium_debug_run.tcl 38 | 39 | sim = $(sim_dir)/$(sim_prefix)-$(long_name) 40 | sim_debug = $(sim_dir)/$(sim_prefix)-$(long_name)-debug 41 | 42 | include $(sim_dir)/xcelium.mk 43 | 44 | .PHONY: simx debug 45 | simx: $(sim) 46 | debug: $(sim_debug) 47 | 48 | 49 | ######################################################################################### 50 | # xcelium binary and arguments 51 | ######################################################################################### 52 | XCELIUM = xrun 53 | XCELIUM_OPTS = $(XCELIUM_CC_OPTS) $(XCELIUM_NONCC_OPTS) $(PREPROC_DEFINES) 54 | 55 | ######################################################################################### 56 | # xcelium build paths 57 | ######################################################################################### 58 | model_dir = $(build_dir)/$(long_name) 59 | model_dir_debug = $(build_dir)/$(long_name).debug 60 | 61 | ######################################################################################### 62 | # xcelium simulator rules 63 | ######################################################################################### 64 | 65 | $(sim_workdir): $(sim_common_files) $(output_dir) 66 | rm -rf $(model_dir) 67 | $(XCELIUM) -elaborate $(XCELIUM_OPTS) $(XCELIUM_COMMON_ARGS) 68 | 69 | $(sim_run_tcl): $(sim_workdir) 70 | echo "run" >> $@ 71 | echo "exit" >> $@ 72 | 73 | $(sim): $(sim_workdir) $(sim_run_tcl) 74 | echo "#!/usr/bin/env bash" > $@ 75 | echo "$(XCELIUM) +permissive -R -input $(sim_run_tcl) $(XCELIUM_COMMON_ARGS) +permissive-off \$$INPUT_ARGS" >> $@ 76 | chmod +x $@ 77 | cp $(sim_prefix)-$(long_name) $(output_dir) && rm -rf $(sim_prefix)-$(long_name) 78 | cd $(output_dir) && ./$(sim_prefix)-$(long_name) 79 | 80 | 81 | $(sim_debug_run_tcl): $(sim_workdir) 82 | echo "ida_database -open -name=\"ida.db\"" >> $@ 83 | echo "ida_probe -log -sv_flow -uvm_reg -log_objects -sv_modules -wave -wave_probe_args= \"tb -depth all -all -memories -variables -packed 10000000 -unpacked 10000000 -dynamic\" -wave_glitch_recording" >> $@ 84 | echo "run" >> $@ 85 | echo "exit" >> $@ 86 | 87 | $(sim_debug): $(sim_workdir) $(sim_debug_run_tcl) 88 | echo "#!/usr/bin/env bash" > $@ 89 | echo "$(XCELIUM) +permissive -R -input $(sim_debug_run_tcl) $(XCELIUM_COMMON_ARGS) +permissive-off \$$INPUT_ARGS" >> $@ 90 | chmod +x $@ 91 | cp $(sim_prefix)-$(long_name)-debug $(output_dir) && rm -rf $(sim_prefix)-$(long_name)-debug 92 | cd $(output_dir) && ./$(sim_prefix)-$(long_name)-debug 93 | 94 | indago: 95 | cd $(output_dir) && indago 96 | 97 | vdebug: 98 | cd $(output_dir) && verisium_debug 99 | 100 | ######################################################################################### 101 | # create vcd rules 102 | ######################################################################################### 103 | .PRECIOUS: $(output_dir)/%.vcd %.vcd 104 | $(output_dir)/%.vcd: $(output_dir)/% $(sim_debug) 105 | (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) 106 | 107 | ######################################################################################### 108 | # general cleanup rules 109 | ######################################################################################### 110 | .PHONY: clean clean-sim clean-sim-debug 111 | clean: 112 | rm -rf $(CLASSPATH_CACHE) output $(gen_dir) $(sim_prefix)-* 113 | 114 | clean-sim: 115 | rm -rf $(model_dir) $(sim) $(sim_workdir) $(sim_run_tcl) ucli.key bpad_*.err sigusrdump.out dramsim*.log 116 | 117 | clean-sim-debug: 118 | rm -rf $(model_dir_debug) $(sim_debug) $(sim_workdir) $(sim_debug_run_tcl) ucli.key bpad_*.err sigusrdump.out dramsim*.log 119 | -------------------------------------------------------------------------------- /rtl/sim/xcelium/xcelium.mk: -------------------------------------------------------------------------------- 1 | ## Refer to Chipyard 2 | 3 | # If ntb_random_seed unspecified, xcelium uses 1 as constant seed. 4 | # Set ntb_random_seed_automatic to actually get a random seed 5 | ifdef RANDOM_SEED 6 | SEED_FLAG=+ntb_random_seed=$(RANDOM_SEED) 7 | else 8 | SEED_FLAG=+ntb_random_seed_automatic 9 | endif 10 | 11 | CLOCK_PERIOD ?= 1.0 12 | RESET_DELAY ?= 777.7 13 | 14 | #---------------------------------------------------------------------------------------- 15 | # gcc configuration/optimization 16 | #---------------------------------------------------------------------------------------- 17 | include $(base_dir)/sim/common-sim-flags.mk 18 | 19 | 20 | XC_CXX_PREFIX=-Wcxx, 21 | XC_LD_PREFIX=-Wld, 22 | 23 | REMOVE_RPATH=-Wl,-rpath% 24 | 25 | XCELIUM_CXXFLAGS = $(addprefix $(XC_CXX_PREFIX), $(SIM_CXXFLAGS)) 26 | XCELIUM_LDFLAGS = $(addprefix $(XC_LD_PREFIX), $(filter-out $(REMOVE_RPATH), $(SIM_LDFLAGS))) 27 | 28 | XCELIUM_COMMON_ARGS = \ 29 | -64bit \ 30 | -xmlibdirname $(sim_workdir) \ 31 | -l /dev/null \ 32 | -log_xmsc_run /dev/null 33 | 34 | XCELIUM_CC_OPTS = \ 35 | $(XCELIUM_CXXFLAGS) \ 36 | $(XCELIUM_LDFLAGS) \ 37 | -enable_rpath 38 | 39 | XCELIUM_NONCC_OPTS = \ 40 | -fast_recompilation \ 41 | -top $(TB) \ 42 | -sv \ 43 | -ALLOWREDEFINITION \ 44 | -timescale 1ns/10ps \ 45 | -define INTCNOPWR \ 46 | -define INTC_NO_PWR_PINS \ 47 | -define INTC_EMULATION \ 48 | -f $(sim_common_files) \ 49 | -glsperf \ 50 | -notimingchecks \ 51 | -delay_mode zero 52 | 53 | PREPROC_DEFINES = \ 54 | -define XCELIUM \ 55 | -define CLOCK_PERIOD=$(CLOCK_PERIOD) \ 56 | -define RESET_DELAY=$(RESET_DELAY) \ 57 | -define PRINTF_COND=$(TB).printf_cond \ 58 | -define STOP_COND=!$(TB).reset \ 59 | -define MODEL=$(MODEL) \ 60 | -define RANDOMIZE_MEM_INIT \ 61 | -define RANDOMIZE_REG_INIT \ 62 | -define RANDOMIZE_GARBAGE_ASSIGN \ 63 | -define RANDOMIZE_INVALID_ASSIGN 64 | 65 | 66 | PREPROC_DEFINES += +define+FSDB 67 | 68 | -------------------------------------------------------------------------------- /rtl/src/bf_rdx2.v: -------------------------------------------------------------------------------- 1 | // Author: brimonzzy 2 | // Create Date: 2025/2/13 3 | // Description: Gentleman-Sande algorithm Radix-2 Butterfly unit 4 | // module bf_rdx2 and module bf_rdx2_noW 5 | 6 | module bf_rdx2 ( 7 | input signed [15:0] x0_re, 8 | input signed [15:0] x0_im, 9 | input signed [15:0] x1_re, 10 | input signed [15:0] x1_im, 11 | input signed [15:0] w_re, 12 | input signed [15:0] w_im, 13 | output signed [15:0] y0_re, 14 | output signed [15:0] y0_im, 15 | output signed [15:0] y1_re, 16 | output signed [15:0] y1_im 17 | ); 18 | 19 | wire [15:0] add1_re, add1_im, sub2_re, sub2_im, mul2_re, mul2_im; 20 | 21 | complex_add add1_u ( 22 | .x0_re(x0_re), 23 | .x0_im(x0_im), 24 | .x1_re(x1_re), 25 | .x1_im(x1_im), 26 | .res_re(add1_re), 27 | .res_im(add1_im) 28 | ); 29 | 30 | complex_sub sub2_u ( 31 | .x0_re(x0_re), 32 | .x0_im(x0_im), 33 | .x1_re(x1_re), 34 | .x1_im(x1_im), 35 | .res_re(sub2_re), 36 | .res_im(sub2_im) 37 | ); 38 | 39 | complex_mult mul2_u ( 40 | .x0_re(sub2_re), 41 | .x0_im(sub2_im), 42 | .x1_re(w_re), 43 | .x1_im(w_im), 44 | .res_re(mul2_re), 45 | .res_im(mul2_im) 46 | ); 47 | 48 | assign y0_re = add1_re; 49 | assign y0_im = add1_im; 50 | assign y1_re = mul2_re; 51 | assign y1_im = mul2_im; 52 | 53 | endmodule 54 | 55 | 56 | module bf_rdx2_noW ( 57 | input signed [15:0] x0_re, 58 | input signed [15:0] x0_im, 59 | input signed [15:0] x1_re, 60 | input signed [15:0] x1_im, 61 | output signed [15:0] y0_re, 62 | output signed [15:0] y0_im, 63 | output signed [15:0] y1_re, 64 | output signed [15:0] y1_im 65 | ); 66 | 67 | wire [15:0] add1_re, add1_im, sub2_re, sub2_im; 68 | 69 | complex_add add1_u ( 70 | .x0_re(x0_re), 71 | .x0_im(x0_im), 72 | .x1_re(x1_re), 73 | .x1_im(x1_im), 74 | .res_re(add1_re), 75 | .res_im(add1_im) 76 | ); 77 | 78 | complex_sub sub2_u ( 79 | .x0_re(x0_re), 80 | .x0_im(x0_im), 81 | .x1_re(x1_re), 82 | .x1_im(x1_im), 83 | .res_re(sub2_re), 84 | .res_im(sub2_im) 85 | ); 86 | 87 | assign y0_re = add1_re; 88 | assign y0_im = add1_im; 89 | assign y1_re = sub2_re; 90 | assign y1_im = sub2_im; 91 | 92 | endmodule 93 | -------------------------------------------------------------------------------- /rtl/src/complex_mult.v: -------------------------------------------------------------------------------- 1 | // Author: brimonzzy 2 | // Create Date: 2025/2/13 3 | // Description: Complex multiplier 4 | // Complex Adder 5 | // Complex Subtractor 6 | 7 | module complex_mult #( 8 | parameter useGauss = 0 9 | )( 10 | input signed [15:0] x0_re, 11 | input signed [15:0] x0_im, 12 | input signed [15:0] x1_re, 13 | input signed [15:0] x1_im, 14 | output signed [15:0] res_re, 15 | output signed [15:0] res_im 16 | ); 17 | 18 | function signed [15:0] saturate(input signed [18:0] value); 19 | begin 20 | if (value > 32767) saturate = 16'h7FFF; 21 | else if (value < -32768) saturate = 16'h8000; 22 | else saturate = value[15:0]; 23 | end 24 | endfunction 25 | 26 | generate 27 | if(useGauss) begin 28 | // k1 = x1_re * (x0_re + x0_im); 29 | // k2 = x0_re * (x1_im - x1_re); 30 | // k3 = x0_im * (x1_re + x1_im); 31 | // res_re = k1 - k3; 32 | // res_im = k1 + k2; 33 | // Intermediate sums and differences (17-bit to handle overflow) 34 | wire signed [16:0] sum_x0 = x0_re + x0_im; 35 | wire signed [16:0] diff_x0 = x0_re - x0_im; 36 | wire signed [16:0] sum_x1 = x1_re + x1_im; 37 | wire signed [16:0] diff_x1 = x1_re - x1_im; 38 | 39 | // Extend to 32 bits for multiplication 40 | wire signed [31:0] k1 = sum_x0 * x1_re; // Q15 * Q15 = Q30 41 | wire signed [31:0] k2 = diff_x0 * x1_im; // Q15 * Q15 = Q30 42 | wire signed [31:0] k3 = x0_im * sum_x1; // Q15 * Q15 = Q30 43 | 44 | // Adjust back to Q15 format 45 | assign res_re = (k1 - k3) >>> 15; 46 | assign res_im = (k1 + k2) >>> 15; 47 | 48 | end else begin 49 | // res_re = x0_re * x1_re - x0_im * x1_im; 50 | // res_im = x0_re * x1_im + x0_im * x1_re; 51 | // Multiply components (results are in Q30 format) 52 | wire signed [31:0] mul_re_re = x0_re * x1_re; 53 | wire signed [31:0] mul_im_im = x0_im * x1_im; 54 | wire signed [31:0] mul_re_im = x0_re * x1_im; 55 | wire signed [31:0] mul_im_re = x0_im * x1_re; 56 | 57 | wire signed [32:0] sub_re = {mul_re_re[31], mul_re_re} - {mul_im_im[31], mul_im_im}; 58 | wire signed [32:0] add_im = {mul_re_im[31], mul_re_im} + {mul_im_re[31], mul_im_re}; 59 | 60 | // Adjust back to Q15 format 61 | assign res_re = saturate(sub_re >>> 15); 62 | assign res_im = saturate(add_im >>> 15); 63 | 64 | end 65 | endgenerate 66 | 67 | endmodule 68 | 69 | module complex_add ( 70 | input signed [15:0] x0_re, 71 | input signed [15:0] x0_im, 72 | input signed [15:0] x1_re, 73 | input signed [15:0] x1_im, 74 | output signed [15:0] res_re, 75 | output signed [15:0] res_im 76 | ); 77 | 78 | assign res_re = x0_re + x1_re; 79 | assign res_im = x0_im + x1_im; 80 | 81 | endmodule 82 | 83 | module complex_sub ( 84 | input signed [15:0] x0_re, 85 | input signed [15:0] x0_im, 86 | input signed [15:0] x1_re, 87 | input signed [15:0] x1_im, 88 | output signed [15:0] res_re, 89 | output signed [15:0] res_im 90 | ); 91 | 92 | assign res_re = x0_re - x1_re; 93 | assign res_im = x0_im - x1_im; 94 | 95 | endmodule 96 | 97 | -------------------------------------------------------------------------------- /rtl/src/fft16.v: -------------------------------------------------------------------------------- 1 | // 16-points R2MDC DIF-FFT 2 | 3 | module fft16 ( 4 | input clk, 5 | input rst_n, 6 | input stb, // Input data valid (active high) 7 | input sop_in, // The first valid data in the input stream 8 | input [15:0] x_re, // Input real part 9 | input [15:0] x_im, // Input imaginary part 10 | output valid_out, // Output data valid (active high) 11 | output sop_out, // The first valid data in the output stream 12 | output [15:0] y_re, // Output real part 13 | output [15:0] y_im // Output imaginary part 14 | ); 15 | 16 | wire [15:0] bf_0_x0_re; 17 | wire [15:0] bf_0_x0_im; 18 | wire [15:0] bf_0_x1_re; 19 | wire [15:0] bf_0_x1_im; 20 | wire [15:0] bf_0_w_re; 21 | wire [15:0] bf_0_w_im; 22 | wire [15:0] bf_0_y0_re; 23 | wire [15:0] bf_0_y0_im; 24 | wire [15:0] bf_0_y1_re; 25 | wire [15:0] bf_0_y1_im; 26 | wire switch_0_sel; 27 | wire [15:0] switch_0_x0_re; 28 | wire [15:0] switch_0_x0_im; 29 | wire [15:0] switch_0_x1_re; 30 | wire [15:0] switch_0_x1_im; 31 | wire [15:0] switch_0_y0_re; 32 | wire [15:0] switch_0_y0_im; 33 | wire [15:0] switch_0_y1_re; 34 | wire [15:0] switch_0_y1_im; 35 | wire [15:0] bf_1_x0_re; 36 | wire [15:0] bf_1_x0_im; 37 | wire [15:0] bf_1_x1_re; 38 | wire [15:0] bf_1_x1_im; 39 | wire [15:0] bf_1_w_re; 40 | wire [15:0] bf_1_w_im; 41 | wire [15:0] bf_1_y0_re; 42 | wire [15:0] bf_1_y0_im; 43 | wire [15:0] bf_1_y1_re; 44 | wire [15:0] bf_1_y1_im; 45 | wire switch_1_sel; 46 | wire [15:0] switch_1_x0_re; 47 | wire [15:0] switch_1_x0_im; 48 | wire [15:0] switch_1_x1_re; 49 | wire [15:0] switch_1_x1_im; 50 | wire [15:0] switch_1_y0_re; 51 | wire [15:0] switch_1_y0_im; 52 | wire [15:0] switch_1_y1_re; 53 | wire [15:0] switch_1_y1_im; 54 | wire [15:0] bf_2_x0_re; 55 | wire [15:0] bf_2_x0_im; 56 | wire [15:0] bf_2_x1_re; 57 | wire [15:0] bf_2_x1_im; 58 | wire [15:0] bf_2_w_re; 59 | wire [15:0] bf_2_w_im; 60 | wire [15:0] bf_2_y0_re; 61 | wire [15:0] bf_2_y0_im; 62 | wire [15:0] bf_2_y1_re; 63 | wire [15:0] bf_2_y1_im; 64 | wire switch_2_sel; 65 | wire [15:0] switch_2_x0_re; 66 | wire [15:0] switch_2_x0_im; 67 | wire [15:0] switch_2_x1_re; 68 | wire [15:0] switch_2_x1_im; 69 | wire [15:0] switch_2_y0_re; 70 | wire [15:0] switch_2_y0_im; 71 | wire [15:0] switch_2_y1_re; 72 | wire [15:0] switch_2_y1_im; 73 | wire [15:0] bf_3_x0_re; 74 | wire [15:0] bf_3_x0_im; 75 | wire [15:0] bf_3_x1_re; 76 | wire [15:0] bf_3_x1_im; 77 | wire [15:0] bf_3_y0_re; 78 | wire [15:0] bf_3_y0_im; 79 | wire [15:0] bf_3_y1_re; 80 | wire [15:0] bf_3_y1_im; 81 | 82 | wire busy; 83 | reg [15:0] cnt; // wide:stage+1 84 | 85 | assign busy = cnt != 10'd0; 86 | always @(posedge clk or negedge rst_n) begin 87 | if(!rst_n) begin 88 | cnt <= 10'd0; 89 | end 90 | else if(sop_in) 91 | cnt <= 10'd1; 92 | else begin 93 | if(stb || busy) begin 94 | if(cnt == 10'd23) // TODO: cnt==FFTlen * 3 / 2 - 1 95 | cnt <= 10'd0; 96 | else 97 | cnt <= cnt + 1'b1; 98 | end 99 | end 100 | end 101 | 102 | 103 | bf_rdx2 bf_0 ( 104 | .x0_re(bf_0_x0_re), 105 | .x0_im(bf_0_x0_im), 106 | .x1_re(bf_0_x1_re), 107 | .x1_im(bf_0_x1_im), 108 | .w_re(bf_0_w_re), 109 | .w_im(bf_0_w_im), 110 | .y0_re(bf_0_y0_re), 111 | .y0_im(bf_0_y0_im), 112 | .y1_re(bf_0_y1_re), 113 | .y1_im(bf_0_y1_im) 114 | ); 115 | switch switch_0 ( 116 | .sel(switch_0_sel), 117 | .x0_re(switch_0_x0_re), 118 | .x0_im(switch_0_x0_im), 119 | .x1_re(switch_0_x1_re), 120 | .x1_im(switch_0_x1_im), 121 | .y0_re(switch_0_y0_re), 122 | .y0_im(switch_0_y0_im), 123 | .y1_re(switch_0_y1_re), 124 | .y1_im(switch_0_y1_im) 125 | ); 126 | bf_rdx2 bf_1 ( 127 | .x0_re(bf_1_x0_re), 128 | .x0_im(bf_1_x0_im), 129 | .x1_re(bf_1_x1_re), 130 | .x1_im(bf_1_x1_im), 131 | .w_re(bf_1_w_re), 132 | .w_im(bf_1_w_im), 133 | .y0_re(bf_1_y0_re), 134 | .y0_im(bf_1_y0_im), 135 | .y1_re(bf_1_y1_re), 136 | .y1_im(bf_1_y1_im) 137 | ); 138 | switch switch_1 ( 139 | .sel(switch_1_sel), 140 | .x0_re(switch_1_x0_re), 141 | .x0_im(switch_1_x0_im), 142 | .x1_re(switch_1_x1_re), 143 | .x1_im(switch_1_x1_im), 144 | .y0_re(switch_1_y0_re), 145 | .y0_im(switch_1_y0_im), 146 | .y1_re(switch_1_y1_re), 147 | .y1_im(switch_1_y1_im) 148 | ); 149 | bf_rdx2 bf_2 ( 150 | .x0_re(bf_2_x0_re), 151 | .x0_im(bf_2_x0_im), 152 | .x1_re(bf_2_x1_re), 153 | .x1_im(bf_2_x1_im), 154 | .w_re(bf_2_w_re), 155 | .w_im(bf_2_w_im), 156 | .y0_re(bf_2_y0_re), 157 | .y0_im(bf_2_y0_im), 158 | .y1_re(bf_2_y1_re), 159 | .y1_im(bf_2_y1_im) 160 | ); 161 | switch switch_2 ( 162 | .sel(switch_2_sel), 163 | .x0_re(switch_2_x0_re), 164 | .x0_im(switch_2_x0_im), 165 | .x1_re(switch_2_x1_re), 166 | .x1_im(switch_2_x1_im), 167 | .y0_re(switch_2_y0_re), 168 | .y0_im(switch_2_y0_im), 169 | .y1_re(switch_2_y1_re), 170 | .y1_im(switch_2_y1_im) 171 | ); 172 | bf_rdx2_noW bf_noW_1 ( 173 | .x0_re(bf_3_x0_re), 174 | .x0_im(bf_3_x0_im), 175 | .x1_re(bf_3_x1_re), 176 | .x1_im(bf_3_x1_im), 177 | .y0_re(bf_3_y0_re), 178 | .y0_im(bf_3_y0_im), 179 | .y1_re(bf_3_y1_re), 180 | .y1_im(bf_3_y1_im) 181 | ); 182 | 183 | twiddle_rom twiddle_rom_0 ( 184 | .addr0(cnt[4-2-0:0]), // TODO: stage-2-i 185 | .addr1({cnt[4-2-1:0], 1'b0}), 186 | .addr2({cnt[4-2-2:0], 2'b0}), 187 | .data0_re(bf_0_w_re), 188 | .data0_im(bf_0_w_im), 189 | .data1_re(bf_1_w_re), 190 | .data1_im(bf_1_w_im), 191 | .data2_re(bf_2_w_re), 192 | .data2_im(bf_2_w_im) 193 | ); 194 | 195 | assign bf_0_x1_re = x_re; 196 | assign bf_0_x1_im = x_im; 197 | assign switch_0_x0_re = bf_0_y0_re; 198 | assign switch_0_x0_im = bf_0_y0_im; 199 | assign switch_0_sel = cnt[4-2-0]; // TODO: stage-2-i 200 | assign bf_1_x1_re = switch_0_y1_re; 201 | assign bf_1_x1_im = switch_0_y1_im; 202 | assign switch_1_x0_re = bf_1_y0_re; 203 | assign switch_1_x0_im = bf_1_y0_im; 204 | assign switch_1_sel = cnt[4-2-1]; 205 | assign bf_2_x1_re = switch_1_y1_re; 206 | assign bf_2_x1_im = switch_1_y1_im; 207 | assign switch_2_x0_re = bf_2_y0_re; 208 | assign switch_2_x0_im = bf_2_y0_im; 209 | assign switch_2_sel = cnt[4-2-2]; 210 | assign bf_3_x1_re = switch_2_y1_re; 211 | assign bf_3_x1_im = switch_2_y1_im; 212 | 213 | shiftreg #(16, 8) shiftreg_0 ( 214 | .clk(clk), 215 | .rst_n(rst_n), 216 | .d_in(x_re), 217 | .d_out(bf_0_x0_re) 218 | ); 219 | shiftreg #(16, 8) shiftreg_1 ( 220 | .clk(clk), 221 | .rst_n(rst_n), 222 | .d_in(x_im), 223 | .d_out(bf_0_x0_im) 224 | ); 225 | 226 | shiftreg #(16, 4) shiftreg_2 ( 227 | .clk(clk), 228 | .rst_n(rst_n), 229 | .d_in(bf_0_y1_re), 230 | .d_out(switch_0_x1_re) 231 | ); 232 | shiftreg #(16, 4) shiftreg_3 ( 233 | .clk(clk), 234 | .rst_n(rst_n), 235 | .d_in(bf_0_y1_im), 236 | .d_out(switch_0_x1_im) 237 | ); 238 | 239 | shiftreg #(16, 4) shiftreg_4 ( 240 | .clk(clk), 241 | .rst_n(rst_n), 242 | .d_in(switch_0_y0_re), 243 | .d_out(bf_1_x0_re) 244 | ); 245 | shiftreg #(16, 4) shiftreg_5 ( 246 | .clk(clk), 247 | .rst_n(rst_n), 248 | .d_in(switch_0_y0_im), 249 | .d_out(bf_1_x0_im) 250 | ); 251 | 252 | shiftreg #(16, 2) shiftreg_6 ( 253 | .clk(clk), 254 | .rst_n(rst_n), 255 | .d_in(bf_1_y1_re), 256 | .d_out(switch_1_x1_re) 257 | ); 258 | shiftreg #(16, 2) shiftreg_7 ( 259 | .clk(clk), 260 | .rst_n(rst_n), 261 | .d_in(bf_1_y1_im), 262 | .d_out(switch_1_x1_im) 263 | ); 264 | 265 | shiftreg #(16, 2) shiftreg_8 ( 266 | .clk(clk), 267 | .rst_n(rst_n), 268 | .d_in(switch_1_y0_re), 269 | .d_out(bf_2_x0_re) 270 | ); 271 | shiftreg #(16, 2) shiftreg_9 ( 272 | .clk(clk), 273 | .rst_n(rst_n), 274 | .d_in(switch_1_y0_im), 275 | .d_out(bf_2_x0_im) 276 | ); 277 | 278 | shiftreg #(16, 1) shiftreg_10 ( 279 | .clk(clk), 280 | .rst_n(rst_n), 281 | .d_in(bf_2_y1_re), 282 | .d_out(switch_2_x1_re) 283 | ); 284 | shiftreg #(16, 1) shiftreg_11 ( 285 | .clk(clk), 286 | .rst_n(rst_n), 287 | .d_in(bf_2_y1_im), 288 | .d_out(switch_2_x1_im) 289 | ); 290 | 291 | shiftreg #(16, 1) shiftreg_12 ( 292 | .clk(clk), 293 | .rst_n(rst_n), 294 | .d_in(switch_2_y0_re), 295 | .d_out(bf_3_x0_re) 296 | ); 297 | shiftreg #(16, 1) shiftreg_13 ( 298 | .clk(clk), 299 | .rst_n(rst_n), 300 | .d_in(switch_2_y0_im), 301 | .d_out(bf_3_x0_im) 302 | ); 303 | 304 | wire fft_out_valid = cnt >= 16'd15 && cnt < 16'd23; // TODO: FFTlen-1 cnt==FFTlen * 3 / 2 - 1 305 | 306 | reorder #(16, 16) reorder_0 ( 307 | .clk(clk), 308 | .rst_n(rst_n), 309 | .in1_re(bf_3_y0_re), 310 | .in1_im(bf_3_y0_im), 311 | .in2_re(bf_3_y1_re), 312 | .in2_im(bf_3_y1_im), 313 | .in_valid(fft_out_valid), 314 | .out_re(y_re), 315 | .out_im(y_im), 316 | .out_valid(valid_out) 317 | ); 318 | 319 | assign sop_out = cnt == 16'd23; // TODO: cnt==FFTlen * 3 / 2 - 1 320 | 321 | endmodule 322 | -------------------------------------------------------------------------------- /rtl/src/fft_multimode.v: -------------------------------------------------------------------------------- 1 | // Author: brimonzzy 2 | // Create Date: 2025/2/13 3 | // Description: Multi-mode FFT accelerator top module 4 | 5 | module fft_multimode ( 6 | input clk, 7 | input rst_n, 8 | input inv, // 0: fft, 1: ifft 9 | input [1:0] np, // FFT/IFFT point number 0:64, 1:128, 2:256, 3:512 10 | input stb, // Input data valid (active high) 11 | input sop_in, // The first valid data in the input stream 12 | input [15:0] x_re, // Input real part 13 | input [15:0] x_im, // Input imaginary part 14 | output valid_out, // Output data valid (active high) 15 | output reg sop_out, // The first valid data in the output stream 16 | output [15:0] y_re, // Output real part 17 | output [15:0] y_im // Output imaginary part 18 | ); 19 | 20 | parameter N = 512; 21 | parameter stage = $clog2(N); 22 | 23 | reg [9:0] point; 24 | reg [3:0] log2point; 25 | always @(*) begin 26 | case(np) 27 | 2'b00: begin point = 10'd64; log2point = 4'd6; end 28 | 2'b01: begin point = 10'd128; log2point = 4'd7; end 29 | 2'b10: begin point = 10'd256; log2point = 4'd8; end 30 | 2'b11: begin point = 10'd512; log2point = 4'd9; end 31 | endcase 32 | end 33 | 34 | wire [15:0] bf_x0_re [0:stage-2]; 35 | wire [15:0] bf_x0_im [0:stage-2]; 36 | wire [15:0] bf_x1_re [0:stage-2]; 37 | wire [15:0] bf_x1_im [0:stage-2]; 38 | wire [15:0] bf_w_re [0:stage-2]; 39 | wire [15:0] bf_w_im [0:stage-2]; 40 | wire [15:0] bf_y0_re [0:stage-2]; 41 | wire [15:0] bf_y0_im [0:stage-2]; 42 | wire [15:0] bf_y1_re [0:stage-2]; 43 | wire [15:0] bf_y1_im [0:stage-2]; 44 | wire [15:0] switch_x0_re [0:stage-2]; 45 | wire [15:0] switch_x0_im [0:stage-2]; 46 | wire [15:0] switch_x1_re [0:stage-2]; 47 | wire [15:0] switch_x1_im [0:stage-2]; 48 | wire [15:0] switch_y0_re [0:stage-2]; 49 | wire [15:0] switch_y0_im [0:stage-2]; 50 | wire [15:0] switch_y1_re [0:stage-2]; 51 | wire [15:0] switch_y1_im [0:stage-2]; 52 | wire switch_sel [0:stage-2]; 53 | wire [15:0] bf_noW_x0_re; 54 | wire [15:0] bf_noW_x0_im; 55 | wire [15:0] bf_noW_x1_re; 56 | wire [15:0] bf_noW_x1_im; 57 | wire [15:0] bf_noW_y0_re; 58 | wire [15:0] bf_noW_y0_im; 59 | wire [15:0] bf_noW_y1_re; 60 | wire [15:0] bf_noW_y1_im; 61 | 62 | wire busy; 63 | reg [$clog2(N):0] cnt; // wide:stage+1 64 | 65 | assign busy = cnt != 10'd0; 66 | always @(posedge clk or negedge rst_n) begin 67 | if(!rst_n) begin 68 | cnt <= {($clog2(N)+1){1'b0}}; 69 | end 70 | else if(sop_in) 71 | cnt <= 1; 72 | else begin 73 | if(stb || busy) begin 74 | if(cnt == (point*3/2-1)) // cnt==FFTlen * 3 / 2 - 1 75 | cnt <= {($clog2(N)+1){1'b0}}; 76 | else 77 | cnt <= cnt + 1'b1; 78 | end 79 | end 80 | end 81 | 82 | genvar i; 83 | generate 84 | for(i=0; i= (point-1) && cnt < (point*3/2-1); // FFTlen-1 cnt==FFTlen * 3 / 2 - 1 318 | 319 | wire [15:0] reorder_out_re, reorder_out_im; 320 | reorder #(16, N) output_reorder_u ( 321 | .clk(clk), 322 | .rst_n(rst_n), 323 | .in1_re(bf_noW_y0_re), 324 | .in1_im(bf_noW_y0_im), 325 | .in2_re(bf_noW_y1_re), 326 | .in2_im(bf_noW_y1_im), 327 | .in_valid(fft_out_valid), 328 | .np(np), 329 | .out_re(reorder_out_re), 330 | .out_im(reorder_out_im), 331 | .out_valid(valid_out) 332 | ); 333 | assign y_re = inv ? reorder_out_re >> log2point : reorder_out_re; 334 | assign y_im = inv ? reorder_out_im >> log2point : reorder_out_im; 335 | 336 | 337 | wire sop_out_t = cnt == (point*3/2-1); 338 | reg sop_out_t1; 339 | always @(posedge clk or negedge rst_n) begin 340 | if(!rst_n) begin 341 | sop_out_t1 <= 1'b0; 342 | sop_out <= 1'b0; 343 | end 344 | else begin 345 | sop_out_t1 <= sop_out_t; 346 | sop_out <= sop_out_t1; 347 | end 348 | end 349 | 350 | endmodule 351 | -------------------------------------------------------------------------------- /rtl/src/ifft_twiddle_rom.v: -------------------------------------------------------------------------------- 1 | // For 512-point IFFT 2 | // 8 read ports 3 | 4 | module ifft_twiddle_rom ( 5 | input [7:0] addr0, 6 | input [7:0] addr1, 7 | input [7:0] addr2, 8 | input [7:0] addr3, 9 | input [7:0] addr4, 10 | input [7:0] addr5, 11 | input [7:0] addr6, 12 | input [7:0] addr7, 13 | output [15:0] data0_re, 14 | output [15:0] data0_im, 15 | output [15:0] data1_re, 16 | output [15:0] data1_im, 17 | output [15:0] data2_re, 18 | output [15:0] data2_im, 19 | output [15:0] data3_re, 20 | output [15:0] data3_im, 21 | output [15:0] data4_re, 22 | output [15:0] data4_im, 23 | output [15:0] data5_re, 24 | output [15:0] data5_im, 25 | output [15:0] data6_re, 26 | output [15:0] data6_im, 27 | output [15:0] data7_re, 28 | output [15:0] data7_im 29 | ); 30 | // For N=512 31 | wire signed [15:0] wn_re [0:255]; 32 | wire signed [15:0] wn_im [0:255]; 33 | 34 | assign wn_re[0] = $signed(16'sh7FFF); 35 | assign wn_re[1] = $signed(16'sh7FFE); 36 | assign wn_re[2] = $signed(16'sh7FF6); 37 | assign wn_re[3] = $signed(16'sh7FEA); 38 | assign wn_re[4] = $signed(16'sh7FD9); 39 | assign wn_re[5] = $signed(16'sh7FC2); 40 | assign wn_re[6] = $signed(16'sh7FA7); 41 | assign wn_re[7] = $signed(16'sh7F87); 42 | assign wn_re[8] = $signed(16'sh7F62); 43 | assign wn_re[9] = $signed(16'sh7F38); 44 | assign wn_re[10] = $signed(16'sh7F0A); 45 | assign wn_re[11] = $signed(16'sh7ED6); 46 | assign wn_re[12] = $signed(16'sh7E9D); 47 | assign wn_re[13] = $signed(16'sh7E60); 48 | assign wn_re[14] = $signed(16'sh7E1E); 49 | assign wn_re[15] = $signed(16'sh7DD6); 50 | assign wn_re[16] = $signed(16'sh7D8A); 51 | assign wn_re[17] = $signed(16'sh7D3A); 52 | assign wn_re[18] = $signed(16'sh7CE4); 53 | assign wn_re[19] = $signed(16'sh7C89); 54 | assign wn_re[20] = $signed(16'sh7C2A); 55 | assign wn_re[21] = $signed(16'sh7BC6); 56 | assign wn_re[22] = $signed(16'sh7B5D); 57 | assign wn_re[23] = $signed(16'sh7AEF); 58 | assign wn_re[24] = $signed(16'sh7A7D); 59 | assign wn_re[25] = $signed(16'sh7A06); 60 | assign wn_re[26] = $signed(16'sh798A); 61 | assign wn_re[27] = $signed(16'sh790A); 62 | assign wn_re[28] = $signed(16'sh7885); 63 | assign wn_re[29] = $signed(16'sh77FB); 64 | assign wn_re[30] = $signed(16'sh776C); 65 | assign wn_re[31] = $signed(16'sh76D9); 66 | assign wn_re[32] = $signed(16'sh7642); 67 | assign wn_re[33] = $signed(16'sh75A6); 68 | assign wn_re[34] = $signed(16'sh7505); 69 | assign wn_re[35] = $signed(16'sh7460); 70 | assign wn_re[36] = $signed(16'sh73B6); 71 | assign wn_re[37] = $signed(16'sh7308); 72 | assign wn_re[38] = $signed(16'sh7255); 73 | assign wn_re[39] = $signed(16'sh719E); 74 | assign wn_re[40] = $signed(16'sh70E3); 75 | assign wn_re[41] = $signed(16'sh7023); 76 | assign wn_re[42] = $signed(16'sh6F5F); 77 | assign wn_re[43] = $signed(16'sh6E97); 78 | assign wn_re[44] = $signed(16'sh6DCA); 79 | assign wn_re[45] = $signed(16'sh6CF9); 80 | assign wn_re[46] = $signed(16'sh6C24); 81 | assign wn_re[47] = $signed(16'sh6B4B); 82 | assign wn_re[48] = $signed(16'sh6A6E); 83 | assign wn_re[49] = $signed(16'sh698C); 84 | assign wn_re[50] = $signed(16'sh68A7); 85 | assign wn_re[51] = $signed(16'sh67BD); 86 | assign wn_re[52] = $signed(16'sh66D0); 87 | assign wn_re[53] = $signed(16'sh65DE); 88 | assign wn_re[54] = $signed(16'sh64E9); 89 | assign wn_re[55] = $signed(16'sh63EF); 90 | assign wn_re[56] = $signed(16'sh62F2); 91 | assign wn_re[57] = $signed(16'sh61F1); 92 | assign wn_re[58] = $signed(16'sh60EC); 93 | assign wn_re[59] = $signed(16'sh5FE4); 94 | assign wn_re[60] = $signed(16'sh5ED7); 95 | assign wn_re[61] = $signed(16'sh5DC8); 96 | assign wn_re[62] = $signed(16'sh5CB4); 97 | assign wn_re[63] = $signed(16'sh5B9D); 98 | assign wn_re[64] = $signed(16'sh5A82); 99 | assign wn_re[65] = $signed(16'sh5964); 100 | assign wn_re[66] = $signed(16'sh5843); 101 | assign wn_re[67] = $signed(16'sh571E); 102 | assign wn_re[68] = $signed(16'sh55F6); 103 | assign wn_re[69] = $signed(16'sh54CA); 104 | assign wn_re[70] = $signed(16'sh539B); 105 | assign wn_re[71] = $signed(16'sh5269); 106 | assign wn_re[72] = $signed(16'sh5134); 107 | assign wn_re[73] = $signed(16'sh4FFB); 108 | assign wn_re[74] = $signed(16'sh4EC0); 109 | assign wn_re[75] = $signed(16'sh4D81); 110 | assign wn_re[76] = $signed(16'sh4C40); 111 | assign wn_re[77] = $signed(16'sh4AFB); 112 | assign wn_re[78] = $signed(16'sh49B4); 113 | assign wn_re[79] = $signed(16'sh486A); 114 | assign wn_re[80] = $signed(16'sh471D); 115 | assign wn_re[81] = $signed(16'sh45CD); 116 | assign wn_re[82] = $signed(16'sh447B); 117 | assign wn_re[83] = $signed(16'sh4326); 118 | assign wn_re[84] = $signed(16'sh41CE); 119 | assign wn_re[85] = $signed(16'sh4074); 120 | assign wn_re[86] = $signed(16'sh3F17); 121 | assign wn_re[87] = $signed(16'sh3DB8); 122 | assign wn_re[88] = $signed(16'sh3C57); 123 | assign wn_re[89] = $signed(16'sh3AF3); 124 | assign wn_re[90] = $signed(16'sh398D); 125 | assign wn_re[91] = $signed(16'sh3825); 126 | assign wn_re[92] = $signed(16'sh36BA); 127 | assign wn_re[93] = $signed(16'sh354E); 128 | assign wn_re[94] = $signed(16'sh33DF); 129 | assign wn_re[95] = $signed(16'sh326E); 130 | assign wn_re[96] = $signed(16'sh30FC); 131 | assign wn_re[97] = $signed(16'sh2F87); 132 | assign wn_re[98] = $signed(16'sh2E11); 133 | assign wn_re[99] = $signed(16'sh2C99); 134 | assign wn_re[100] = $signed(16'sh2B1F); 135 | assign wn_re[101] = $signed(16'sh29A4); 136 | assign wn_re[102] = $signed(16'sh2827); 137 | assign wn_re[103] = $signed(16'sh26A8); 138 | assign wn_re[104] = $signed(16'sh2528); 139 | assign wn_re[105] = $signed(16'sh23A7); 140 | assign wn_re[106] = $signed(16'sh2224); 141 | assign wn_re[107] = $signed(16'sh209F); 142 | assign wn_re[108] = $signed(16'sh1F1A); 143 | assign wn_re[109] = $signed(16'sh1D93); 144 | assign wn_re[110] = $signed(16'sh1C0C); 145 | assign wn_re[111] = $signed(16'sh1A83); 146 | assign wn_re[112] = $signed(16'sh18F9); 147 | assign wn_re[113] = $signed(16'sh176E); 148 | assign wn_re[114] = $signed(16'sh15E2); 149 | assign wn_re[115] = $signed(16'sh1455); 150 | assign wn_re[116] = $signed(16'sh12C8); 151 | assign wn_re[117] = $signed(16'sh113A); 152 | assign wn_re[118] = $signed(16'sh0FAB); 153 | assign wn_re[119] = $signed(16'sh0E1C); 154 | assign wn_re[120] = $signed(16'sh0C8C); 155 | assign wn_re[121] = $signed(16'sh0AFB); 156 | assign wn_re[122] = $signed(16'sh096B); 157 | assign wn_re[123] = $signed(16'sh07D9); 158 | assign wn_re[124] = $signed(16'sh0648); 159 | assign wn_re[125] = $signed(16'sh04B6); 160 | assign wn_re[126] = $signed(16'sh0324); 161 | assign wn_re[127] = $signed(16'sh0192); 162 | assign wn_re[128] = $signed(16'sh0000); 163 | assign wn_re[129] = $signed(-16'sh0192); 164 | assign wn_re[130] = $signed(-16'sh0324); 165 | assign wn_re[131] = $signed(-16'sh04B6); 166 | assign wn_re[132] = $signed(-16'sh0648); 167 | assign wn_re[133] = $signed(-16'sh07D9); 168 | assign wn_re[134] = $signed(-16'sh096B); 169 | assign wn_re[135] = $signed(-16'sh0AFB); 170 | assign wn_re[136] = $signed(-16'sh0C8C); 171 | assign wn_re[137] = $signed(-16'sh0E1C); 172 | assign wn_re[138] = $signed(-16'sh0FAB); 173 | assign wn_re[139] = $signed(-16'sh113A); 174 | assign wn_re[140] = $signed(-16'sh12C8); 175 | assign wn_re[141] = $signed(-16'sh1455); 176 | assign wn_re[142] = $signed(-16'sh15E2); 177 | assign wn_re[143] = $signed(-16'sh176E); 178 | assign wn_re[144] = $signed(-16'sh18F9); 179 | assign wn_re[145] = $signed(-16'sh1A83); 180 | assign wn_re[146] = $signed(-16'sh1C0C); 181 | assign wn_re[147] = $signed(-16'sh1D93); 182 | assign wn_re[148] = $signed(-16'sh1F1A); 183 | assign wn_re[149] = $signed(-16'sh209F); 184 | assign wn_re[150] = $signed(-16'sh2224); 185 | assign wn_re[151] = $signed(-16'sh23A7); 186 | assign wn_re[152] = $signed(-16'sh2528); 187 | assign wn_re[153] = $signed(-16'sh26A8); 188 | assign wn_re[154] = $signed(-16'sh2827); 189 | assign wn_re[155] = $signed(-16'sh29A4); 190 | assign wn_re[156] = $signed(-16'sh2B1F); 191 | assign wn_re[157] = $signed(-16'sh2C99); 192 | assign wn_re[158] = $signed(-16'sh2E11); 193 | assign wn_re[159] = $signed(-16'sh2F87); 194 | assign wn_re[160] = $signed(-16'sh30FC); 195 | assign wn_re[161] = $signed(-16'sh326E); 196 | assign wn_re[162] = $signed(-16'sh33DF); 197 | assign wn_re[163] = $signed(-16'sh354E); 198 | assign wn_re[164] = $signed(-16'sh36BA); 199 | assign wn_re[165] = $signed(-16'sh3825); 200 | assign wn_re[166] = $signed(-16'sh398D); 201 | assign wn_re[167] = $signed(-16'sh3AF3); 202 | assign wn_re[168] = $signed(-16'sh3C57); 203 | assign wn_re[169] = $signed(-16'sh3DB8); 204 | assign wn_re[170] = $signed(-16'sh3F17); 205 | assign wn_re[171] = $signed(-16'sh4074); 206 | assign wn_re[172] = $signed(-16'sh41CE); 207 | assign wn_re[173] = $signed(-16'sh4326); 208 | assign wn_re[174] = $signed(-16'sh447B); 209 | assign wn_re[175] = $signed(-16'sh45CD); 210 | assign wn_re[176] = $signed(-16'sh471D); 211 | assign wn_re[177] = $signed(-16'sh486A); 212 | assign wn_re[178] = $signed(-16'sh49B4); 213 | assign wn_re[179] = $signed(-16'sh4AFB); 214 | assign wn_re[180] = $signed(-16'sh4C40); 215 | assign wn_re[181] = $signed(-16'sh4D81); 216 | assign wn_re[182] = $signed(-16'sh4EC0); 217 | assign wn_re[183] = $signed(-16'sh4FFB); 218 | assign wn_re[184] = $signed(-16'sh5134); 219 | assign wn_re[185] = $signed(-16'sh5269); 220 | assign wn_re[186] = $signed(-16'sh539B); 221 | assign wn_re[187] = $signed(-16'sh54CA); 222 | assign wn_re[188] = $signed(-16'sh55F6); 223 | assign wn_re[189] = $signed(-16'sh571E); 224 | assign wn_re[190] = $signed(-16'sh5843); 225 | assign wn_re[191] = $signed(-16'sh5964); 226 | assign wn_re[192] = $signed(-16'sh5A82); 227 | assign wn_re[193] = $signed(-16'sh5B9D); 228 | assign wn_re[194] = $signed(-16'sh5CB4); 229 | assign wn_re[195] = $signed(-16'sh5DC8); 230 | assign wn_re[196] = $signed(-16'sh5ED7); 231 | assign wn_re[197] = $signed(-16'sh5FE4); 232 | assign wn_re[198] = $signed(-16'sh60EC); 233 | assign wn_re[199] = $signed(-16'sh61F1); 234 | assign wn_re[200] = $signed(-16'sh62F2); 235 | assign wn_re[201] = $signed(-16'sh63EF); 236 | assign wn_re[202] = $signed(-16'sh64E9); 237 | assign wn_re[203] = $signed(-16'sh65DE); 238 | assign wn_re[204] = $signed(-16'sh66D0); 239 | assign wn_re[205] = $signed(-16'sh67BD); 240 | assign wn_re[206] = $signed(-16'sh68A7); 241 | assign wn_re[207] = $signed(-16'sh698C); 242 | assign wn_re[208] = $signed(-16'sh6A6E); 243 | assign wn_re[209] = $signed(-16'sh6B4B); 244 | assign wn_re[210] = $signed(-16'sh6C24); 245 | assign wn_re[211] = $signed(-16'sh6CF9); 246 | assign wn_re[212] = $signed(-16'sh6DCA); 247 | assign wn_re[213] = $signed(-16'sh6E97); 248 | assign wn_re[214] = $signed(-16'sh6F5F); 249 | assign wn_re[215] = $signed(-16'sh7023); 250 | assign wn_re[216] = $signed(-16'sh70E3); 251 | assign wn_re[217] = $signed(-16'sh719E); 252 | assign wn_re[218] = $signed(-16'sh7255); 253 | assign wn_re[219] = $signed(-16'sh7308); 254 | assign wn_re[220] = $signed(-16'sh73B6); 255 | assign wn_re[221] = $signed(-16'sh7460); 256 | assign wn_re[222] = $signed(-16'sh7505); 257 | assign wn_re[223] = $signed(-16'sh75A6); 258 | assign wn_re[224] = $signed(-16'sh7642); 259 | assign wn_re[225] = $signed(-16'sh76D9); 260 | assign wn_re[226] = $signed(-16'sh776C); 261 | assign wn_re[227] = $signed(-16'sh77FB); 262 | assign wn_re[228] = $signed(-16'sh7885); 263 | assign wn_re[229] = $signed(-16'sh790A); 264 | assign wn_re[230] = $signed(-16'sh798A); 265 | assign wn_re[231] = $signed(-16'sh7A06); 266 | assign wn_re[232] = $signed(-16'sh7A7D); 267 | assign wn_re[233] = $signed(-16'sh7AEF); 268 | assign wn_re[234] = $signed(-16'sh7B5D); 269 | assign wn_re[235] = $signed(-16'sh7BC6); 270 | assign wn_re[236] = $signed(-16'sh7C2A); 271 | assign wn_re[237] = $signed(-16'sh7C89); 272 | assign wn_re[238] = $signed(-16'sh7CE4); 273 | assign wn_re[239] = $signed(-16'sh7D3A); 274 | assign wn_re[240] = $signed(-16'sh7D8A); 275 | assign wn_re[241] = $signed(-16'sh7DD6); 276 | assign wn_re[242] = $signed(-16'sh7E1E); 277 | assign wn_re[243] = $signed(-16'sh7E60); 278 | assign wn_re[244] = $signed(-16'sh7E9D); 279 | assign wn_re[245] = $signed(-16'sh7ED6); 280 | assign wn_re[246] = $signed(-16'sh7F0A); 281 | assign wn_re[247] = $signed(-16'sh7F38); 282 | assign wn_re[248] = $signed(-16'sh7F62); 283 | assign wn_re[249] = $signed(-16'sh7F87); 284 | assign wn_re[250] = $signed(-16'sh7FA7); 285 | assign wn_re[251] = $signed(-16'sh7FC2); 286 | assign wn_re[252] = $signed(-16'sh7FD9); 287 | assign wn_re[253] = $signed(-16'sh7FEA); 288 | assign wn_re[254] = $signed(-16'sh7FF6); 289 | assign wn_re[255] = $signed(-16'sh7FFE); 290 | assign wn_im[0] = $signed(16'sh0000); 291 | assign wn_im[1] = $signed(16'sh0192); 292 | assign wn_im[2] = $signed(16'sh0324); 293 | assign wn_im[3] = $signed(16'sh04B6); 294 | assign wn_im[4] = $signed(16'sh0648); 295 | assign wn_im[5] = $signed(16'sh07D9); 296 | assign wn_im[6] = $signed(16'sh096B); 297 | assign wn_im[7] = $signed(16'sh0AFB); 298 | assign wn_im[8] = $signed(16'sh0C8C); 299 | assign wn_im[9] = $signed(16'sh0E1C); 300 | assign wn_im[10] = $signed(16'sh0FAB); 301 | assign wn_im[11] = $signed(16'sh113A); 302 | assign wn_im[12] = $signed(16'sh12C8); 303 | assign wn_im[13] = $signed(16'sh1455); 304 | assign wn_im[14] = $signed(16'sh15E2); 305 | assign wn_im[15] = $signed(16'sh176E); 306 | assign wn_im[16] = $signed(16'sh18F9); 307 | assign wn_im[17] = $signed(16'sh1A83); 308 | assign wn_im[18] = $signed(16'sh1C0C); 309 | assign wn_im[19] = $signed(16'sh1D93); 310 | assign wn_im[20] = $signed(16'sh1F1A); 311 | assign wn_im[21] = $signed(16'sh209F); 312 | assign wn_im[22] = $signed(16'sh2224); 313 | assign wn_im[23] = $signed(16'sh23A7); 314 | assign wn_im[24] = $signed(16'sh2528); 315 | assign wn_im[25] = $signed(16'sh26A8); 316 | assign wn_im[26] = $signed(16'sh2827); 317 | assign wn_im[27] = $signed(16'sh29A4); 318 | assign wn_im[28] = $signed(16'sh2B1F); 319 | assign wn_im[29] = $signed(16'sh2C99); 320 | assign wn_im[30] = $signed(16'sh2E11); 321 | assign wn_im[31] = $signed(16'sh2F87); 322 | assign wn_im[32] = $signed(16'sh30FC); 323 | assign wn_im[33] = $signed(16'sh326E); 324 | assign wn_im[34] = $signed(16'sh33DF); 325 | assign wn_im[35] = $signed(16'sh354E); 326 | assign wn_im[36] = $signed(16'sh36BA); 327 | assign wn_im[37] = $signed(16'sh3825); 328 | assign wn_im[38] = $signed(16'sh398D); 329 | assign wn_im[39] = $signed(16'sh3AF3); 330 | assign wn_im[40] = $signed(16'sh3C57); 331 | assign wn_im[41] = $signed(16'sh3DB8); 332 | assign wn_im[42] = $signed(16'sh3F17); 333 | assign wn_im[43] = $signed(16'sh4074); 334 | assign wn_im[44] = $signed(16'sh41CE); 335 | assign wn_im[45] = $signed(16'sh4326); 336 | assign wn_im[46] = $signed(16'sh447B); 337 | assign wn_im[47] = $signed(16'sh45CD); 338 | assign wn_im[48] = $signed(16'sh471D); 339 | assign wn_im[49] = $signed(16'sh486A); 340 | assign wn_im[50] = $signed(16'sh49B4); 341 | assign wn_im[51] = $signed(16'sh4AFB); 342 | assign wn_im[52] = $signed(16'sh4C40); 343 | assign wn_im[53] = $signed(16'sh4D81); 344 | assign wn_im[54] = $signed(16'sh4EC0); 345 | assign wn_im[55] = $signed(16'sh4FFB); 346 | assign wn_im[56] = $signed(16'sh5134); 347 | assign wn_im[57] = $signed(16'sh5269); 348 | assign wn_im[58] = $signed(16'sh539B); 349 | assign wn_im[59] = $signed(16'sh54CA); 350 | assign wn_im[60] = $signed(16'sh55F6); 351 | assign wn_im[61] = $signed(16'sh571E); 352 | assign wn_im[62] = $signed(16'sh5843); 353 | assign wn_im[63] = $signed(16'sh5964); 354 | assign wn_im[64] = $signed(16'sh5A82); 355 | assign wn_im[65] = $signed(16'sh5B9D); 356 | assign wn_im[66] = $signed(16'sh5CB4); 357 | assign wn_im[67] = $signed(16'sh5DC8); 358 | assign wn_im[68] = $signed(16'sh5ED7); 359 | assign wn_im[69] = $signed(16'sh5FE4); 360 | assign wn_im[70] = $signed(16'sh60EC); 361 | assign wn_im[71] = $signed(16'sh61F1); 362 | assign wn_im[72] = $signed(16'sh62F2); 363 | assign wn_im[73] = $signed(16'sh63EF); 364 | assign wn_im[74] = $signed(16'sh64E9); 365 | assign wn_im[75] = $signed(16'sh65DE); 366 | assign wn_im[76] = $signed(16'sh66D0); 367 | assign wn_im[77] = $signed(16'sh67BD); 368 | assign wn_im[78] = $signed(16'sh68A7); 369 | assign wn_im[79] = $signed(16'sh698C); 370 | assign wn_im[80] = $signed(16'sh6A6E); 371 | assign wn_im[81] = $signed(16'sh6B4B); 372 | assign wn_im[82] = $signed(16'sh6C24); 373 | assign wn_im[83] = $signed(16'sh6CF9); 374 | assign wn_im[84] = $signed(16'sh6DCA); 375 | assign wn_im[85] = $signed(16'sh6E97); 376 | assign wn_im[86] = $signed(16'sh6F5F); 377 | assign wn_im[87] = $signed(16'sh7023); 378 | assign wn_im[88] = $signed(16'sh70E3); 379 | assign wn_im[89] = $signed(16'sh719E); 380 | assign wn_im[90] = $signed(16'sh7255); 381 | assign wn_im[91] = $signed(16'sh7308); 382 | assign wn_im[92] = $signed(16'sh73B6); 383 | assign wn_im[93] = $signed(16'sh7460); 384 | assign wn_im[94] = $signed(16'sh7505); 385 | assign wn_im[95] = $signed(16'sh75A6); 386 | assign wn_im[96] = $signed(16'sh7642); 387 | assign wn_im[97] = $signed(16'sh76D9); 388 | assign wn_im[98] = $signed(16'sh776C); 389 | assign wn_im[99] = $signed(16'sh77FB); 390 | assign wn_im[100] = $signed(16'sh7885); 391 | assign wn_im[101] = $signed(16'sh790A); 392 | assign wn_im[102] = $signed(16'sh798A); 393 | assign wn_im[103] = $signed(16'sh7A06); 394 | assign wn_im[104] = $signed(16'sh7A7D); 395 | assign wn_im[105] = $signed(16'sh7AEF); 396 | assign wn_im[106] = $signed(16'sh7B5D); 397 | assign wn_im[107] = $signed(16'sh7BC6); 398 | assign wn_im[108] = $signed(16'sh7C2A); 399 | assign wn_im[109] = $signed(16'sh7C89); 400 | assign wn_im[110] = $signed(16'sh7CE4); 401 | assign wn_im[111] = $signed(16'sh7D3A); 402 | assign wn_im[112] = $signed(16'sh7D8A); 403 | assign wn_im[113] = $signed(16'sh7DD6); 404 | assign wn_im[114] = $signed(16'sh7E1E); 405 | assign wn_im[115] = $signed(16'sh7E60); 406 | assign wn_im[116] = $signed(16'sh7E9D); 407 | assign wn_im[117] = $signed(16'sh7ED6); 408 | assign wn_im[118] = $signed(16'sh7F0A); 409 | assign wn_im[119] = $signed(16'sh7F38); 410 | assign wn_im[120] = $signed(16'sh7F62); 411 | assign wn_im[121] = $signed(16'sh7F87); 412 | assign wn_im[122] = $signed(16'sh7FA7); 413 | assign wn_im[123] = $signed(16'sh7FC2); 414 | assign wn_im[124] = $signed(16'sh7FD9); 415 | assign wn_im[125] = $signed(16'sh7FEA); 416 | assign wn_im[126] = $signed(16'sh7FF6); 417 | assign wn_im[127] = $signed(16'sh7FFE); 418 | assign wn_im[128] = $signed(16'sh7FFF); 419 | assign wn_im[129] = $signed(16'sh7FFE); 420 | assign wn_im[130] = $signed(16'sh7FF6); 421 | assign wn_im[131] = $signed(16'sh7FEA); 422 | assign wn_im[132] = $signed(16'sh7FD9); 423 | assign wn_im[133] = $signed(16'sh7FC2); 424 | assign wn_im[134] = $signed(16'sh7FA7); 425 | assign wn_im[135] = $signed(16'sh7F87); 426 | assign wn_im[136] = $signed(16'sh7F62); 427 | assign wn_im[137] = $signed(16'sh7F38); 428 | assign wn_im[138] = $signed(16'sh7F0A); 429 | assign wn_im[139] = $signed(16'sh7ED6); 430 | assign wn_im[140] = $signed(16'sh7E9D); 431 | assign wn_im[141] = $signed(16'sh7E60); 432 | assign wn_im[142] = $signed(16'sh7E1E); 433 | assign wn_im[143] = $signed(16'sh7DD6); 434 | assign wn_im[144] = $signed(16'sh7D8A); 435 | assign wn_im[145] = $signed(16'sh7D3A); 436 | assign wn_im[146] = $signed(16'sh7CE4); 437 | assign wn_im[147] = $signed(16'sh7C89); 438 | assign wn_im[148] = $signed(16'sh7C2A); 439 | assign wn_im[149] = $signed(16'sh7BC6); 440 | assign wn_im[150] = $signed(16'sh7B5D); 441 | assign wn_im[151] = $signed(16'sh7AEF); 442 | assign wn_im[152] = $signed(16'sh7A7D); 443 | assign wn_im[153] = $signed(16'sh7A06); 444 | assign wn_im[154] = $signed(16'sh798A); 445 | assign wn_im[155] = $signed(16'sh790A); 446 | assign wn_im[156] = $signed(16'sh7885); 447 | assign wn_im[157] = $signed(16'sh77FB); 448 | assign wn_im[158] = $signed(16'sh776C); 449 | assign wn_im[159] = $signed(16'sh76D9); 450 | assign wn_im[160] = $signed(16'sh7642); 451 | assign wn_im[161] = $signed(16'sh75A6); 452 | assign wn_im[162] = $signed(16'sh7505); 453 | assign wn_im[163] = $signed(16'sh7460); 454 | assign wn_im[164] = $signed(16'sh73B6); 455 | assign wn_im[165] = $signed(16'sh7308); 456 | assign wn_im[166] = $signed(16'sh7255); 457 | assign wn_im[167] = $signed(16'sh719E); 458 | assign wn_im[168] = $signed(16'sh70E3); 459 | assign wn_im[169] = $signed(16'sh7023); 460 | assign wn_im[170] = $signed(16'sh6F5F); 461 | assign wn_im[171] = $signed(16'sh6E97); 462 | assign wn_im[172] = $signed(16'sh6DCA); 463 | assign wn_im[173] = $signed(16'sh6CF9); 464 | assign wn_im[174] = $signed(16'sh6C24); 465 | assign wn_im[175] = $signed(16'sh6B4B); 466 | assign wn_im[176] = $signed(16'sh6A6E); 467 | assign wn_im[177] = $signed(16'sh698C); 468 | assign wn_im[178] = $signed(16'sh68A7); 469 | assign wn_im[179] = $signed(16'sh67BD); 470 | assign wn_im[180] = $signed(16'sh66D0); 471 | assign wn_im[181] = $signed(16'sh65DE); 472 | assign wn_im[182] = $signed(16'sh64E9); 473 | assign wn_im[183] = $signed(16'sh63EF); 474 | assign wn_im[184] = $signed(16'sh62F2); 475 | assign wn_im[185] = $signed(16'sh61F1); 476 | assign wn_im[186] = $signed(16'sh60EC); 477 | assign wn_im[187] = $signed(16'sh5FE4); 478 | assign wn_im[188] = $signed(16'sh5ED7); 479 | assign wn_im[189] = $signed(16'sh5DC8); 480 | assign wn_im[190] = $signed(16'sh5CB4); 481 | assign wn_im[191] = $signed(16'sh5B9D); 482 | assign wn_im[192] = $signed(16'sh5A82); 483 | assign wn_im[193] = $signed(16'sh5964); 484 | assign wn_im[194] = $signed(16'sh5843); 485 | assign wn_im[195] = $signed(16'sh571E); 486 | assign wn_im[196] = $signed(16'sh55F6); 487 | assign wn_im[197] = $signed(16'sh54CA); 488 | assign wn_im[198] = $signed(16'sh539B); 489 | assign wn_im[199] = $signed(16'sh5269); 490 | assign wn_im[200] = $signed(16'sh5134); 491 | assign wn_im[201] = $signed(16'sh4FFB); 492 | assign wn_im[202] = $signed(16'sh4EC0); 493 | assign wn_im[203] = $signed(16'sh4D81); 494 | assign wn_im[204] = $signed(16'sh4C40); 495 | assign wn_im[205] = $signed(16'sh4AFB); 496 | assign wn_im[206] = $signed(16'sh49B4); 497 | assign wn_im[207] = $signed(16'sh486A); 498 | assign wn_im[208] = $signed(16'sh471D); 499 | assign wn_im[209] = $signed(16'sh45CD); 500 | assign wn_im[210] = $signed(16'sh447B); 501 | assign wn_im[211] = $signed(16'sh4326); 502 | assign wn_im[212] = $signed(16'sh41CE); 503 | assign wn_im[213] = $signed(16'sh4074); 504 | assign wn_im[214] = $signed(16'sh3F17); 505 | assign wn_im[215] = $signed(16'sh3DB8); 506 | assign wn_im[216] = $signed(16'sh3C57); 507 | assign wn_im[217] = $signed(16'sh3AF3); 508 | assign wn_im[218] = $signed(16'sh398D); 509 | assign wn_im[219] = $signed(16'sh3825); 510 | assign wn_im[220] = $signed(16'sh36BA); 511 | assign wn_im[221] = $signed(16'sh354E); 512 | assign wn_im[222] = $signed(16'sh33DF); 513 | assign wn_im[223] = $signed(16'sh326E); 514 | assign wn_im[224] = $signed(16'sh30FC); 515 | assign wn_im[225] = $signed(16'sh2F87); 516 | assign wn_im[226] = $signed(16'sh2E11); 517 | assign wn_im[227] = $signed(16'sh2C99); 518 | assign wn_im[228] = $signed(16'sh2B1F); 519 | assign wn_im[229] = $signed(16'sh29A4); 520 | assign wn_im[230] = $signed(16'sh2827); 521 | assign wn_im[231] = $signed(16'sh26A8); 522 | assign wn_im[232] = $signed(16'sh2528); 523 | assign wn_im[233] = $signed(16'sh23A7); 524 | assign wn_im[234] = $signed(16'sh2224); 525 | assign wn_im[235] = $signed(16'sh209F); 526 | assign wn_im[236] = $signed(16'sh1F1A); 527 | assign wn_im[237] = $signed(16'sh1D93); 528 | assign wn_im[238] = $signed(16'sh1C0C); 529 | assign wn_im[239] = $signed(16'sh1A83); 530 | assign wn_im[240] = $signed(16'sh18F9); 531 | assign wn_im[241] = $signed(16'sh176E); 532 | assign wn_im[242] = $signed(16'sh15E2); 533 | assign wn_im[243] = $signed(16'sh1455); 534 | assign wn_im[244] = $signed(16'sh12C8); 535 | assign wn_im[245] = $signed(16'sh113A); 536 | assign wn_im[246] = $signed(16'sh0FAB); 537 | assign wn_im[247] = $signed(16'sh0E1C); 538 | assign wn_im[248] = $signed(16'sh0C8C); 539 | assign wn_im[249] = $signed(16'sh0AFB); 540 | assign wn_im[250] = $signed(16'sh096B); 541 | assign wn_im[251] = $signed(16'sh07D9); 542 | assign wn_im[252] = $signed(16'sh0648); 543 | assign wn_im[253] = $signed(16'sh04B6); 544 | assign wn_im[254] = $signed(16'sh0324); 545 | assign wn_im[255] = $signed(16'sh0192); 546 | 547 | assign data0_re = wn_re[addr0]; 548 | assign data0_im = wn_im[addr0]; 549 | assign data1_re = wn_re[addr1]; 550 | assign data1_im = wn_im[addr1]; 551 | assign data2_re = wn_re[addr2]; 552 | assign data2_im = wn_im[addr2]; 553 | assign data3_re = wn_re[addr3]; 554 | assign data3_im = wn_im[addr3]; 555 | assign data4_re = wn_re[addr4]; 556 | assign data4_im = wn_im[addr4]; 557 | assign data5_re = wn_re[addr5]; 558 | assign data5_im = wn_im[addr5]; 559 | assign data6_re = wn_re[addr6]; 560 | assign data6_im = wn_im[addr6]; 561 | assign data7_re = wn_re[addr7]; 562 | assign data7_im = wn_im[addr7]; 563 | 564 | endmodule -------------------------------------------------------------------------------- /rtl/src/include/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !.gitignore 5 | !*.md 6 | !*.[cSh] 7 | !*.v 8 | !*.vh 9 | -------------------------------------------------------------------------------- /rtl/src/memory/fft_reoder_sramsp16x256_maskoff.v: -------------------------------------------------------------------------------- 1 | 2 | // use tsmc n28 hpc 3 | `define TSMC_N28HPC 4 | 5 | module fft_reoder_sramsp16x256_maskoff ( 6 | input clk, 7 | input ce, 8 | input rw, 9 | input [7:0] addr, 10 | input [15:0] din, 11 | output reg [15:0] dout 12 | ); 13 | 14 | `ifdef TSMC_N28HPC 15 | 16 | sramsp16x256_tsmc28hpc sramsp16x256_maskoff ( 17 | .CLK (clk ), 18 | .CEB (~ce ), 19 | .WEB (~rw ), 20 | .A (addr ), 21 | .D (din ), 22 | .Q (dout ) 23 | ); 24 | 25 | `else 26 | 27 | sramsp_maskoff #( 28 | .DATA_WIDTH(16), 29 | .ADDR_WIDTH(8) 30 | ) sramsp16x256_maskoff ( 31 | .CLK (clk ), 32 | .GWEN (~rw ), 33 | .CEN (~ce ), 34 | .A (addr), 35 | .D (din ), 36 | .Q (dout) 37 | ); 38 | 39 | `endif 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /rtl/src/memory/sramsp_maskoff.v: -------------------------------------------------------------------------------- 1 | module sramsp_maskoff #( 2 | parameter DATA_WIDTH = 16, 3 | parameter ADDR_WIDTH = 8 4 | ) ( 5 | input CLK, 6 | input GWEN, 7 | input CEN, 8 | input [ADDR_WIDTH-1:0] A, 9 | input [DATA_WIDTH-1:0] D, 10 | output reg [DATA_WIDTH-1:0] Q 11 | ); 12 | 13 | reg [DATA_WIDTH-1:0] mem [0:(1 << ADDR_WIDTH)-1]; 14 | 15 | always @(posedge CLK) begin 16 | if ((! CEN) && (! GWEN )) begin 17 | mem[A] <= D; 18 | end 19 | end 20 | always @(posedge CLK) begin 21 | if ((! CEN) && GWEN) begin 22 | Q <= mem[A]; 23 | end 24 | else begin 25 | Q <= {DATA_WIDTH{1'bx}}; 26 | end 27 | end 28 | 29 | endmodule 30 | -------------------------------------------------------------------------------- /rtl/src/reoder.v: -------------------------------------------------------------------------------- 1 | module reorder #( 2 | parameter DATA_WIDTH = 16, 3 | parameter FFT_LENGTH = 64 4 | ) ( 5 | input clk, 6 | input rst_n, 7 | input [DATA_WIDTH-1:0] in1_re, 8 | input [DATA_WIDTH-1:0] in1_im, 9 | input [DATA_WIDTH-1:0] in2_re, 10 | input [DATA_WIDTH-1:0] in2_im, 11 | input in_valid, 12 | input [1:0] np, 13 | output [DATA_WIDTH-1:0] out_re, 14 | output [DATA_WIDTH-1:0] out_im, 15 | output reg out_valid 16 | ); 17 | 18 | localparam TIMES = $clog2(FFT_LENGTH/2); 19 | 20 | reg [TIMES:0] index1; 21 | reg [TIMES:0] index2; 22 | 23 | reg [TIMES-1:0] in_counter; // receive 2 data per cycle 24 | reg [TIMES:0] out_counter, out_counter_reg1, out_counter_reg2; // output 1 data per cycle 25 | 26 | always @(posedge clk or negedge rst_n) begin 27 | if(!rst_n) begin 28 | out_counter_reg1 <= {(TIMES+1){1'b0}}; 29 | out_counter_reg2 <= {(TIMES+1){1'b0}}; 30 | end 31 | else begin 32 | out_counter_reg1 <= out_counter; 33 | out_counter_reg2 <= out_counter_reg1; 34 | end 35 | end 36 | 37 | wire out_valid_t; 38 | 39 | reg [9:0] point; 40 | always @(*) begin 41 | case(np) 42 | 2'b00: point = 10'd64; 43 | 2'b01: point = 10'd128; 44 | 2'b10: point = 10'd256; 45 | 2'b11: point = 10'd512; 46 | endcase 47 | end 48 | 49 | reg w_en; 50 | reg [TIMES-1:0] addr0, addr1; 51 | reg [DATA_WIDTH-1:0] din0, din1, din2, din3; 52 | wire [DATA_WIDTH-1:0] dout0, dout1, dout2, dout3; 53 | 54 | // rambank0_re 55 | fft_reoder_sramsp16x256_maskoff sram16x256_0 ( 56 | .clk(clk), 57 | .ce(1'b1), 58 | .rw(w_en), 59 | .addr(addr0), 60 | .din(din0), 61 | .dout(dout0) 62 | ); 63 | // rambank0_im 64 | fft_reoder_sramsp16x256_maskoff sram16x256_1 ( 65 | .clk(clk), 66 | .ce(1'b1), 67 | .rw(w_en), 68 | .addr(addr0), 69 | .din(din1), 70 | .dout(dout1) 71 | ); 72 | // rambank1_re 73 | fft_reoder_sramsp16x256_maskoff sram16x256_2 ( 74 | .clk(clk), 75 | .ce(1'b1), 76 | .rw(w_en), 77 | .addr(addr1), 78 | .din(din2), 79 | .dout(dout2) 80 | ); 81 | // rambank1_im 82 | fft_reoder_sramsp16x256_maskoff sram16x256_3 ( 83 | .clk(clk), 84 | .ce(1'b1), 85 | .rw(w_en), 86 | .addr(addr1), 87 | .din(din3), 88 | .dout(dout3) 89 | ); 90 | 91 | 92 | wire [TIMES:0] index1_0, index1_1, index1_2, index1_3; 93 | wire [TIMES:0] index2_0, index2_1, index2_2, index2_3; 94 | // 512 95 | reverse_bits #(TIMES+1) reverse_bits_00 ( 96 | .in({in_counter, 1'b0}), 97 | .out(index1_0) 98 | ); 99 | reverse_bits #(TIMES+1) reverse_bits_01 ( 100 | .in({in_counter, 1'b1}), 101 | .out(index2_0) 102 | ); 103 | // 256 104 | reverse_bits #(TIMES) reverse_bits_10 ( 105 | .in({in_counter[6:0], 1'b0}), 106 | .out(index1_1[7:0]) 107 | ); 108 | reverse_bits #(TIMES) reverse_bits_11 ( 109 | .in({in_counter[6:0], 1'b1}), 110 | .out(index2_1[7:0]) 111 | ); 112 | // 128 113 | reverse_bits #(TIMES-1) reverse_bits_20 ( 114 | .in({in_counter[5:0], 1'b0}), 115 | .out(index1_2[6:0]) 116 | ); 117 | reverse_bits #(TIMES-1) reverse_bits_21 ( 118 | .in({in_counter[5:0], 1'b1}), 119 | .out(index2_2[6:0]) 120 | ); 121 | // 64 122 | reverse_bits #(TIMES-2) reverse_bits_30 ( 123 | .in({in_counter[4:0], 1'b0}), 124 | .out(index1_3[5:0]) 125 | ); 126 | reverse_bits #(TIMES-2) reverse_bits_31 ( 127 | .in({in_counter[4:0], 1'b1}), 128 | .out(index2_3[5:0]) 129 | ); 130 | 131 | always @(*) begin 132 | case(np) 133 | 2'b00: begin //64 134 | index1 = {3'b0, index1_3[5:0]}; 135 | index2 = {3'b0, index2_3[5:0]}; 136 | end 137 | 2'b01: begin //128 138 | index1 = {2'b0, index1_2[6:0]}; 139 | index2 = {2'b0, index2_2[6:0]}; 140 | end 141 | 2'b10: begin //256 142 | index1 = {1'b0, index1_1[7:0]}; 143 | index2 = {1'b0, index2_1[7:0]}; 144 | end 145 | 2'b11: begin //512 146 | index1 = index1_0; 147 | index2 = index2_0; 148 | end 149 | endcase 150 | end 151 | 152 | 153 | always @(posedge clk or negedge rst_n) begin 154 | if (!rst_n) begin 155 | in_counter <= {TIMES{1'b0}}; 156 | addr0 <= {TIMES{1'b0}}; 157 | addr1 <= {TIMES{1'b0}}; 158 | end 159 | else if ((in_valid || in_counter != {TIMES{1'b0}}) && (in_counter < (point>>1))) begin 160 | in_counter <= in_counter + 1'b1; 161 | w_en <= 1'b1; 162 | addr0 <= index1; 163 | addr1 <= index2-(point>>1); 164 | din0 <= in1_re; 165 | din1 <= in1_im; 166 | din2 <= in2_re; 167 | din3 <= in2_im; 168 | end 169 | else begin 170 | in_counter <= {TIMES{1'b0}}; 171 | w_en <= 1'b0; 172 | 173 | if(out_counter < (point>>1)) begin 174 | addr0 <= out_counter; 175 | addr1 <= out_counter; 176 | end 177 | else begin 178 | addr0 <= out_counter-(point>>1); 179 | addr1 <= out_counter-(point>>1); 180 | end 181 | end 182 | end 183 | 184 | always @(posedge clk or negedge rst_n) begin 185 | if (!rst_n) begin 186 | out_counter <= {(TIMES+1){1'b0}}; 187 | end 188 | else if (out_valid_t && out_counter < point-1) begin 189 | out_counter <= out_counter + 1; 190 | end 191 | else begin 192 | out_counter <= {(TIMES+1){1'b0}}; 193 | end 194 | end 195 | 196 | reg [TIMES-1:0] in_counter_reg; 197 | always @(posedge clk or negedge rst_n) begin 198 | if (!rst_n) 199 | in_counter_reg <= {TIMES{1'b0}}; 200 | else 201 | in_counter_reg <= in_counter; 202 | end 203 | 204 | assign out_re = (out_counter_reg2 < ((point>>1))) ? dout0 : dout2; 205 | assign out_im = (out_counter_reg2 < ((point>>1))) ? dout1 : dout3; 206 | 207 | assign out_valid_t = (in_counter_reg == ((point>>1) - 1)) || (out_counter != 0); 208 | 209 | reg out_valid_t1; 210 | always @(posedge clk or negedge rst_n) begin 211 | if(!rst_n) begin 212 | out_valid_t1 <= 1'b0; 213 | out_valid <= 1'b0; 214 | end 215 | else begin 216 | out_valid_t1 <= out_valid_t; 217 | out_valid <= out_valid_t1; 218 | end 219 | end 220 | 221 | endmodule 222 | -------------------------------------------------------------------------------- /rtl/src/reserve_bits.v: -------------------------------------------------------------------------------- 1 | module reverse_bits #( 2 | parameter WIDTH = 16 3 | )( 4 | input [WIDTH-1:0] in, 5 | output [WIDTH-1:0] out 6 | ); 7 | 8 | genvar i; 9 | generate 10 | for(i = 0; i < WIDTH; i = i + 1) begin : bit_reverse 11 | assign out[i] = in[WIDTH-1 - i]; 12 | end 13 | endgenerate 14 | 15 | endmodule 16 | -------------------------------------------------------------------------------- /rtl/src/shiftreg.v: -------------------------------------------------------------------------------- 1 | // Author: brimonzzy 2 | // Create Date: 2025/2/13 3 | // Description: N-stage shift register with width W 4 | 5 | module shiftreg #( 6 | parameter W = 16, 7 | parameter N = 8 8 | )( 9 | input clk, 10 | input rst_n, 11 | input [W-1:0] d_in, 12 | output [W-1:0] d_out 13 | ); 14 | 15 | reg [W-1:0] shift_reg [N-1:0]; 16 | integer i; 17 | 18 | always @(posedge clk or negedge rst_n) begin 19 | if (!rst_n) begin 20 | for (i = 0; i < N; i = i + 1) begin 21 | shift_reg[i] <= {W{1'b0}}; 22 | end 23 | end 24 | else begin 25 | shift_reg[0] <= d_in; 26 | for (i = 1; i < N; i = i + 1) begin 27 | shift_reg[i] <= shift_reg[i-1]; 28 | end 29 | end 30 | end 31 | 32 | assign d_out = shift_reg[N-1]; 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /rtl/src/switch.v: -------------------------------------------------------------------------------- 1 | // Author: brimonzzy 2 | // Create Date: 2025/2/13 3 | // Description: Complex switch module 4 | 5 | module switch ( 6 | input sel, 7 | input signed [15:0] x0_re, 8 | input signed [15:0] x0_im, 9 | input signed [15:0] x1_re, 10 | input signed [15:0] x1_im, 11 | output signed [15:0] y0_re, 12 | output signed [15:0] y0_im, 13 | output signed [15:0] y1_re, 14 | output signed [15:0] y1_im 15 | ); 16 | 17 | assign y0_re = sel ? x1_re : x0_re; 18 | assign y0_im = sel ? x1_im : x0_im; 19 | assign y1_re = sel ? x0_re : x1_re; 20 | assign y1_im = sel ? x0_im : x1_im; 21 | 22 | endmodule 23 | -------------------------------------------------------------------------------- /rtl/src/twiddle_rom.v: -------------------------------------------------------------------------------- 1 | // For 512-point FFT 2 | // 8 read ports 3 | 4 | module twiddle_rom ( 5 | input [7:0] addr0, 6 | input [7:0] addr1, 7 | input [7:0] addr2, 8 | input [7:0] addr3, 9 | input [7:0] addr4, 10 | input [7:0] addr5, 11 | input [7:0] addr6, 12 | input [7:0] addr7, 13 | output [15:0] data0_re, 14 | output [15:0] data0_im, 15 | output [15:0] data1_re, 16 | output [15:0] data1_im, 17 | output [15:0] data2_re, 18 | output [15:0] data2_im, 19 | output [15:0] data3_re, 20 | output [15:0] data3_im, 21 | output [15:0] data4_re, 22 | output [15:0] data4_im, 23 | output [15:0] data5_re, 24 | output [15:0] data5_im, 25 | output [15:0] data6_re, 26 | output [15:0] data6_im, 27 | output [15:0] data7_re, 28 | output [15:0] data7_im 29 | ); 30 | // For N=512 31 | wire signed [15:0] wn_re [0:255]; 32 | wire signed [15:0] wn_im [0:255]; 33 | 34 | assign wn_re[0] = $signed(16'sh7FFF); 35 | assign wn_re[1] = $signed(16'sh7FFE); 36 | assign wn_re[2] = $signed(16'sh7FF6); 37 | assign wn_re[3] = $signed(16'sh7FEA); 38 | assign wn_re[4] = $signed(16'sh7FD9); 39 | assign wn_re[5] = $signed(16'sh7FC2); 40 | assign wn_re[6] = $signed(16'sh7FA7); 41 | assign wn_re[7] = $signed(16'sh7F87); 42 | assign wn_re[8] = $signed(16'sh7F62); 43 | assign wn_re[9] = $signed(16'sh7F38); 44 | assign wn_re[10] = $signed(16'sh7F0A); 45 | assign wn_re[11] = $signed(16'sh7ED6); 46 | assign wn_re[12] = $signed(16'sh7E9D); 47 | assign wn_re[13] = $signed(16'sh7E60); 48 | assign wn_re[14] = $signed(16'sh7E1E); 49 | assign wn_re[15] = $signed(16'sh7DD6); 50 | assign wn_re[16] = $signed(16'sh7D8A); 51 | assign wn_re[17] = $signed(16'sh7D3A); 52 | assign wn_re[18] = $signed(16'sh7CE4); 53 | assign wn_re[19] = $signed(16'sh7C89); 54 | assign wn_re[20] = $signed(16'sh7C2A); 55 | assign wn_re[21] = $signed(16'sh7BC6); 56 | assign wn_re[22] = $signed(16'sh7B5D); 57 | assign wn_re[23] = $signed(16'sh7AEF); 58 | assign wn_re[24] = $signed(16'sh7A7D); 59 | assign wn_re[25] = $signed(16'sh7A06); 60 | assign wn_re[26] = $signed(16'sh798A); 61 | assign wn_re[27] = $signed(16'sh790A); 62 | assign wn_re[28] = $signed(16'sh7885); 63 | assign wn_re[29] = $signed(16'sh77FB); 64 | assign wn_re[30] = $signed(16'sh776C); 65 | assign wn_re[31] = $signed(16'sh76D9); 66 | assign wn_re[32] = $signed(16'sh7642); 67 | assign wn_re[33] = $signed(16'sh75A6); 68 | assign wn_re[34] = $signed(16'sh7505); 69 | assign wn_re[35] = $signed(16'sh7460); 70 | assign wn_re[36] = $signed(16'sh73B6); 71 | assign wn_re[37] = $signed(16'sh7308); 72 | assign wn_re[38] = $signed(16'sh7255); 73 | assign wn_re[39] = $signed(16'sh719E); 74 | assign wn_re[40] = $signed(16'sh70E3); 75 | assign wn_re[41] = $signed(16'sh7023); 76 | assign wn_re[42] = $signed(16'sh6F5F); 77 | assign wn_re[43] = $signed(16'sh6E97); 78 | assign wn_re[44] = $signed(16'sh6DCA); 79 | assign wn_re[45] = $signed(16'sh6CF9); 80 | assign wn_re[46] = $signed(16'sh6C24); 81 | assign wn_re[47] = $signed(16'sh6B4B); 82 | assign wn_re[48] = $signed(16'sh6A6E); 83 | assign wn_re[49] = $signed(16'sh698C); 84 | assign wn_re[50] = $signed(16'sh68A7); 85 | assign wn_re[51] = $signed(16'sh67BD); 86 | assign wn_re[52] = $signed(16'sh66D0); 87 | assign wn_re[53] = $signed(16'sh65DE); 88 | assign wn_re[54] = $signed(16'sh64E9); 89 | assign wn_re[55] = $signed(16'sh63EF); 90 | assign wn_re[56] = $signed(16'sh62F2); 91 | assign wn_re[57] = $signed(16'sh61F1); 92 | assign wn_re[58] = $signed(16'sh60EC); 93 | assign wn_re[59] = $signed(16'sh5FE4); 94 | assign wn_re[60] = $signed(16'sh5ED7); 95 | assign wn_re[61] = $signed(16'sh5DC8); 96 | assign wn_re[62] = $signed(16'sh5CB4); 97 | assign wn_re[63] = $signed(16'sh5B9D); 98 | assign wn_re[64] = $signed(16'sh5A82); 99 | assign wn_re[65] = $signed(16'sh5964); 100 | assign wn_re[66] = $signed(16'sh5843); 101 | assign wn_re[67] = $signed(16'sh571E); 102 | assign wn_re[68] = $signed(16'sh55F6); 103 | assign wn_re[69] = $signed(16'sh54CA); 104 | assign wn_re[70] = $signed(16'sh539B); 105 | assign wn_re[71] = $signed(16'sh5269); 106 | assign wn_re[72] = $signed(16'sh5134); 107 | assign wn_re[73] = $signed(16'sh4FFB); 108 | assign wn_re[74] = $signed(16'sh4EC0); 109 | assign wn_re[75] = $signed(16'sh4D81); 110 | assign wn_re[76] = $signed(16'sh4C40); 111 | assign wn_re[77] = $signed(16'sh4AFB); 112 | assign wn_re[78] = $signed(16'sh49B4); 113 | assign wn_re[79] = $signed(16'sh486A); 114 | assign wn_re[80] = $signed(16'sh471D); 115 | assign wn_re[81] = $signed(16'sh45CD); 116 | assign wn_re[82] = $signed(16'sh447B); 117 | assign wn_re[83] = $signed(16'sh4326); 118 | assign wn_re[84] = $signed(16'sh41CE); 119 | assign wn_re[85] = $signed(16'sh4074); 120 | assign wn_re[86] = $signed(16'sh3F17); 121 | assign wn_re[87] = $signed(16'sh3DB8); 122 | assign wn_re[88] = $signed(16'sh3C57); 123 | assign wn_re[89] = $signed(16'sh3AF3); 124 | assign wn_re[90] = $signed(16'sh398D); 125 | assign wn_re[91] = $signed(16'sh3825); 126 | assign wn_re[92] = $signed(16'sh36BA); 127 | assign wn_re[93] = $signed(16'sh354E); 128 | assign wn_re[94] = $signed(16'sh33DF); 129 | assign wn_re[95] = $signed(16'sh326E); 130 | assign wn_re[96] = $signed(16'sh30FC); 131 | assign wn_re[97] = $signed(16'sh2F87); 132 | assign wn_re[98] = $signed(16'sh2E11); 133 | assign wn_re[99] = $signed(16'sh2C99); 134 | assign wn_re[100] = $signed(16'sh2B1F); 135 | assign wn_re[101] = $signed(16'sh29A4); 136 | assign wn_re[102] = $signed(16'sh2827); 137 | assign wn_re[103] = $signed(16'sh26A8); 138 | assign wn_re[104] = $signed(16'sh2528); 139 | assign wn_re[105] = $signed(16'sh23A7); 140 | assign wn_re[106] = $signed(16'sh2224); 141 | assign wn_re[107] = $signed(16'sh209F); 142 | assign wn_re[108] = $signed(16'sh1F1A); 143 | assign wn_re[109] = $signed(16'sh1D93); 144 | assign wn_re[110] = $signed(16'sh1C0C); 145 | assign wn_re[111] = $signed(16'sh1A83); 146 | assign wn_re[112] = $signed(16'sh18F9); 147 | assign wn_re[113] = $signed(16'sh176E); 148 | assign wn_re[114] = $signed(16'sh15E2); 149 | assign wn_re[115] = $signed(16'sh1455); 150 | assign wn_re[116] = $signed(16'sh12C8); 151 | assign wn_re[117] = $signed(16'sh113A); 152 | assign wn_re[118] = $signed(16'sh0FAB); 153 | assign wn_re[119] = $signed(16'sh0E1C); 154 | assign wn_re[120] = $signed(16'sh0C8C); 155 | assign wn_re[121] = $signed(16'sh0AFB); 156 | assign wn_re[122] = $signed(16'sh096B); 157 | assign wn_re[123] = $signed(16'sh07D9); 158 | assign wn_re[124] = $signed(16'sh0648); 159 | assign wn_re[125] = $signed(16'sh04B6); 160 | assign wn_re[126] = $signed(16'sh0324); 161 | assign wn_re[127] = $signed(16'sh0192); 162 | assign wn_re[128] = $signed(16'sh0000); 163 | assign wn_re[129] = $signed(-16'sh0192); 164 | assign wn_re[130] = $signed(-16'sh0324); 165 | assign wn_re[131] = $signed(-16'sh04B6); 166 | assign wn_re[132] = $signed(-16'sh0648); 167 | assign wn_re[133] = $signed(-16'sh07D9); 168 | assign wn_re[134] = $signed(-16'sh096B); 169 | assign wn_re[135] = $signed(-16'sh0AFB); 170 | assign wn_re[136] = $signed(-16'sh0C8C); 171 | assign wn_re[137] = $signed(-16'sh0E1C); 172 | assign wn_re[138] = $signed(-16'sh0FAB); 173 | assign wn_re[139] = $signed(-16'sh113A); 174 | assign wn_re[140] = $signed(-16'sh12C8); 175 | assign wn_re[141] = $signed(-16'sh1455); 176 | assign wn_re[142] = $signed(-16'sh15E2); 177 | assign wn_re[143] = $signed(-16'sh176E); 178 | assign wn_re[144] = $signed(-16'sh18F9); 179 | assign wn_re[145] = $signed(-16'sh1A83); 180 | assign wn_re[146] = $signed(-16'sh1C0C); 181 | assign wn_re[147] = $signed(-16'sh1D93); 182 | assign wn_re[148] = $signed(-16'sh1F1A); 183 | assign wn_re[149] = $signed(-16'sh209F); 184 | assign wn_re[150] = $signed(-16'sh2224); 185 | assign wn_re[151] = $signed(-16'sh23A7); 186 | assign wn_re[152] = $signed(-16'sh2528); 187 | assign wn_re[153] = $signed(-16'sh26A8); 188 | assign wn_re[154] = $signed(-16'sh2827); 189 | assign wn_re[155] = $signed(-16'sh29A4); 190 | assign wn_re[156] = $signed(-16'sh2B1F); 191 | assign wn_re[157] = $signed(-16'sh2C99); 192 | assign wn_re[158] = $signed(-16'sh2E11); 193 | assign wn_re[159] = $signed(-16'sh2F87); 194 | assign wn_re[160] = $signed(-16'sh30FC); 195 | assign wn_re[161] = $signed(-16'sh326E); 196 | assign wn_re[162] = $signed(-16'sh33DF); 197 | assign wn_re[163] = $signed(-16'sh354E); 198 | assign wn_re[164] = $signed(-16'sh36BA); 199 | assign wn_re[165] = $signed(-16'sh3825); 200 | assign wn_re[166] = $signed(-16'sh398D); 201 | assign wn_re[167] = $signed(-16'sh3AF3); 202 | assign wn_re[168] = $signed(-16'sh3C57); 203 | assign wn_re[169] = $signed(-16'sh3DB8); 204 | assign wn_re[170] = $signed(-16'sh3F17); 205 | assign wn_re[171] = $signed(-16'sh4074); 206 | assign wn_re[172] = $signed(-16'sh41CE); 207 | assign wn_re[173] = $signed(-16'sh4326); 208 | assign wn_re[174] = $signed(-16'sh447B); 209 | assign wn_re[175] = $signed(-16'sh45CD); 210 | assign wn_re[176] = $signed(-16'sh471D); 211 | assign wn_re[177] = $signed(-16'sh486A); 212 | assign wn_re[178] = $signed(-16'sh49B4); 213 | assign wn_re[179] = $signed(-16'sh4AFB); 214 | assign wn_re[180] = $signed(-16'sh4C40); 215 | assign wn_re[181] = $signed(-16'sh4D81); 216 | assign wn_re[182] = $signed(-16'sh4EC0); 217 | assign wn_re[183] = $signed(-16'sh4FFB); 218 | assign wn_re[184] = $signed(-16'sh5134); 219 | assign wn_re[185] = $signed(-16'sh5269); 220 | assign wn_re[186] = $signed(-16'sh539B); 221 | assign wn_re[187] = $signed(-16'sh54CA); 222 | assign wn_re[188] = $signed(-16'sh55F6); 223 | assign wn_re[189] = $signed(-16'sh571E); 224 | assign wn_re[190] = $signed(-16'sh5843); 225 | assign wn_re[191] = $signed(-16'sh5964); 226 | assign wn_re[192] = $signed(-16'sh5A82); 227 | assign wn_re[193] = $signed(-16'sh5B9D); 228 | assign wn_re[194] = $signed(-16'sh5CB4); 229 | assign wn_re[195] = $signed(-16'sh5DC8); 230 | assign wn_re[196] = $signed(-16'sh5ED7); 231 | assign wn_re[197] = $signed(-16'sh5FE4); 232 | assign wn_re[198] = $signed(-16'sh60EC); 233 | assign wn_re[199] = $signed(-16'sh61F1); 234 | assign wn_re[200] = $signed(-16'sh62F2); 235 | assign wn_re[201] = $signed(-16'sh63EF); 236 | assign wn_re[202] = $signed(-16'sh64E9); 237 | assign wn_re[203] = $signed(-16'sh65DE); 238 | assign wn_re[204] = $signed(-16'sh66D0); 239 | assign wn_re[205] = $signed(-16'sh67BD); 240 | assign wn_re[206] = $signed(-16'sh68A7); 241 | assign wn_re[207] = $signed(-16'sh698C); 242 | assign wn_re[208] = $signed(-16'sh6A6E); 243 | assign wn_re[209] = $signed(-16'sh6B4B); 244 | assign wn_re[210] = $signed(-16'sh6C24); 245 | assign wn_re[211] = $signed(-16'sh6CF9); 246 | assign wn_re[212] = $signed(-16'sh6DCA); 247 | assign wn_re[213] = $signed(-16'sh6E97); 248 | assign wn_re[214] = $signed(-16'sh6F5F); 249 | assign wn_re[215] = $signed(-16'sh7023); 250 | assign wn_re[216] = $signed(-16'sh70E3); 251 | assign wn_re[217] = $signed(-16'sh719E); 252 | assign wn_re[218] = $signed(-16'sh7255); 253 | assign wn_re[219] = $signed(-16'sh7308); 254 | assign wn_re[220] = $signed(-16'sh73B6); 255 | assign wn_re[221] = $signed(-16'sh7460); 256 | assign wn_re[222] = $signed(-16'sh7505); 257 | assign wn_re[223] = $signed(-16'sh75A6); 258 | assign wn_re[224] = $signed(-16'sh7642); 259 | assign wn_re[225] = $signed(-16'sh76D9); 260 | assign wn_re[226] = $signed(-16'sh776C); 261 | assign wn_re[227] = $signed(-16'sh77FB); 262 | assign wn_re[228] = $signed(-16'sh7885); 263 | assign wn_re[229] = $signed(-16'sh790A); 264 | assign wn_re[230] = $signed(-16'sh798A); 265 | assign wn_re[231] = $signed(-16'sh7A06); 266 | assign wn_re[232] = $signed(-16'sh7A7D); 267 | assign wn_re[233] = $signed(-16'sh7AEF); 268 | assign wn_re[234] = $signed(-16'sh7B5D); 269 | assign wn_re[235] = $signed(-16'sh7BC6); 270 | assign wn_re[236] = $signed(-16'sh7C2A); 271 | assign wn_re[237] = $signed(-16'sh7C89); 272 | assign wn_re[238] = $signed(-16'sh7CE4); 273 | assign wn_re[239] = $signed(-16'sh7D3A); 274 | assign wn_re[240] = $signed(-16'sh7D8A); 275 | assign wn_re[241] = $signed(-16'sh7DD6); 276 | assign wn_re[242] = $signed(-16'sh7E1E); 277 | assign wn_re[243] = $signed(-16'sh7E60); 278 | assign wn_re[244] = $signed(-16'sh7E9D); 279 | assign wn_re[245] = $signed(-16'sh7ED6); 280 | assign wn_re[246] = $signed(-16'sh7F0A); 281 | assign wn_re[247] = $signed(-16'sh7F38); 282 | assign wn_re[248] = $signed(-16'sh7F62); 283 | assign wn_re[249] = $signed(-16'sh7F87); 284 | assign wn_re[250] = $signed(-16'sh7FA7); 285 | assign wn_re[251] = $signed(-16'sh7FC2); 286 | assign wn_re[252] = $signed(-16'sh7FD9); 287 | assign wn_re[253] = $signed(-16'sh7FEA); 288 | assign wn_re[254] = $signed(-16'sh7FF6); 289 | assign wn_re[255] = $signed(-16'sh7FFE); 290 | assign wn_im[0] = $signed(16'sh0000); 291 | assign wn_im[1] = $signed(-16'sh0192); 292 | assign wn_im[2] = $signed(-16'sh0324); 293 | assign wn_im[3] = $signed(-16'sh04B6); 294 | assign wn_im[4] = $signed(-16'sh0648); 295 | assign wn_im[5] = $signed(-16'sh07D9); 296 | assign wn_im[6] = $signed(-16'sh096B); 297 | assign wn_im[7] = $signed(-16'sh0AFB); 298 | assign wn_im[8] = $signed(-16'sh0C8C); 299 | assign wn_im[9] = $signed(-16'sh0E1C); 300 | assign wn_im[10] = $signed(-16'sh0FAB); 301 | assign wn_im[11] = $signed(-16'sh113A); 302 | assign wn_im[12] = $signed(-16'sh12C8); 303 | assign wn_im[13] = $signed(-16'sh1455); 304 | assign wn_im[14] = $signed(-16'sh15E2); 305 | assign wn_im[15] = $signed(-16'sh176E); 306 | assign wn_im[16] = $signed(-16'sh18F9); 307 | assign wn_im[17] = $signed(-16'sh1A83); 308 | assign wn_im[18] = $signed(-16'sh1C0C); 309 | assign wn_im[19] = $signed(-16'sh1D93); 310 | assign wn_im[20] = $signed(-16'sh1F1A); 311 | assign wn_im[21] = $signed(-16'sh209F); 312 | assign wn_im[22] = $signed(-16'sh2224); 313 | assign wn_im[23] = $signed(-16'sh23A7); 314 | assign wn_im[24] = $signed(-16'sh2528); 315 | assign wn_im[25] = $signed(-16'sh26A8); 316 | assign wn_im[26] = $signed(-16'sh2827); 317 | assign wn_im[27] = $signed(-16'sh29A4); 318 | assign wn_im[28] = $signed(-16'sh2B1F); 319 | assign wn_im[29] = $signed(-16'sh2C99); 320 | assign wn_im[30] = $signed(-16'sh2E11); 321 | assign wn_im[31] = $signed(-16'sh2F87); 322 | assign wn_im[32] = $signed(-16'sh30FC); 323 | assign wn_im[33] = $signed(-16'sh326E); 324 | assign wn_im[34] = $signed(-16'sh33DF); 325 | assign wn_im[35] = $signed(-16'sh354E); 326 | assign wn_im[36] = $signed(-16'sh36BA); 327 | assign wn_im[37] = $signed(-16'sh3825); 328 | assign wn_im[38] = $signed(-16'sh398D); 329 | assign wn_im[39] = $signed(-16'sh3AF3); 330 | assign wn_im[40] = $signed(-16'sh3C57); 331 | assign wn_im[41] = $signed(-16'sh3DB8); 332 | assign wn_im[42] = $signed(-16'sh3F17); 333 | assign wn_im[43] = $signed(-16'sh4074); 334 | assign wn_im[44] = $signed(-16'sh41CE); 335 | assign wn_im[45] = $signed(-16'sh4326); 336 | assign wn_im[46] = $signed(-16'sh447B); 337 | assign wn_im[47] = $signed(-16'sh45CD); 338 | assign wn_im[48] = $signed(-16'sh471D); 339 | assign wn_im[49] = $signed(-16'sh486A); 340 | assign wn_im[50] = $signed(-16'sh49B4); 341 | assign wn_im[51] = $signed(-16'sh4AFB); 342 | assign wn_im[52] = $signed(-16'sh4C40); 343 | assign wn_im[53] = $signed(-16'sh4D81); 344 | assign wn_im[54] = $signed(-16'sh4EC0); 345 | assign wn_im[55] = $signed(-16'sh4FFB); 346 | assign wn_im[56] = $signed(-16'sh5134); 347 | assign wn_im[57] = $signed(-16'sh5269); 348 | assign wn_im[58] = $signed(-16'sh539B); 349 | assign wn_im[59] = $signed(-16'sh54CA); 350 | assign wn_im[60] = $signed(-16'sh55F6); 351 | assign wn_im[61] = $signed(-16'sh571E); 352 | assign wn_im[62] = $signed(-16'sh5843); 353 | assign wn_im[63] = $signed(-16'sh5964); 354 | assign wn_im[64] = $signed(-16'sh5A82); 355 | assign wn_im[65] = $signed(-16'sh5B9D); 356 | assign wn_im[66] = $signed(-16'sh5CB4); 357 | assign wn_im[67] = $signed(-16'sh5DC8); 358 | assign wn_im[68] = $signed(-16'sh5ED7); 359 | assign wn_im[69] = $signed(-16'sh5FE4); 360 | assign wn_im[70] = $signed(-16'sh60EC); 361 | assign wn_im[71] = $signed(-16'sh61F1); 362 | assign wn_im[72] = $signed(-16'sh62F2); 363 | assign wn_im[73] = $signed(-16'sh63EF); 364 | assign wn_im[74] = $signed(-16'sh64E9); 365 | assign wn_im[75] = $signed(-16'sh65DE); 366 | assign wn_im[76] = $signed(-16'sh66D0); 367 | assign wn_im[77] = $signed(-16'sh67BD); 368 | assign wn_im[78] = $signed(-16'sh68A7); 369 | assign wn_im[79] = $signed(-16'sh698C); 370 | assign wn_im[80] = $signed(-16'sh6A6E); 371 | assign wn_im[81] = $signed(-16'sh6B4B); 372 | assign wn_im[82] = $signed(-16'sh6C24); 373 | assign wn_im[83] = $signed(-16'sh6CF9); 374 | assign wn_im[84] = $signed(-16'sh6DCA); 375 | assign wn_im[85] = $signed(-16'sh6E97); 376 | assign wn_im[86] = $signed(-16'sh6F5F); 377 | assign wn_im[87] = $signed(-16'sh7023); 378 | assign wn_im[88] = $signed(-16'sh70E3); 379 | assign wn_im[89] = $signed(-16'sh719E); 380 | assign wn_im[90] = $signed(-16'sh7255); 381 | assign wn_im[91] = $signed(-16'sh7308); 382 | assign wn_im[92] = $signed(-16'sh73B6); 383 | assign wn_im[93] = $signed(-16'sh7460); 384 | assign wn_im[94] = $signed(-16'sh7505); 385 | assign wn_im[95] = $signed(-16'sh75A6); 386 | assign wn_im[96] = $signed(-16'sh7642); 387 | assign wn_im[97] = $signed(-16'sh76D9); 388 | assign wn_im[98] = $signed(-16'sh776C); 389 | assign wn_im[99] = $signed(-16'sh77FB); 390 | assign wn_im[100] = $signed(-16'sh7885); 391 | assign wn_im[101] = $signed(-16'sh790A); 392 | assign wn_im[102] = $signed(-16'sh798A); 393 | assign wn_im[103] = $signed(-16'sh7A06); 394 | assign wn_im[104] = $signed(-16'sh7A7D); 395 | assign wn_im[105] = $signed(-16'sh7AEF); 396 | assign wn_im[106] = $signed(-16'sh7B5D); 397 | assign wn_im[107] = $signed(-16'sh7BC6); 398 | assign wn_im[108] = $signed(-16'sh7C2A); 399 | assign wn_im[109] = $signed(-16'sh7C89); 400 | assign wn_im[110] = $signed(-16'sh7CE4); 401 | assign wn_im[111] = $signed(-16'sh7D3A); 402 | assign wn_im[112] = $signed(-16'sh7D8A); 403 | assign wn_im[113] = $signed(-16'sh7DD6); 404 | assign wn_im[114] = $signed(-16'sh7E1E); 405 | assign wn_im[115] = $signed(-16'sh7E60); 406 | assign wn_im[116] = $signed(-16'sh7E9D); 407 | assign wn_im[117] = $signed(-16'sh7ED6); 408 | assign wn_im[118] = $signed(-16'sh7F0A); 409 | assign wn_im[119] = $signed(-16'sh7F38); 410 | assign wn_im[120] = $signed(-16'sh7F62); 411 | assign wn_im[121] = $signed(-16'sh7F87); 412 | assign wn_im[122] = $signed(-16'sh7FA7); 413 | assign wn_im[123] = $signed(-16'sh7FC2); 414 | assign wn_im[124] = $signed(-16'sh7FD9); 415 | assign wn_im[125] = $signed(-16'sh7FEA); 416 | assign wn_im[126] = $signed(-16'sh7FF6); 417 | assign wn_im[127] = $signed(-16'sh7FFE); 418 | assign wn_im[128] = $signed(-16'sh7FFF); 419 | assign wn_im[129] = $signed(-16'sh7FFE); 420 | assign wn_im[130] = $signed(-16'sh7FF6); 421 | assign wn_im[131] = $signed(-16'sh7FEA); 422 | assign wn_im[132] = $signed(-16'sh7FD9); 423 | assign wn_im[133] = $signed(-16'sh7FC2); 424 | assign wn_im[134] = $signed(-16'sh7FA7); 425 | assign wn_im[135] = $signed(-16'sh7F87); 426 | assign wn_im[136] = $signed(-16'sh7F62); 427 | assign wn_im[137] = $signed(-16'sh7F38); 428 | assign wn_im[138] = $signed(-16'sh7F0A); 429 | assign wn_im[139] = $signed(-16'sh7ED6); 430 | assign wn_im[140] = $signed(-16'sh7E9D); 431 | assign wn_im[141] = $signed(-16'sh7E60); 432 | assign wn_im[142] = $signed(-16'sh7E1E); 433 | assign wn_im[143] = $signed(-16'sh7DD6); 434 | assign wn_im[144] = $signed(-16'sh7D8A); 435 | assign wn_im[145] = $signed(-16'sh7D3A); 436 | assign wn_im[146] = $signed(-16'sh7CE4); 437 | assign wn_im[147] = $signed(-16'sh7C89); 438 | assign wn_im[148] = $signed(-16'sh7C2A); 439 | assign wn_im[149] = $signed(-16'sh7BC6); 440 | assign wn_im[150] = $signed(-16'sh7B5D); 441 | assign wn_im[151] = $signed(-16'sh7AEF); 442 | assign wn_im[152] = $signed(-16'sh7A7D); 443 | assign wn_im[153] = $signed(-16'sh7A06); 444 | assign wn_im[154] = $signed(-16'sh798A); 445 | assign wn_im[155] = $signed(-16'sh790A); 446 | assign wn_im[156] = $signed(-16'sh7885); 447 | assign wn_im[157] = $signed(-16'sh77FB); 448 | assign wn_im[158] = $signed(-16'sh776C); 449 | assign wn_im[159] = $signed(-16'sh76D9); 450 | assign wn_im[160] = $signed(-16'sh7642); 451 | assign wn_im[161] = $signed(-16'sh75A6); 452 | assign wn_im[162] = $signed(-16'sh7505); 453 | assign wn_im[163] = $signed(-16'sh7460); 454 | assign wn_im[164] = $signed(-16'sh73B6); 455 | assign wn_im[165] = $signed(-16'sh7308); 456 | assign wn_im[166] = $signed(-16'sh7255); 457 | assign wn_im[167] = $signed(-16'sh719E); 458 | assign wn_im[168] = $signed(-16'sh70E3); 459 | assign wn_im[169] = $signed(-16'sh7023); 460 | assign wn_im[170] = $signed(-16'sh6F5F); 461 | assign wn_im[171] = $signed(-16'sh6E97); 462 | assign wn_im[172] = $signed(-16'sh6DCA); 463 | assign wn_im[173] = $signed(-16'sh6CF9); 464 | assign wn_im[174] = $signed(-16'sh6C24); 465 | assign wn_im[175] = $signed(-16'sh6B4B); 466 | assign wn_im[176] = $signed(-16'sh6A6E); 467 | assign wn_im[177] = $signed(-16'sh698C); 468 | assign wn_im[178] = $signed(-16'sh68A7); 469 | assign wn_im[179] = $signed(-16'sh67BD); 470 | assign wn_im[180] = $signed(-16'sh66D0); 471 | assign wn_im[181] = $signed(-16'sh65DE); 472 | assign wn_im[182] = $signed(-16'sh64E9); 473 | assign wn_im[183] = $signed(-16'sh63EF); 474 | assign wn_im[184] = $signed(-16'sh62F2); 475 | assign wn_im[185] = $signed(-16'sh61F1); 476 | assign wn_im[186] = $signed(-16'sh60EC); 477 | assign wn_im[187] = $signed(-16'sh5FE4); 478 | assign wn_im[188] = $signed(-16'sh5ED7); 479 | assign wn_im[189] = $signed(-16'sh5DC8); 480 | assign wn_im[190] = $signed(-16'sh5CB4); 481 | assign wn_im[191] = $signed(-16'sh5B9D); 482 | assign wn_im[192] = $signed(-16'sh5A82); 483 | assign wn_im[193] = $signed(-16'sh5964); 484 | assign wn_im[194] = $signed(-16'sh5843); 485 | assign wn_im[195] = $signed(-16'sh571E); 486 | assign wn_im[196] = $signed(-16'sh55F6); 487 | assign wn_im[197] = $signed(-16'sh54CA); 488 | assign wn_im[198] = $signed(-16'sh539B); 489 | assign wn_im[199] = $signed(-16'sh5269); 490 | assign wn_im[200] = $signed(-16'sh5134); 491 | assign wn_im[201] = $signed(-16'sh4FFB); 492 | assign wn_im[202] = $signed(-16'sh4EC0); 493 | assign wn_im[203] = $signed(-16'sh4D81); 494 | assign wn_im[204] = $signed(-16'sh4C40); 495 | assign wn_im[205] = $signed(-16'sh4AFB); 496 | assign wn_im[206] = $signed(-16'sh49B4); 497 | assign wn_im[207] = $signed(-16'sh486A); 498 | assign wn_im[208] = $signed(-16'sh471D); 499 | assign wn_im[209] = $signed(-16'sh45CD); 500 | assign wn_im[210] = $signed(-16'sh447B); 501 | assign wn_im[211] = $signed(-16'sh4326); 502 | assign wn_im[212] = $signed(-16'sh41CE); 503 | assign wn_im[213] = $signed(-16'sh4074); 504 | assign wn_im[214] = $signed(-16'sh3F17); 505 | assign wn_im[215] = $signed(-16'sh3DB8); 506 | assign wn_im[216] = $signed(-16'sh3C57); 507 | assign wn_im[217] = $signed(-16'sh3AF3); 508 | assign wn_im[218] = $signed(-16'sh398D); 509 | assign wn_im[219] = $signed(-16'sh3825); 510 | assign wn_im[220] = $signed(-16'sh36BA); 511 | assign wn_im[221] = $signed(-16'sh354E); 512 | assign wn_im[222] = $signed(-16'sh33DF); 513 | assign wn_im[223] = $signed(-16'sh326E); 514 | assign wn_im[224] = $signed(-16'sh30FC); 515 | assign wn_im[225] = $signed(-16'sh2F87); 516 | assign wn_im[226] = $signed(-16'sh2E11); 517 | assign wn_im[227] = $signed(-16'sh2C99); 518 | assign wn_im[228] = $signed(-16'sh2B1F); 519 | assign wn_im[229] = $signed(-16'sh29A4); 520 | assign wn_im[230] = $signed(-16'sh2827); 521 | assign wn_im[231] = $signed(-16'sh26A8); 522 | assign wn_im[232] = $signed(-16'sh2528); 523 | assign wn_im[233] = $signed(-16'sh23A7); 524 | assign wn_im[234] = $signed(-16'sh2224); 525 | assign wn_im[235] = $signed(-16'sh209F); 526 | assign wn_im[236] = $signed(-16'sh1F1A); 527 | assign wn_im[237] = $signed(-16'sh1D93); 528 | assign wn_im[238] = $signed(-16'sh1C0C); 529 | assign wn_im[239] = $signed(-16'sh1A83); 530 | assign wn_im[240] = $signed(-16'sh18F9); 531 | assign wn_im[241] = $signed(-16'sh176E); 532 | assign wn_im[242] = $signed(-16'sh15E2); 533 | assign wn_im[243] = $signed(-16'sh1455); 534 | assign wn_im[244] = $signed(-16'sh12C8); 535 | assign wn_im[245] = $signed(-16'sh113A); 536 | assign wn_im[246] = $signed(-16'sh0FAB); 537 | assign wn_im[247] = $signed(-16'sh0E1C); 538 | assign wn_im[248] = $signed(-16'sh0C8C); 539 | assign wn_im[249] = $signed(-16'sh0AFB); 540 | assign wn_im[250] = $signed(-16'sh096B); 541 | assign wn_im[251] = $signed(-16'sh07D9); 542 | assign wn_im[252] = $signed(-16'sh0648); 543 | assign wn_im[253] = $signed(-16'sh04B6); 544 | assign wn_im[254] = $signed(-16'sh0324); 545 | assign wn_im[255] = $signed(-16'sh0192); 546 | 547 | assign data0_re = wn_re[addr0]; 548 | assign data0_im = wn_im[addr0]; 549 | assign data1_re = wn_re[addr1]; 550 | assign data1_im = wn_im[addr1]; 551 | assign data2_re = wn_re[addr2]; 552 | assign data2_im = wn_im[addr2]; 553 | assign data3_re = wn_re[addr3]; 554 | assign data3_im = wn_im[addr3]; 555 | assign data4_re = wn_re[addr4]; 556 | assign data4_im = wn_im[addr4]; 557 | assign data5_re = wn_re[addr5]; 558 | assign data5_im = wn_im[addr5]; 559 | assign data6_re = wn_re[addr6]; 560 | assign data6_im = wn_im[addr6]; 561 | assign data7_re = wn_re[addr7]; 562 | assign data7_im = wn_im[addr7]; 563 | 564 | endmodule 565 | -------------------------------------------------------------------------------- /scripts/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Use to backup the whole project 3 | ## 4 | ## By brimonzzy 5 | ## Email: zzzy218@foxmail.com 6 | ## 7 | 8 | cd .. 9 | 10 | mkdir -p backup 11 | 12 | cur_date=$(date +%Y-%m-%d-%H-%M) 13 | echo $cur_date 14 | prj_folder=$(basename "$PWD") 15 | 16 | ## check pigz command 17 | if command -v pigz > /dev/null 2>&1; then 18 | echo "$(pigz -V)" 19 | else 20 | echo "*** 'pigz' no found, please install 'pigz' ***" 21 | exit 1 22 | fi 23 | 24 | cd .. 25 | 26 | tar -cvf - --exclude=backup --exclude=*.fsdb --exclude=*.tar.gz $prj_folder | pigz --best -k > ${prj_folder}-${cur_date}.tar.gz 27 | mv ${prj_folder}-${cur_date}.tar.gz $prj_folder/backup 28 | -------------------------------------------------------------------------------- /scripts/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## clean temp files in project 3 | ## 4 | ## By brimonzzy 5 | ## Email: zzzy218@foxmail.com 6 | ## 7 | 8 | cd .. 9 | prj_path=$(pwd) 10 | echo "project path: $prj_path" 11 | 12 | read -p "是否执行该操作?(y/n): " choice 13 | # 判断用户输入 14 | case "$choice" in 15 | y|Y ) 16 | ;; 17 | n|N ) 18 | exit 1 19 | ;; 20 | * ) 21 | echo "无效的输入,请输入 'y' 或 'n'。" 22 | exit 1 23 | ;; 24 | esac 25 | 26 | rm -rf $prj_path/sim/vcs/generated-src 27 | rm -rf $prj_path/sim/vcs/output 28 | rm -rf $prj_path/sim/vcs/verdi_config_file 29 | 30 | rm -rf $prj_path/syn/syn_asic/output 31 | rm -rf $prj_path/syn/syn_asic/syn 32 | -------------------------------------------------------------------------------- /software/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/software/README.md -------------------------------------------------------------------------------- /software/bit_reverse.m: -------------------------------------------------------------------------------- 1 | function x_reversed = bit_reverse(x, n_bits) 2 | % Bit-reverse the input vector 3 | % x: input vector 4 | % n_bits: number of bits (log2(N)) 5 | % Example: 6 | % x=[0 1 2 3 4 5 6 7] 7 | % n_bits=3 8 | % x_reversed=[0 4 2 6 1 5 3 7] 9 | 10 | N = length(x); 11 | reversed_indices = zeros(1, N); 12 | 13 | for i = 0:N-1 14 | reversed = 0; 15 | for bit_pos = 1:n_bits 16 | reversed = bitshift(reversed, 1); 17 | reversed = reversed + bitget(i, bit_pos); 18 | end 19 | reversed_indices(i + 1) = reversed; 20 | end 21 | 22 | x_reversed = x(reversed_indices + 1); % 转换为Matlab的1-based索引 23 | 24 | end 25 | -------------------------------------------------------------------------------- /software/fft_fixed.m: -------------------------------------------------------------------------------- 1 | function [X_re, X_im] = fft_fixed(x_re, x_im, N) 2 | % N-point fixed FFT 3 | % Input: 4 | % x_re: real part of input signal (int16) 5 | % x_im: image part of input signal (int16) 6 | % Output: 7 | % X_re: real part of FFT result 8 | % X_im: image part of FFT result 9 | 10 | real = x_re; 11 | imag = x_im; 12 | 13 | % 生成旋转因子 14 | rotation_factors = cell(log2(N), 1); 15 | for stage = 1:log2(N) 16 | m = 2^(log2(N) - stage + 1); 17 | factors = int16(zeros(m/2, 2)); 18 | for k = 0:(m/2 - 1) 19 | theta = 2 * pi * k / m; 20 | W_real = cos(theta); 21 | W_imag = -sin(theta); 22 | factors(k+1, 1) = int16(round(W_real * 2^15)); 23 | factors(k+1, 2) = int16(round(W_imag * 2^15)); 24 | end 25 | rotation_factors{stage} = factors; 26 | end 27 | % W=rotation_factors{1} 28 | 29 | for stage = 1:log2(N) 30 | m = 2^(log2(N) - stage + 1); 31 | half_m = m / 2; 32 | factors = rotation_factors{stage}; 33 | for k = 0:(N/m - 1) 34 | for j = 0:(half_m - 1) 35 | idx1 = k * m + j + 1; 36 | idx2 = idx1 + half_m; 37 | 38 | % 提取 x(idx1) 和 x(idx2) 39 | a_re = real(idx1); 40 | a_im = imag(idx1); 41 | b_re = real(idx2); 42 | b_im = imag(idx2); 43 | 44 | % 蝶形运算 45 | temp_re = int16(a_re - b_re); 46 | temp_im = int16(a_im - b_im); 47 | real(idx1) = int16(a_re + b_re); 48 | imag(idx1) = int16(a_im + b_im); 49 | 50 | % 获取旋转因子 51 | W_real = factors(j+1, 1); 52 | W_imag = factors(j+1, 2); 53 | 54 | t_re = int32(temp_re) * int32(W_real) - int32(temp_im) * int32(W_imag); 55 | t_im = int32(temp_re) * int32(W_imag) + int32(temp_im) * int32(W_real); 56 | 57 | % 右移15位并四舍五入 58 | % 逐级处理蝶形运算,每次乘法后右移15位进行四舍五入,加减法后右移1位防止溢出。 59 | t_re = int16(bitshift(t_re + 16384, -15)); 60 | t_im = int16(bitshift(t_im + 16384, -15)); 61 | 62 | real(idx2) = t_re; 63 | imag(idx2) = t_im; 64 | end 65 | end 66 | 67 | fprintf('Stage%d re0 output:\n', stage); 68 | for ii = 1:N/2 69 | hex_value = dec2hex(typecast(abs(real(ii)), 'uint16'), 4); 70 | fprintf('%s\n', hex_value); 71 | end 72 | fprintf('\n'); 73 | fprintf('Stage%d re1 output:\n', stage); 74 | for ii = 1:N/2 75 | hex_value = dec2hex(typecast(abs(real(ii+half_m)), 'uint16'), 4); 76 | fprintf('%s\n', hex_value); 77 | end 78 | fprintf('\n\n\n\n'); 79 | 80 | end 81 | 82 | X_re = bit_reverse(real, log2(N)); 83 | X_im = bit_reverse(imag, log2(N)); 84 | 85 | end 86 | -------------------------------------------------------------------------------- /software/fft_fixed_run.m: -------------------------------------------------------------------------------- 1 | clc;clear; 2 | 3 | % 设置FFT点数 4 | N = 512; 5 | 6 | % 处理输入数据 7 | t = 0:N-1; 8 | % x_re = 0.0001*flip(1:N); 9 | % x_im = 0.0001*flip(1:N); 10 | x_re = 0.005*sin(t); 11 | x_im = 0.005*sin(t); 12 | 13 | % 输入定点化 14 | % x_re_fixed = int16(x_re); 15 | % x_im_fixed = int16(x_im); 16 | x_re_fixed=int16(round(x_re * 2^15)); % Q15 17 | x_im_fixed=int16(round(x_im * 2^15)); 18 | 19 | x_fixed = complex(x_re_fixed, x_im_fixed); 20 | 21 | 22 | % 计算FFT 23 | [X_re,X_im] = fft_fixed(x_re_fixed, x_im_fixed, N); 24 | X_matlab = fft(x_fixed, N); 25 | 26 | X_matlab_fixed_re = int16(real(X_matlab)); 27 | X_matlab_fixed_im = int16(imag(X_matlab)); 28 | 29 | fprintf('Output:\n'); 30 | for ii = 1:N 31 | hex_value = dec2hex(typecast(abs(X_re(ii)), 'uint16'), 4); 32 | fprintf('%d:%s\n', ii-1, hex_value); 33 | end 34 | 35 | % 比较结果 36 | subplot(2,2,1); 37 | plot(abs(X_re)); 38 | title('My FFT re'); 39 | subplot(2,2,2); 40 | plot(abs(X_matlab_fixed_re)); 41 | title('Matlab FFT re'); 42 | subplot(2,2,3); 43 | plot(abs(X_im)); 44 | title('My FFT im'); 45 | subplot(2,2,4); 46 | plot(abs(X_matlab_fixed_im)); 47 | title('Matlab FFT im'); 48 | 49 | % 计算最大误差 50 | max_error = max(abs(X_re - X_matlab_fixed_re)); 51 | fprintf('实部最大误差: %e\n', max_error); 52 | max_error = max(abs(X_im - X_matlab_fixed_im)); 53 | fprintf('虚部最大误差: %e\n', max_error); 54 | -------------------------------------------------------------------------------- /software/fft_float.m: -------------------------------------------------------------------------------- 1 | function X = fft_float(x, N) 2 | % N-point FFT implementation using floating-point model 3 | % Input: 4 | % x: input signal (N points) 5 | % Output: 6 | % X: FFT result 7 | 8 | % Bit-reverse the input 9 | x = bit_reverse(x, log2(N)); 10 | 11 | % Process each stage (log2N stages) 12 | for stage = 0:(log2(N)-1) 13 | num_blocks = N / (2^(stage + 1)); % 每一级有多少组 14 | butterflies_per_block = 2^stage; % 每一组有多少个 15 | step = 2^stage; 16 | 17 | % Calculate twiddle factors for this stage 18 | k = 0 : butterflies_per_block - 1; 19 | W = exp(-1j * 2 * pi * k / (2^(stage + 1))); 20 | 21 | for block = 0 : num_blocks - 1 22 | base = block * 2^(stage + 1); 23 | 24 | for b = 0 : butterflies_per_block - 1 25 | idx1 = base + b + 1; % Matlab索引从1开始 26 | idx2 = idx1 + step; 27 | 28 | % 获取旋转因子 29 | w = W(b + 1); 30 | 31 | % 蝶形运算 32 | a = x(idx1); 33 | b_val = x(idx2) * w; 34 | 35 | x(idx1) = a + b_val; 36 | x(idx2) = a - b_val; 37 | end 38 | end 39 | end 40 | 41 | X = x; 42 | 43 | end 44 | -------------------------------------------------------------------------------- /software/fft_run.m: -------------------------------------------------------------------------------- 1 | clc;clear; 2 | 3 | % FFT点数 4 | N = 64; 5 | 6 | t = 0:N-1; 7 | f = 10; 8 | % x_re = cos(2*pi*f*t/N); 9 | % x_im = sin(2*pi*f*t/N); 10 | % x_re = flip(1:N); 11 | % x_im = flip(1:N); 12 | x_re = cos(1/3*pi*t); 13 | x_im = zeros(1,N); 14 | x = complex(x_re, x_im); 15 | 16 | % 计算FFT 17 | X_my = fft_float(x, N); 18 | X_matlab = fft(x, N); 19 | 20 | % 比较结果 21 | subplot(2,1,1); 22 | plot(abs(X_my)); 23 | title('My FFT'); 24 | subplot(2,1,2); 25 | plot(abs(X_matlab)); 26 | title('Matlab FFT'); 27 | 28 | % 计算最大误差 29 | max_error = max(abs(X_my - X_matlab)); 30 | fprintf('最大误差: %e\n', max_error); 31 | -------------------------------------------------------------------------------- /software/ifft_fixed.m: -------------------------------------------------------------------------------- 1 | function [X_re, X_im] = ifft_fixed(x_re, x_im, N) 2 | % N-point fixed FFT 3 | % Input: 4 | % x_re: real part of input signal (int16) 5 | % x_im: image part of input signal (int16) 6 | % Output: 7 | % X_re: real part of FFT result 8 | % X_im: image part of FFT result 9 | 10 | real = x_re; 11 | imag = x_im; 12 | 13 | % 生成旋转因子 14 | rotation_factors = cell(log2(N), 1); 15 | for stage = 1:log2(N) 16 | m = 2^(log2(N) - stage + 1); 17 | factors = int16(zeros(m/2, 2)); 18 | for k = 0:(m/2 - 1) 19 | theta = 2 * pi * k / m; 20 | W_real = cos(theta); 21 | W_imag = sin(theta); 22 | factors(k+1, 1) = int16(round(W_real * 2^15)); 23 | factors(k+1, 2) = int16(round(W_imag * 2^15)); 24 | end 25 | rotation_factors{stage} = factors; 26 | end 27 | W=rotation_factors{1} 28 | 29 | for stage = 1:log2(N) 30 | m = 2^(log2(N) - stage + 1); 31 | half_m = m / 2; 32 | factors = rotation_factors{stage}; 33 | for k = 0:(N/m - 1) 34 | for j = 0:(half_m - 1) 35 | idx1 = k * m + j + 1; 36 | idx2 = idx1 + half_m; 37 | 38 | % 提取 x(idx1) 和 x(idx2) 39 | a_re = real(idx1); 40 | a_im = imag(idx1); 41 | b_re = real(idx2); 42 | b_im = imag(idx2); 43 | 44 | % 蝶形运算 45 | temp_re = int16(a_re - b_re); 46 | temp_im = int16(a_im - b_im); 47 | real(idx1) = int16(a_re + b_re); 48 | imag(idx1) = int16(a_im + b_im); 49 | 50 | % 获取旋转因子 51 | W_real = factors(j+1, 1); 52 | W_imag = factors(j+1, 2); 53 | 54 | t_re = int32(temp_re) * int32(W_real) - int32(temp_im) * int32(W_imag); 55 | t_im = int32(temp_re) * int32(W_imag) + int32(temp_im) * int32(W_real); 56 | 57 | % 右移15位并四舍五入 58 | % 逐级处理蝶形运算,每次乘法后右移15位进行四舍五入,加减法后右移1位防止溢出。 59 | t_re = int16(bitshift(t_re + 16384, -15)); 60 | t_im = int16(bitshift(t_im + 16384, -15)); 61 | 62 | real(idx2) = t_re; 63 | imag(idx2) = t_im; 64 | end 65 | end 66 | 67 | fprintf('Stage%d re0 output:\n', stage); 68 | for ii = 1:N/2 69 | hex_value = dec2hex(typecast(abs(real(ii)), 'uint16'), 4); 70 | fprintf('%s\n', hex_value); 71 | end 72 | fprintf('\n'); 73 | fprintf('Stage%d re1 output:\n', stage); 74 | for ii = 1:N/2 75 | hex_value = dec2hex(typecast(abs(real(ii+half_m)), 'uint16'), 4); 76 | fprintf('%s\n', hex_value); 77 | end 78 | fprintf('\n\n\n\n'); 79 | 80 | end 81 | 82 | X_re = bit_reverse(real, log2(N)); 83 | X_im = bit_reverse(imag, log2(N)); 84 | 85 | shift = log2(N); 86 | for i = 1:N 87 | X_re(i) = int16(bitshift(X_re(i), -shift)); 88 | X_im(i) = int16(bitshift(X_im(i), -shift)); 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /software/ifft_fixed_run.m: -------------------------------------------------------------------------------- 1 | clc;clear; 2 | 3 | % 设置FFT点数 4 | N = 256; 5 | 6 | % 处理原输入数据 7 | t = 0:N-1; 8 | x_re = 0.00003*flip(1:N); 9 | x_im = 0.00003*flip(1:N); 10 | 11 | % 原输入定点化 12 | x_re_fixed=int16(round(x_re * 2^15)); % Q15 13 | x_im_fixed=int16(round(x_im * 2^15)); 14 | x_fixed = complex(x_re_fixed, x_im_fixed); 15 | 16 | % 计算FFT 17 | X_matlab = fft(x_fixed, N); 18 | X_matlab_fixed_re = int16(real(X_matlab)); 19 | X_matlab_fixed_im = int16(imag(X_matlab)); 20 | X_matlab_fixed = complex(X_matlab_fixed_re, X_matlab_fixed_im); 21 | 22 | % 计算IFFT 23 | X_matlab_ifft = ifft(X_matlab_fixed, N); 24 | [X_ifft_re, X_ifft_im] = ifft_fixed(X_matlab_fixed_re, X_matlab_fixed_im, N); 25 | 26 | X_matlab_ifft_fixed_re = int16(real(X_matlab_ifft)); 27 | X_matlab_ifft_fixed_im = int16(imag(X_matlab_ifft)); 28 | 29 | 30 | % fprintf('Output:\n'); 31 | % for ii = 1:N 32 | % hex_value = dec2hex(typecast(abs(X_re(ii)), 'uint16'), 4); 33 | % fprintf('%d:%s\n', ii-1, hex_value); 34 | % end 35 | 36 | % 比较结果 37 | subplot(2,2,1); 38 | plot(abs(X_ifft_re)); 39 | title('My IFFT re'); 40 | subplot(2,2,2); 41 | plot(abs(X_matlab_ifft_fixed_re)); 42 | title('Matlab IFFT re'); 43 | subplot(2,2,3); 44 | plot(abs(X_ifft_im)); 45 | title('My IFFT im'); 46 | subplot(2,2,4); 47 | plot(abs(X_matlab_ifft_fixed_im)); 48 | title('Matlab IFFT im'); 49 | 50 | % 计算最大误差 51 | max_error = max(abs(X_ifft_re - X_matlab_ifft_fixed_re)); 52 | fprintf('实部最大误差: %e\n', max_error); 53 | max_error = max(abs(X_ifft_im - X_matlab_ifft_fixed_im)); 54 | fprintf('虚部最大误差: %e\n', max_error); 55 | -------------------------------------------------------------------------------- /software/ifft_input_gen.m: -------------------------------------------------------------------------------- 1 | function ifft_input_gen(N) 2 | % 生成激励的verilog代码 3 | 4 | % 处理原输入数据 5 | x_re = 0.00003*flip(1:N); 6 | x_im = 0.00003*flip(1:N); 7 | 8 | % 原输入定点化 9 | x_re_fixed=int16(round(x_re * 2^15)); % Q15 10 | x_im_fixed=int16(round(x_im * 2^15)); 11 | x_fixed = complex(x_re_fixed, x_im_fixed); 12 | 13 | % 计算FFT 14 | X_matlab = fft(x_fixed, N); 15 | X_re = int16(real(X_matlab)); 16 | X_im = int16(imag(X_matlab)); 17 | 18 | for ii = 1:N 19 | hex_value = dec2hex(typecast(X_re(ii), 'uint16'), 4); 20 | fprintf('%s\n', hex_value); 21 | end 22 | fprintf("\n\n\n"); 23 | for ii = 1:N 24 | hex_value = dec2hex(typecast(X_im(ii), 'uint16'), 4); 25 | fprintf('%s\n', hex_value); 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /software/input_gen.m: -------------------------------------------------------------------------------- 1 | function input_gen(N) 2 | % 生成激励的verilog代码 3 | 4 | n=0:N-1; 5 | 6 | % 输入激励 7 | in_re = 0.005*sin(n); 8 | in_im = 0.005*sin(n); 9 | % 定点化输入激励 10 | x_re=int16(round(in_re * 2^15)); % Q15 11 | x_im=int16(round(in_im * 2^15)); 12 | 13 | fprintf('reg [15:0] x_re;\n'); 14 | fprintf('reg [15:0] x_re;\n\n'); 15 | 16 | for ii = 1:N 17 | hex_value = dec2hex(typecast(x_re(ii), 'uint16'), 4); 18 | fprintf('%s\n', hex_value); 19 | end 20 | fprintf("\n\n\n"); 21 | for ii = 1:N 22 | hex_value = dec2hex(typecast(x_im(ii), 'uint16'), 4); 23 | fprintf('%s\n', hex_value); 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /software/wave.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | def read_hex_data_from_file(file_name): 4 | with open(file_name, 'r') as file: 5 | data = file.read().split() 6 | return [int(value, 16) for value in data] 7 | 8 | def plot_re_im(re_data, im_data): 9 | print(len(re_data)) 10 | plt.figure(figsize=(12, 5)) 11 | 12 | plt.subplot(1, 2, 1) 13 | # plt.plot(range(len(re_data)), re_data, marker='o', color='blue', linestyle='-', label='Real Part') 14 | plt.plot(range(len(re_data)), re_data, color='blue', linestyle='-', label='Real Part') 15 | plt.xlabel('Index') 16 | plt.ylabel('Real') 17 | plt.title('FFT Real output') 18 | plt.grid(True) 19 | plt.legend() 20 | 21 | plt.subplot(1, 2, 2) 22 | # plt.plot(range(len(im_data)), im_data, marker='o', color='red', linestyle='-', label='Imaginary Part') 23 | plt.plot(range(len(im_data)), im_data, color='red', linestyle='-', label='Imaginary Part') 24 | plt.xlabel('Index') 25 | plt.ylabel('Imag') 26 | plt.title('FFT Imag output') 27 | plt.grid(True) 28 | plt.legend() 29 | 30 | plt.tight_layout() 31 | plt.show() 32 | 33 | re_data = read_hex_data_from_file('../rtl/sim/test_vector/fft_output_re.txt') 34 | im_data = read_hex_data_from_file('../rtl/sim/test_vector/fft_output_im.txt') 35 | 36 | 37 | plot_re_im(re_data, im_data) 38 | -------------------------------------------------------------------------------- /software/wn_gen.m: -------------------------------------------------------------------------------- 1 | function wn_gen(N, IFFT) 2 | % 生成N点FFT的旋转因子ROM的verilog代码 3 | 4 | if IFFT 5 | n=0:(N/2-1); 6 | w_re=cos(2*pi*n/N); 7 | wn_re=int16(round(w_re * 2^15)); 8 | w_im=sin(2*pi*n/N); 9 | wn_im=int16(round(w_im * 2^15)); 10 | else 11 | n=0:(N/2-1); 12 | w_re=cos(2*pi*n/N); 13 | wn_re=int16(round(w_re * 2^15)); 14 | w_im=-sin(2*pi*n/N); 15 | wn_im=int16(round(w_im * 2^15)); 16 | end 17 | 18 | % 打印实部赋值 19 | for ii = 1:(N/2) 20 | if wn_re(ii) >= 0 21 | hex_value = dec2hex(typecast(wn_re(ii), 'uint16'), 4); 22 | fprintf('assign wn_re[%d] = $signed(16''sh%s);\n', ii-1, hex_value); 23 | else 24 | hex_value = dec2hex(typecast(abs(wn_re(ii)), 'uint16'), 4); 25 | fprintf('assign wn_re[%d] = $signed(-16''sh%s);\n', ii-1, hex_value); 26 | end 27 | end 28 | 29 | % 打印虚部赋值 30 | for ii = 1:(N/2) 31 | if wn_im(ii) >= 0 32 | hex_value = dec2hex(typecast(wn_im(ii), 'uint16'), 4); 33 | fprintf('assign wn_im[%d] = $signed(16''sh%s);\n', ii-1, hex_value); 34 | else 35 | hex_value = dec2hex(typecast(abs(wn_im(ii)), 'uint16'), 4); 36 | fprintf('assign wn_im[%d] = $signed(-16''sh%s);\n', ii-1, hex_value); 37 | end 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /syn/syn_asic/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !.gitignore 4 | !Makefile 5 | !*.md 6 | !/scripts/* 7 | 8 | -------------------------------------------------------------------------------- /syn/syn_asic/Makefile: -------------------------------------------------------------------------------- 1 | ## by BriMon 2 | ## Email: zzybr@qq.com 3 | ## DC synthesis flow 4 | ## 5 | ## make syn MODEL_NAME= CLK= RST= 6 | ## make clean 7 | ## 8 | 9 | ## parameter 10 | MODEL_NAME?=fft_multimode 11 | CLK?=clk 12 | RST?=rst_n 13 | 14 | 15 | DC:=dc_shell 16 | 17 | base_dir:=$(abspath .) 18 | db_dir:=$(base_dir)/db 19 | output_dir:=$(base_dir)/output 20 | syn_reslut_dir:=$(base_dir)/syn 21 | script_dir:=$(base_dir)/scripts 22 | rtl_src_dir:=$(base_dir)/../../rtl/src 23 | 24 | syn_files ?= $(syn_reslut_dir)/syn_files.f 25 | 26 | help: 27 | @echo " - make syn MODEL_NAME= RST= CLK=" 28 | @echo " - make clean" 29 | 30 | 31 | .PHONY: syn clean 32 | 33 | syn: $(syn_files) update_synflow 34 | cd output && $(DC) -f $(script_dir)/synflow.tcl -output_log_file ./syn/log/syn.log 35 | 36 | update_synflow: 37 | sed -i 's/^set TOP_DESIGN .*/set TOP_DESIGN $(MODEL_NAME)/' $(script_dir)/synflow.tcl 38 | sed -i 's/^set RST_NAME .*/set RST_NAME $(RST)/' $(script_dir)/sdc.tcl 39 | sed -i 's/^set CLK_NAME .*/set CLK_NAME $(CLK)/' $(script_dir)/sdc.tcl 40 | 41 | $(output_dir): 42 | mkdir -p $@ 43 | 44 | $(syn_reslut_dir): 45 | mkdir -p $@ && mkdir -p $(syn_reslut_dir)/mapped $(syn_reslut_dir)/report $(syn_reslut_dir)/unmapped $(syn_reslut_dir)/log 46 | 47 | $(syn_files): | $(syn_reslut_dir) $(output_dir) 48 | touch $@ && find $(rtl_src_dir) -name "*.v" -o -name "*.h" -o -name "*.vh" -o -name "*.svh" >> $@ 49 | 50 | clean: 51 | rm -rf output syn 52 | -------------------------------------------------------------------------------- /syn/syn_asic/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/syn/syn_asic/README.md -------------------------------------------------------------------------------- /syn/syn_asic/scripts/.synopsys_dc.setup: -------------------------------------------------------------------------------- 1 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 | # Library Setup 3 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4 | 5 | #set search_path "$search_path ./db/tsmc90" 6 | #set target_library "typical.db" 7 | #set link_library "* typical.db" 8 | #set symbol_library "tsmc090.sdb" 9 | 10 | #echo "\n\nSettings:" 11 | #echo "search_path: $search_path" 12 | #echo "link_library: $link_library" 13 | #echo "target_library: $target_library" 14 | #echo "symbol_library: $symbol_library" 15 | 16 | 17 | #define_design_lib DEFAULT -path ./analyzed 18 | 19 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 | # History 21 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 22 | 23 | history keep 200 24 | 25 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 26 | # Aliases 27 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 28 | 29 | alias h history 30 | alias rc "report_constraint -all_violators" 31 | alias rt report_timing 32 | alias ra report_area 33 | alias page_on {set sh_enable_page_mode true} 34 | alias page_off {set sh_enable_page_mode false} 35 | alias fr "remove_design -designs" 36 | 37 | echo "\n\nI am ready...\n" 38 | -------------------------------------------------------------------------------- /syn/syn_asic/scripts/main.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | script1_file_dir = "/home/yian/workspace/seq_detector/syn/syn_asic/scripts/synflow.tcl" 5 | script2_file_dir = "/home/yian/workspace/seq_detector/syn/syn_asic/scripts/sdc.tcl" 6 | design_file_dir = "/home/yian/workspace/seq_detector/rtl/src" 7 | 8 | def CopyScript(): 9 | os.system('cp {} ../syn/script/'.format(script1_file_dir)) 10 | os.system('cp {} ../syn/script/'.format(script2_file_dir)) 11 | 12 | 13 | def create_SynFlow(design): 14 | text = """ 15 | #--------------------------Specify Libraries-------------------------- 16 | set search_path "$search_path /home/yian/workspace/seq_detector/syn/syn_asic/db/tsmc90" 17 | set target_library "fast.db" 18 | set link_library "* fast.db" 19 | set symbol_library "tsmc090.sdb" 20 | 21 | echo "\n\nSettings:" 22 | echo "search_path: $search_path" 23 | echo "link_library: $link_library" 24 | echo "target_library: $target_library" 25 | echo "\n\nI'm Ready!" 26 | #--------------------------Prepare Filelist--------------------------- 27 | set FILE_LIST "" 28 | set f [open "../scripts/files_syn.fl" r] 29 | while {![eof $f]} { 30 | gets $f line 31 | append FILE_LIST "$line " 32 | } 33 | echo $FILE_LIST 34 | close $f 35 | 36 | #--------------------------Read Designs------------------------------ 37 | 38 | # Reset all constraints 39 | # reset_design 40 | 41 | set TOP_DESIGN seq_detector 42 | analyze -format verilog $FILE_LIST 43 | elaborate $TOP_DESIGN 44 | 45 | #------------------------Set Current Design&&Link Designs-------------------------- 46 | #current_design $TOP_DESIGN(auto) 47 | #link(auto) 48 | 49 | #-------------------------------SDC---------------------------------- 50 | source ../syn/script/sdc.tcl 51 | 52 | #--------------------Map and Optimize the Design--------------------- 53 | compile_ultra -no_autoungroup -incremental -no_boundary_optimization 54 | #----------------------Save Design Database-------------------------- 55 | change_names -rules verilog -hierarchy 56 | set_fix_multiple_port_nets -all -buffer_constants 57 | #---------------Check the Synthesized Design for Consistency--------- 58 | check_design -summary > ../syn/report/check_design.rpt 59 | check_timing > ../syn/report/check_timing.rpt 60 | #---------------------Report Timing and Area------------------------- 61 | report_qor > ../syn/report/$TOP_DESIGN.qor_rpt 62 | report_timing -max_paths 1000 > ../syn/report/$TOP_DESIGN.timing_rpt 63 | report_timing -path full > ../syn/report/$TOP_DESIGN.full_timing_rpt 64 | report_timing -delay max > ../syn/report/$TOP_DESIGN.setup_timing_rpt 65 | report_timing -delay min > ../syn/report/$TOP_DESIGN.hold_timing_rpt 66 | report_reference > ../syn/report/$TOP_DESIGN.ref_rpt 67 | report_area > ../syn/report/$TOP_DESIGN.area_rpt 68 | report_constraints > ../syn/report/$TOP_DESIGN.const_rpt 69 | report_constraint -all_violators > ../syn/report/$TOP_DESIGN.violators_rpt 70 | report_power > ../syn/report/$TOP_DESIGN.power_rpt 71 | check_timing > ../syn/log/last_check_timing.log 72 | #---------------------Generate Files ------------------------- 73 | write -f verilog -hierarchy -output ../syn/mapped/$TOP_DESIGN.v 74 | write_sdc ../syn/mapped/$TOP_DESIGN.sdc 75 | write_sdf -context verilog ../syn/mapped/$TOP_DESIGN.sdf 76 | 77 | """ 78 | return text 79 | 80 | 81 | def create_Sdc(design): 82 | text = """ 83 | #==================================Env Vars=================================== 84 | set RST_NAME rst_n 85 | set CLK_NAME clk 86 | 87 | set CLK_PERIOD_I 7 88 | set CLK_PERIOD [expr $CLK_PERIOD_I*0.95] 89 | set CLK_SKEW [expr $CLK_PERIOD*0.01] 90 | set CLK_SOURCE_LATENCY [expr $CLK_PERIOD*0.1] 91 | set CLK_NETWORK_LATENCY [expr $CLK_PERIOD*0.1] 92 | set CLK_TRAN [expr $CLK_PERIOD*0.01] 93 | 94 | set INPUT_DELAY_MAX [expr $CLK_PERIOD*0.4] 95 | set INPUT_DELAY_MIN 0 96 | set OUTPUT_DELAY_MAX [expr $CLK_PERIOD*0.4] 97 | set OUTPUT_DELAY_MIN 0 98 | 99 | set MAX_FANOUT 6 100 | set MAX_TRAN 5 101 | set MAX_CAP 1.5 102 | 103 | set ALL_INPUT_EX_CLK [remove_from_collection [all_inputs] [get_ports $CLK_NAME]] 104 | #==================================Define Design Environment========================= 105 | #GUIDANCE: use the default 106 | set_max_area 0 107 | #set_max_transition $MAX_TRAN [current_design] 108 | #set_max_fanout $MAX_FANOUT [current_design] 109 | #set_max_capacitance $MAX_CAP [current_design] 110 | 111 | #============================= Set Design Constraints========================= 112 | #--------------------------------Clock and Reset Definition---------------------------- 113 | set_drive 0 [get_ports $CLK_NAME] 114 | create_clock -name $CLK_NAME -period $CLK_PERIOD [get_ports $CLK_NAME] 115 | set_dont_touch_network [get_ports $CLK_NAME] 116 | 117 | set_clock_uncertainty $CLK_SKEW [get_clocks $CLK_NAME] 118 | set_clock_transition $CLK_TRAN [all_clocks] 119 | set_clock_latency -source $CLK_SOURCE_LATENCY [get_clocks $CLK_NAME] 120 | set_clock_latency -max $CLK_NETWORK_LATENCY [get_clocks $CLK_NAME] 121 | #rst_ports 122 | set_drive 0 [get_ports $RST_NAME] 123 | set_dont_touch_network [get_ports $RST_NAME] 124 | set_false_path -from [get_ports $RST_NAME] 125 | set_ideal_network -no_propagate [get_ports $RST_NAME] 126 | set_ideal_network -no_propagate [get_ports $CLK_NAME] 127 | 128 | 129 | #--------------------------------I/O Constraint----------------------------- 130 | set_input_delay -max $INPUT_DELAY_MAX -clock $CLK_NAME $ALL_INPUT_EX_CLK 131 | set_input_delay -min $INPUT_DELAY_MIN -clock $CLK_NAME $ALL_INPUT_EX_CLK -add 132 | set_output_delay -max $OUTPUT_DELAY_MAX -clock $CLK_NAME [all_outputs] 133 | set_output_delay -min $OUTPUT_DELAY_MIN -clock $CLK_NAME [all_outputs] -add 134 | set_load 0.2 [all_outputs] 135 | 136 | """ 137 | return text 138 | 139 | 140 | def createFile(): 141 | prjname = "seq_detector" 142 | with open(f"../syn/script/synflow.tcl", "w") as f: 143 | synflow = create_SynFlow(prjname) 144 | f.write(synflow) 145 | 146 | with open(f"../syn/script/sdc.tcl", "w") as f: 147 | sdc = create_Sdc(prjname) 148 | f.write(sdc) 149 | 150 | 151 | if __name__ == "__main__": 152 | os.system('rm -rf ../syn ./files_syn.fl ../temp') 153 | os.system('mkdir -p ../syn/mapped ../syn/report ../syn/script ../syn/unmapped ../syn/log ../temp') 154 | createFile() 155 | os.system("find /home/yian/workspace/seq_detector/rtl/src/ -name \"*.v\" > files_syn.fl") 156 | # CopyScript() 157 | os.system("cp .synopsys_dc.setup ../temp") # copy dc setup file 158 | os.system('cd ../temp && dc_shell -f ../syn/script/synflow.tcl -output_log_file ../syn/log/syn.log') 159 | 160 | -------------------------------------------------------------------------------- /syn/syn_asic/scripts/sdc.tcl: -------------------------------------------------------------------------------- 1 | #==================================Env Vars=================================== 2 | set RST_NAME rst_n 3 | set CLK_NAME clk 4 | 5 | set CLK_PERIOD_I 1.5 6 | set CLK_PERIOD [expr $CLK_PERIOD_I*0.95] 7 | set CLK_SKEW [expr $CLK_PERIOD*0.005] 8 | set CLK_SOURCE_LATENCY [expr $CLK_PERIOD*0.01] 9 | set CLK_NETWORK_LATENCY [expr $CLK_PERIOD*0.005] 10 | set CLK_TRAN [expr $CLK_PERIOD*0.005] 11 | 12 | set INPUT_DELAY_MAX [expr $CLK_PERIOD*0.2] 13 | set INPUT_DELAY_MIN 0 14 | set OUTPUT_DELAY_MAX [expr $CLK_PERIOD*0.2] 15 | set OUTPUT_DELAY_MIN 0 16 | 17 | set MAX_FANOUT 6 18 | set MAX_TRAN 5 19 | set MAX_CAP 1.5 20 | 21 | set ALL_INPUT_EX_CLK [remove_from_collection [all_inputs] [get_ports $CLK_NAME]] 22 | 23 | #==================================Define Design Environment========================= 24 | set_max_area 0 25 | #set_max_transition $MAX_TRAN [current_design] 26 | #set_max_fanout $MAX_FANOUT [current_design] 27 | #set_max_capacitance $MAX_CAP [current_design] 28 | 29 | #============================= Set Design Constraints========================= 30 | #--------------------------------Clock and Reset Definition---------------------------- 31 | set_drive 0 [get_ports $CLK_NAME] 32 | create_clock -name $CLK_NAME -period $CLK_PERIOD [get_ports $CLK_NAME] 33 | set_dont_touch_network [get_ports $CLK_NAME] 34 | 35 | set_clock_uncertainty $CLK_SKEW [get_clocks $CLK_NAME] 36 | set_clock_transition $CLK_TRAN [all_clocks] 37 | set_clock_latency -source $CLK_SOURCE_LATENCY [get_clocks $CLK_NAME] 38 | set_clock_latency -max $CLK_NETWORK_LATENCY [get_clocks $CLK_NAME] 39 | #rst_ports 40 | set_drive 0 [get_ports $RST_NAME] 41 | set_dont_touch_network [get_ports $RST_NAME] 42 | set_false_path -from [get_ports $RST_NAME] 43 | 44 | set_ideal_network -no_propagate [get_ports $RST_NAME] 45 | set_ideal_network -no_propagate [get_ports $CLK_NAME] 46 | 47 | #--------------------------------I/O Constraint----------------------------- 48 | set_input_delay -max $INPUT_DELAY_MAX -clock $CLK_NAME $ALL_INPUT_EX_CLK 49 | set_input_delay -min $INPUT_DELAY_MIN -clock $CLK_NAME $ALL_INPUT_EX_CLK -add 50 | set_output_delay -max $OUTPUT_DELAY_MAX -clock $CLK_NAME [all_outputs] 51 | set_output_delay -min $OUTPUT_DELAY_MIN -clock $CLK_NAME [all_outputs] -add 52 | set_load 0.2 [all_outputs] 53 | -------------------------------------------------------------------------------- /syn/syn_asic/scripts/synflow.tcl: -------------------------------------------------------------------------------- 1 | #--------------------------Specify Libraries-------------------------- 2 | set search_path "$search_path\ 3 | /tools/PDK/tsmc28nm/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn28hpcplusbwp40p140_180a\ 4 | /tools/PDK/tsmc40nm/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn40lpbwp_200a\ 5 | /home/brimon/workspace/multi-mode-fft-processor/rtl/src/include" 6 | 7 | ## tsmc28 8 | set target_library "tcbn28hpcplusbwp40p140ffg0p88v0c.db\ 9 | /home/brimon/workspace/multi-mode-fft-processor/syn/syn_asic/sram/sramsp16x256_tsmc28hpc_ffg0p99v0c.db" 10 | set link_library "* tcbn28hpcplusbwp40p140ffg0p88v0c.db" 11 | 12 | ## tsmc40 13 | # set target_library "tcbn40lpbwpbc.db\ 14 | # " 15 | # set link_library "* tcbn40lpbwpbc.db" 16 | 17 | ## tsmc90 18 | # set target_library "fast.db" 19 | # set link_library "* fast.db" 20 | ## smic40 21 | # set target_library "scc40nll_hs_rvt_ff_v1p21_-40c_basic.db" 22 | # set link_library "* scc40nll_hs_rvt_ff_v1p21_-40c_basic.db" 23 | 24 | ## for DesignWare use 25 | # set synthetic_library "dw_foundation.sldb" 26 | # set link_library "* fast.db $synthetic_library" 27 | 28 | ## tsmc90 29 | # set symbol_library "tsmc090.sdb" 30 | ## smic40 31 | # set symbol_library "SCC40NLL_HS_RVT_V0p1.sdb" 32 | 33 | 34 | 35 | echo "\n\nSettings:" 36 | echo "search_path: $search_path" 37 | echo "link_library: $link_library" 38 | echo "target_library: $target_library" 39 | echo "\n\nI'm Ready!" 40 | #--------------------------Prepare Filelist--------------------------- 41 | set FILE_LIST "" 42 | set f [open "../syn/syn_files.f" r] 43 | while {![eof $f]} { 44 | gets $f line 45 | append FILE_LIST "$line " 46 | } 47 | echo $FILE_LIST 48 | close $f 49 | 50 | #--------------------------Read Designs------------------------------ 51 | 52 | # Reset all constraints 53 | # reset_design 54 | set TOP_DESIGN fft_multimode 55 | 56 | analyze -format verilog $FILE_LIST 57 | elaborate $TOP_DESIGN 58 | 59 | #------------------------Set Current Design&&Link Designs-------------------------- 60 | current_design $TOP_DESIGN 61 | link 62 | 63 | #-------------------------------SDC---------------------------------- 64 | source ../scripts/sdc.tcl 65 | 66 | #--------------------Map and Optimize the Design--------------------- 67 | compile_ultra -no_autoungroup -incremental -no_boundary_optimization 68 | # compile_ultra 69 | #----------------------Save Design Database-------------------------- 70 | change_names -rules verilog -hierarchy 71 | set_fix_multiple_port_nets -all -buffer_constants 72 | #---------------Check the Synthesized Design for Consistency--------- 73 | check_design -summary > ../syn/report/check_design.rpt 74 | check_timing > ../syn/report/check_timing.rpt 75 | #---------------------Report Timing and Area------------------------- 76 | report_qor > ../syn/report/qor_$TOP_DESIGN.rpt 77 | report_timing -max_paths 1000 > ../syn/report/timing_$TOP_DESIGN.rpt 78 | report_timing -path full > ../syn/report/full_timing_$TOP_DESIGN.rpt 79 | report_timing -delay max > ../syn/report/setup_timing_$TOP_DESIGN.rpt 80 | report_timing -delay min > ../syn/report/hold_timing_$TOP_DESIGN.rpt 81 | report_reference > ../syn/report/ref_$TOP_DESIGN.rpt 82 | report_area > ../syn/report/area_$TOP_DESIGN.rpt 83 | report_constraints > ../syn/report/const_$TOP_DESIGN.rpt 84 | report_constraint -all_violators > ../syn/report/violators_$TOP_DESIGN.rpt 85 | report_power > ../syn/report/power_$TOP_DESIGN.rpt 86 | check_timing > ../syn/log/last_check_timing.log 87 | 88 | #---------------------Generate Files ------------------------- 89 | write -f verilog -hierarchy -output ../syn/mapped/$TOP_DESIGN.v 90 | write_sdc ../syn/mapped/$TOP_DESIGN.sdc 91 | write_sdf -context verilog ../syn/mapped/$TOP_DESIGN.sdf 92 | write -hierarchy -format ddc -output ../syn/mapped/$TOP_DESIGN.ddc 93 | -------------------------------------------------------------------------------- /syn/syn_fpga/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !.gitignore 4 | !Makefile 5 | !*.md 6 | !*.tcl 7 | !*.setup 8 | !/quartus/* 9 | !/vivado/* 10 | -------------------------------------------------------------------------------- /syn/syn_fpga/quartus/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BriMonzZY/multi-mode-fft-processor/976bf9512f40cdac07363e99d41b312627e83921/syn/syn_fpga/quartus/Makefile -------------------------------------------------------------------------------- /syn/syn_fpga/vivado/Makefile: -------------------------------------------------------------------------------- 1 | ## by BriMon 2 | ## 3 | ## Vivado 4 | ## 5 | ## make synth 6 | ## make impl 7 | ## make all 8 | ## make elaborate 9 | ## 10 | 11 | 12 | MAX_CPU := $(shell nproc) 13 | VIVADO ?= vivado 14 | VIVADO_OPTS ?= -nolog -nojournal -mode batch 15 | 16 | 17 | FPGA_PART ?= xc7z020clg400-1 18 | MODEL_NAME ?= fft_multimode 19 | 20 | RTL ?= v......... 21 | CONSTRAINTS ?= xdc.......... 22 | 23 | 24 | base_dir := $(abspath .) 25 | SCRIPTS := $(base_dir)/scripts 26 | 27 | 28 | 29 | ## generate tcl file 30 | build/target.tcl: $(RTL) $(CONSTRAINTS) 31 | mkdir -p build 32 | truncate -s 0 $@ 33 | echo "set ABS_TOP $(ABS_TOP)" >> $@ 34 | echo "set TOP $(MODEL_NAME)" >> $@ 35 | echo "set FPGA_PART $(FPGA_PART)" >> $@ 36 | echo "set_param general.maxThreads $(MAX_CPU)" >> $@ 37 | echo "set_param general.maxBackupLogs 0" >> $@ 38 | echo -n "set RTL { " >> $@ 39 | FLIST="$(RTL)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 40 | echo "}" >> $@ 41 | echo -n "set CONSTRAINTS { " >> $@ 42 | FLIST="$(CONSTRAINTS)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 43 | echo "}" >> $@ 44 | 45 | 46 | setup: build/target.tcl 47 | 48 | elaborate: build/target.tcl $(SCRIPTS)/elaborate.tcl 49 | mkdir -p ./build 50 | cd ./build && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/elaborate.tcl |& tee elaborate.log 51 | 52 | build/synth/$(TOP).dcp: build/target.tcl $(SCRIPTS)/synth.tcl 53 | mkdir -p ./build/synth/ 54 | cd ./build/synth/ && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/synth.tcl |& tee synth.log 55 | 56 | synth: build/synth/$(TOP).dcp 57 | 58 | build/impl/$(TOP).bit: build/synth/$(TOP).dcp $(SCRIPTS)/impl.tcl 59 | mkdir -p ./build/impl/ 60 | cd ./build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/impl.tcl |& tee impl.log 61 | 62 | impl: build/impl/$(TOP).bit 63 | all: build/impl/$(TOP).bit 64 | 65 | vivado: build 66 | cd build && nohup $(VIVADO) /dev/null 2>&1 & 67 | 68 | sim_build/compile_simlib/synopsys_sim.setup: 69 | mkdir -p sim_build/compile_simlib 70 | cd build/sim_build/compile_simlib && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/compile_simlib.tcl 71 | 72 | -------------------------------------------------------------------------------- /syn/syn_fpga/vivado/scripts/elaborate.tcl: -------------------------------------------------------------------------------- 1 | source ./target.tcl 2 | 3 | # Read Verilog source files 4 | if {[string trim ${RTL}] ne ""} { 5 | read_verilog -v ${RTL} 6 | } 7 | 8 | # Read user constraints 9 | if {[string trim ${CONSTRAINTS}] ne ""} { 10 | read_xdc ${CONSTRAINTS} 11 | } 12 | 13 | # Only elaborate RTL (don't synthesize to netlist) 14 | synth_design -top ${TOP} -part ${FPGA_PART} -rtl 15 | 16 | # write_checkpoint doesn't work: 17 | # Vivado% write_checkpoint -force z1top_post_elab.dcp 18 | # ERROR: [Common 17-69] Command failed: Checkpoints are not supported for RTL designs 19 | 20 | # Open the schematic visualization 21 | start_gui 22 | -------------------------------------------------------------------------------- /syn/syn_fpga/vivado/scripts/impl.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | open_checkpoint ${ABS_TOP}/build/synth/${TOP}.dcp 4 | 5 | if {[string trim ${CONSTRAINTS}] ne ""} { 6 | read_xdc ${CONSTRAINTS} 7 | } 8 | 9 | opt_design 10 | place_design 11 | write_checkpoint -force ${TOP}_placed.dcp 12 | report_utilization -file post_place_utilization.rpt 13 | phys_opt_design 14 | route_design 15 | 16 | write_checkpoint -force ${TOP}_routed.dcp 17 | write_verilog -force post_route.v 18 | write_xdc -force post_route.xdc 19 | report_drc -file post_route_drc.rpt 20 | report_timing_summary -warn_on_violation -file post_route_timing_summary.rpt 21 | 22 | write_bitstream -force ${TOP}.bit 23 | -------------------------------------------------------------------------------- /syn/syn_fpga/vivado/scripts/synth.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | # Read Verilog source files 4 | if {[string trim ${RTL}] ne ""} { 5 | read_verilog -v ${RTL} 6 | } 7 | 8 | # Read user constraints 9 | if {[string trim ${CONSTRAINTS}] ne ""} { 10 | read_xdc ${CONSTRAINTS} 11 | } 12 | 13 | synth_design -top ${TOP} -part ${FPGA_PART} 14 | 15 | write_checkpoint -force ${TOP}.dcp 16 | report_timing_summary -file post_synth_timing_summary.rpt 17 | report_drc -file post_synth_drc.rpt 18 | report_utilization -file post_synth_utilization.rpt 19 | write_verilog -force -file post_synth.v 20 | write_xdc -force -file post_synth.xdc 21 | --------------------------------------------------------------------------------