├── .gitignore ├── LICENSE ├── README.md ├── README_zh.md ├── chnn_rcvr ├── create_project.tcl ├── draw.odg ├── hdl │ ├── axi_cmult.v │ ├── chnn_rcvr.v │ └── exp_mult.v ├── readme_zh.md ├── script │ ├── channelizer.py │ ├── fir_coe_gen.py │ ├── rotate_factor_gen.py │ ├── sig_gen.py │ └── sim_chnn_rcvr.py └── sim │ └── sim_chnn_rcvr.v ├── common ├── cmult.v ├── pipe_delay.v └── rom.v ├── fir ├── create_project.tcl ├── data_gen.py ├── fir.v ├── fir_coe_gen.py ├── image │ ├── df_fir.PNG │ └── fir_1.PNG ├── multadd.v ├── readme_zh.md ├── sim_fir.py └── sim_fir.v └── pfft ├── butterfly.v ├── butterfly_block.v ├── create_project.tcl ├── pfft.v ├── readme.md ├── readme_zh.md ├── sim_butterfly.v ├── sim_data_gen.py ├── sim_pfft.py └── sim_pfft.v /.gitignore: -------------------------------------------------------------------------------- 1 | proj 2 | /pfft/pfft 3 | /chnn_rcvr/ip 4 | *.dat 5 | *.coe 6 | *.cache 7 | *.hw 8 | *.ip_user_files 9 | *.sim 10 | *.runs 11 | *.xpr 12 | __pycache__ 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 falwat 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 | # My Module Repositry 2 | 3 | [Click here for readme in Chinese...](./README_zh.md) 4 | 5 | ## FIR Filter Module 6 | 7 | This design implements a single-rate finite impulse response (FIR) filter module. 8 | 9 | > For more details, please read [fir readme](./fir/readme_zh.md) 10 | 11 | ## PFFT(Parallel FFT) Processing Module 12 | 13 | The `PFFT` module uses the Radix-2 decimation-in-time(DIT) decomposition method for computing the DFT. 14 | 15 | The `PFFT` module computes an N-Point forward DFT where N is 2^FFT_ORDER, 16 | the value of parameter FFT_ORDER can be 1,2,..,6. For larger N, you need to modify 17 | the source code appropriately. 18 | 19 | The main difference with Xilinx FFT LogiCORE IP is that `PFFT` can perform one FFT operation per clock, but Xilinx FFT LogiCORE IP need N+1 clocks. 20 | 21 | > For more details, please read [pfft's readme](./pfft/readme.md) 22 | 23 | ## Channelized Receiver Module Based on Polyphase Filterbank (CHNN_RCVR) 24 | 25 | In this design, channelized receiver module based on polyphase filterbank with configurable channel number and filter coefficient is implemented. 26 | 27 | > For more details, please read [chn_rcvr readme](./chnn_rcvr/readme_zh.md). -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # 个人模块仓库 2 | 3 | [点击此处查看英文说明...](./README.md) 4 | 5 | ## 有限冲激响应滤波器模块(FIR Filter) 6 | 7 | 该设计实现了一个单速率(single-rate)有限冲激响应(FIR)滤波器模块. 8 | 9 | > 请阅读[fir readme](./fir/readme_zh.md), 获取该模块的详细信息. 10 | 11 | ## 并行快速傅里叶变换模块(PFFT) 12 | 13 | PFFT 模块采用时域抽取基-2分解方法来计算N点DFT, N为2的指数幂(2^FFT_ORDER, FFT_ORDER = 1,2,...,6).对于64点(2^6)以上的FFT计算, 需要对代码进行适当修改. 14 | 15 | > 请阅读[pfft's readme](./pfft/readme_zh.md), 获取该模块的详细信息. 16 | 17 | 18 | ## 多相滤波数字信道化模块(chnn_rcvr) 19 | 20 | 该设计实现了一个通道数和滤波器系数均可配置的多相滤波数字信道化模块. 21 | 22 | > 请阅读[chn_rcvr readme](./chnn_rcvr/readme_zh.md), 获取详细信息. 23 | 24 | -------------------------------------------------------------------------------- /chnn_rcvr/create_project.tcl: -------------------------------------------------------------------------------- 1 | #***************************************************************************************** 2 | # Vivado (TM) v2020.2 (64-bit) 3 | # 4 | # create_project.tcl: Tcl script for re-creating project 'chnn_rcvr' 5 | # 6 | # Generated by Vivado on Sat Nov 27 11:20:44 +0800 2021 7 | # IP Build 3064653 on Wed Nov 18 14:17:31 MST 2020 8 | # 9 | # This file contains the Vivado Tcl commands for re-creating the project to the state* 10 | # when this script was generated. In order to re-create the project, please source this 11 | # file in the Vivado Tcl Shell. 12 | # 13 | # * Note that the runs in the created project will be configured the same way as the 14 | # original project, however they will not be launched automatically. To regenerate the 15 | # run results please launch the synthesis/implementation runs as needed. 16 | # 17 | #***************************************************************************************** 18 | # NOTE: In order to use this script for source control purposes, please make sure that the 19 | # following files are added to the source control system:- 20 | # 21 | # 1. This project restoration tcl script (create_project.tcl) that was generated. 22 | # 23 | # 2. The following source(s) files that were local or imported into the original project. 24 | # (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) 25 | # 26 | # "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/axi_cmult.v" 27 | # "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/exp_mult.v" 28 | # "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/chnn_rcvr.v" 29 | # "C:/Users/falwa/workspace/code_repo/chnn_rcvr/sim/sim_chnn_rcvr.v" 30 | # 31 | # 3. The following remote source files that were added to the original project:- 32 | # 33 | # "C:/Users/falwa/workspace/code_repo/pfft/butterfly.v" 34 | # "C:/Users/falwa/workspace/code_repo/pfft/butterfly_block.v" 35 | # "C:/Users/falwa/workspace/code_repo/common/cmult.v" 36 | # "C:/Users/falwa/workspace/code_repo/fir/fir.v" 37 | # "C:/Users/falwa/workspace/code_repo/fir/multadd.v" 38 | # "C:/Users/falwa/workspace/code_repo/pfft/pfft.v" 39 | # "C:/Users/falwa/workspace/code_repo/common/pipe_delay.v" 40 | # "C:/Users/falwa/workspace/code_repo/common/rom.v" 41 | # 42 | #***************************************************************************************** 43 | 44 | # Check file required for this script exists 45 | proc checkRequiredFiles { origin_dir} { 46 | set status true 47 | set files [list \ 48 | "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/axi_cmult.v" \ 49 | "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/exp_mult.v" \ 50 | "C:/Users/falwa/workspace/code_repo/chnn_rcvr/hdl/chnn_rcvr.v" \ 51 | "C:/Users/falwa/workspace/code_repo/chnn_rcvr/sim/sim_chnn_rcvr.v" \ 52 | ] 53 | foreach ifile $files { 54 | if { ![file isfile $ifile] } { 55 | puts " Could not find local file $ifile " 56 | set status false 57 | } 58 | } 59 | 60 | set files [list \ 61 | "C:/Users/falwa/workspace/code_repo/pfft/butterfly.v" \ 62 | "C:/Users/falwa/workspace/code_repo/pfft/butterfly_block.v" \ 63 | "C:/Users/falwa/workspace/code_repo/common/cmult.v" \ 64 | "C:/Users/falwa/workspace/code_repo/fir/fir.v" \ 65 | "C:/Users/falwa/workspace/code_repo/fir/multadd.v" \ 66 | "C:/Users/falwa/workspace/code_repo/pfft/pfft.v" \ 67 | "C:/Users/falwa/workspace/code_repo/common/pipe_delay.v" \ 68 | "C:/Users/falwa/workspace/code_repo/common/rom.v" \ 69 | ] 70 | foreach ifile $files { 71 | if { ![file isfile $ifile] } { 72 | puts " Could not find remote file $ifile " 73 | set status false 74 | } 75 | } 76 | 77 | return $status 78 | } 79 | # Set the reference directory for source file relative paths (by default the value is script directory path) 80 | set origin_dir "." 81 | 82 | # Use origin directory path location variable, if specified in the tcl shell 83 | if { [info exists ::origin_dir_loc] } { 84 | set origin_dir $::origin_dir_loc 85 | } 86 | 87 | # Set the project name 88 | set _xil_proj_name_ "chnn_rcvr" 89 | 90 | # Use project name variable, if specified in the tcl shell 91 | if { [info exists ::user_project_name] } { 92 | set _xil_proj_name_ $::user_project_name 93 | } 94 | 95 | variable script_file 96 | set script_file "create_project.tcl" 97 | 98 | # Help information for this script 99 | proc print_help {} { 100 | variable script_file 101 | puts "\nDescription:" 102 | puts "Recreate a Vivado project from this script. The created project will be" 103 | puts "functionally equivalent to the original project for which this script was" 104 | puts "generated. The script contains commands for creating a project, filesets," 105 | puts "runs, adding/importing sources and setting properties on various objects.\n" 106 | puts "Syntax:" 107 | puts "$script_file" 108 | puts "$script_file -tclargs \[--origin_dir \]" 109 | puts "$script_file -tclargs \[--project_name \]" 110 | puts "$script_file -tclargs \[--help\]\n" 111 | puts "Usage:" 112 | puts "Name Description" 113 | puts "-------------------------------------------------------------------------" 114 | puts "\[--origin_dir \] Determine source file paths wrt this path. Default" 115 | puts " origin_dir path value is \".\", otherwise, the value" 116 | puts " that was set with the \"-paths_relative_to\" switch" 117 | puts " when this script was generated.\n" 118 | puts "\[--project_name \] Create project with the specified name. Default" 119 | puts " name is the name of the project from where this" 120 | puts " script was generated.\n" 121 | puts "\[--help\] Print help information for this script" 122 | puts "-------------------------------------------------------------------------\n" 123 | exit 0 124 | } 125 | 126 | if { $::argc > 0 } { 127 | for {set i 0} {$i < $::argc} {incr i} { 128 | set option [string trim [lindex $::argv $i]] 129 | switch -regexp -- $option { 130 | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } 131 | "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } 132 | "--help" { print_help } 133 | default { 134 | if { [regexp {^-} $option] } { 135 | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" 136 | return 1 137 | } 138 | } 139 | } 140 | } 141 | } 142 | 143 | # Set the directory path for the original project from where this script was exported 144 | set orig_proj_dir "[file normalize "$origin_dir/"]" 145 | 146 | # Check for paths and files needed for project creation 147 | set validate_required 0 148 | if { $validate_required } { 149 | if { [checkRequiredFiles $origin_dir] } { 150 | puts "Tcl file $script_file is valid. All files required for project creation is accesable. " 151 | } else { 152 | puts "Tcl file $script_file is not valid. Not all files required for project creation is accesable. " 153 | return 154 | } 155 | } 156 | 157 | # Create project 158 | create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7vx690tffg1761-2 159 | 160 | # Set the directory path for the new project 161 | set proj_dir [get_property directory [current_project]] 162 | 163 | # Set project properties 164 | set obj [current_project] 165 | set_property -name "board_part" -value "xilinx.com:vc709:part0:1.8" -objects $obj 166 | set_property -name "default_lib" -value "xil_defaultlib" -objects $obj 167 | set_property -name "enable_vhdl_2008" -value "1" -objects $obj 168 | set_property -name "ip_cache_permissions" -value "read write" -objects $obj 169 | set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj 170 | set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj 171 | set_property -name "platform.board_id" -value "vc709" -objects $obj 172 | set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj 173 | set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj 174 | set_property -name "simulator_language" -value "Mixed" -objects $obj 175 | set_property -name "webtalk.xsim_launch_sim" -value "34" -objects $obj 176 | 177 | # Create 'sources_1' fileset (if not found) 178 | if {[string equal [get_filesets -quiet sources_1] ""]} { 179 | create_fileset -srcset sources_1 180 | } 181 | 182 | # Set 'sources_1' fileset object 183 | set obj [get_filesets sources_1] 184 | set files [list \ 185 | [file normalize "${origin_dir}/../pfft/butterfly.v"] \ 186 | [file normalize "${origin_dir}/../pfft/butterfly_block.v"] \ 187 | [file normalize "${origin_dir}/../common/cmult.v"] \ 188 | [file normalize "${origin_dir}/../fir/fir.v"] \ 189 | [file normalize "${origin_dir}/../fir/multadd.v"] \ 190 | [file normalize "${origin_dir}/../pfft/pfft.v"] \ 191 | [file normalize "${origin_dir}/../common/pipe_delay.v"] \ 192 | [file normalize "${origin_dir}/../common/rom.v"] \ 193 | ] 194 | add_files -norecurse -fileset $obj $files 195 | 196 | # Add local files from the original project (-no_copy_sources specified) 197 | set files [list \ 198 | [file normalize "${origin_dir}/hdl/axi_cmult.v" ]\ 199 | [file normalize "${origin_dir}/hdl/exp_mult.v" ]\ 200 | [file normalize "${origin_dir}/hdl/chnn_rcvr.v" ]\ 201 | ] 202 | set added_files [add_files -fileset sources_1 $files] 203 | 204 | # Set 'sources_1' fileset file properties for remote files 205 | # None 206 | 207 | # Set 'sources_1' fileset file properties for local files 208 | # None 209 | 210 | # Set 'sources_1' fileset properties 211 | set obj [get_filesets sources_1] 212 | set_property -name "top" -value "chnn_rcvr" -objects $obj 213 | 214 | # Create 'constrs_1' fileset (if not found) 215 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 216 | create_fileset -constrset constrs_1 217 | } 218 | 219 | # Set 'constrs_1' fileset object 220 | set obj [get_filesets constrs_1] 221 | 222 | # Empty (no sources present) 223 | 224 | # Set 'constrs_1' fileset properties 225 | set obj [get_filesets constrs_1] 226 | 227 | # Create 'sim_1' fileset (if not found) 228 | if {[string equal [get_filesets -quiet sim_1] ""]} { 229 | create_fileset -simset sim_1 230 | } 231 | 232 | # Set 'sim_1' fileset object 233 | set obj [get_filesets sim_1] 234 | # Add local files from the original project (-no_copy_sources specified) 235 | set files [list \ 236 | [file normalize "${origin_dir}/sim/sim_chnn_rcvr.v" ]\ 237 | ] 238 | set added_files [add_files -fileset sim_1 $files] 239 | 240 | # Set 'sim_1' fileset file properties for remote files 241 | # None 242 | 243 | # Set 'sim_1' fileset file properties for local files 244 | # None 245 | 246 | # Set 'sim_1' fileset properties 247 | set obj [get_filesets sim_1] 248 | set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj 249 | set_property -name "top" -value "sim_chnn_rcvr" -objects $obj 250 | set_property -name "top_auto_set" -value "0" -objects $obj 251 | set_property -name "top_lib" -value "xil_defaultlib" -objects $obj 252 | 253 | # Set 'utils_1' fileset object 254 | set obj [get_filesets utils_1] 255 | # Empty (no sources present) 256 | 257 | # Set 'utils_1' fileset properties 258 | set obj [get_filesets utils_1] 259 | 260 | # Create 'synth_1' run (if not found) 261 | if {[string equal [get_runs -quiet synth_1] ""]} { 262 | create_run -name synth_1 -part xc7vx690tffg1761-2 -flow {Vivado Synthesis 2018} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 263 | } else { 264 | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] 265 | set_property flow "Vivado Synthesis 2018" [get_runs synth_1] 266 | } 267 | set obj [get_runs synth_1] 268 | set_property set_report_strategy_name 1 $obj 269 | set_property report_strategy {Vivado Synthesis Default Reports} $obj 270 | set_property set_report_strategy_name 0 $obj 271 | # Create 'synth_1_synth_report_utilization_0' report (if not found) 272 | if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { 273 | create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 274 | } 275 | set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] 276 | if { $obj != "" } { 277 | 278 | } 279 | set obj [get_runs synth_1] 280 | set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj 281 | 282 | # set the current synth run 283 | current_run -synthesis [get_runs synth_1] 284 | 285 | # Create 'impl_1' run (if not found) 286 | if {[string equal [get_runs -quiet impl_1] ""]} { 287 | create_run -name impl_1 -part xc7vx690tffg1761-2 -flow {Vivado Implementation 2018} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 288 | } else { 289 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 290 | set_property flow "Vivado Implementation 2018" [get_runs impl_1] 291 | } 292 | set obj [get_runs impl_1] 293 | set_property set_report_strategy_name 1 $obj 294 | set_property report_strategy {Vivado Implementation Default Reports} $obj 295 | set_property set_report_strategy_name 0 $obj 296 | # Create 'impl_1_init_report_timing_summary_0' report (if not found) 297 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { 298 | create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 299 | } 300 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] 301 | if { $obj != "" } { 302 | set_property -name "is_enabled" -value "0" -objects $obj 303 | set_property -name "options.max_paths" -value "10" -objects $obj 304 | 305 | } 306 | # Create 'impl_1_opt_report_drc_0' report (if not found) 307 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { 308 | create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 309 | } 310 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] 311 | if { $obj != "" } { 312 | 313 | } 314 | # Create 'impl_1_opt_report_timing_summary_0' report (if not found) 315 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { 316 | create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 317 | } 318 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] 319 | if { $obj != "" } { 320 | set_property -name "is_enabled" -value "0" -objects $obj 321 | set_property -name "options.max_paths" -value "10" -objects $obj 322 | 323 | } 324 | # Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) 325 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { 326 | create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 327 | } 328 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] 329 | if { $obj != "" } { 330 | set_property -name "is_enabled" -value "0" -objects $obj 331 | set_property -name "options.max_paths" -value "10" -objects $obj 332 | 333 | } 334 | # Create 'impl_1_place_report_io_0' report (if not found) 335 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { 336 | create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 337 | } 338 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] 339 | if { $obj != "" } { 340 | 341 | } 342 | # Create 'impl_1_place_report_utilization_0' report (if not found) 343 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { 344 | create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 345 | } 346 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] 347 | if { $obj != "" } { 348 | 349 | } 350 | # Create 'impl_1_place_report_control_sets_0' report (if not found) 351 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { 352 | create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 353 | } 354 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] 355 | if { $obj != "" } { 356 | set_property -name "options.verbose" -value "1" -objects $obj 357 | 358 | } 359 | # Create 'impl_1_place_report_incremental_reuse_0' report (if not found) 360 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { 361 | create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 362 | } 363 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] 364 | if { $obj != "" } { 365 | set_property -name "is_enabled" -value "0" -objects $obj 366 | 367 | } 368 | # Create 'impl_1_place_report_incremental_reuse_1' report (if not found) 369 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { 370 | create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 371 | } 372 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] 373 | if { $obj != "" } { 374 | set_property -name "is_enabled" -value "0" -objects $obj 375 | 376 | } 377 | # Create 'impl_1_place_report_timing_summary_0' report (if not found) 378 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { 379 | create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 380 | } 381 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] 382 | if { $obj != "" } { 383 | set_property -name "is_enabled" -value "0" -objects $obj 384 | set_property -name "options.max_paths" -value "10" -objects $obj 385 | 386 | } 387 | # Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) 388 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { 389 | create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 390 | } 391 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] 392 | if { $obj != "" } { 393 | set_property -name "is_enabled" -value "0" -objects $obj 394 | set_property -name "options.max_paths" -value "10" -objects $obj 395 | 396 | } 397 | # Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) 398 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { 399 | create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 400 | } 401 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] 402 | if { $obj != "" } { 403 | set_property -name "is_enabled" -value "0" -objects $obj 404 | set_property -name "options.max_paths" -value "10" -objects $obj 405 | 406 | } 407 | # Create 'impl_1_route_report_drc_0' report (if not found) 408 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { 409 | create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 410 | } 411 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] 412 | if { $obj != "" } { 413 | 414 | } 415 | # Create 'impl_1_route_report_methodology_0' report (if not found) 416 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { 417 | create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 418 | } 419 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] 420 | if { $obj != "" } { 421 | 422 | } 423 | # Create 'impl_1_route_report_power_0' report (if not found) 424 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { 425 | create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 426 | } 427 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] 428 | if { $obj != "" } { 429 | 430 | } 431 | # Create 'impl_1_route_report_route_status_0' report (if not found) 432 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { 433 | create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 434 | } 435 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] 436 | if { $obj != "" } { 437 | 438 | } 439 | # Create 'impl_1_route_report_timing_summary_0' report (if not found) 440 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { 441 | create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 442 | } 443 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] 444 | if { $obj != "" } { 445 | set_property -name "options.max_paths" -value "10" -objects $obj 446 | 447 | } 448 | # Create 'impl_1_route_report_incremental_reuse_0' report (if not found) 449 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { 450 | create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 451 | } 452 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] 453 | if { $obj != "" } { 454 | 455 | } 456 | # Create 'impl_1_route_report_clock_utilization_0' report (if not found) 457 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { 458 | create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 459 | } 460 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] 461 | if { $obj != "" } { 462 | 463 | } 464 | # Create 'impl_1_route_report_bus_skew_0' report (if not found) 465 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { 466 | create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 467 | } 468 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] 469 | if { $obj != "" } { 470 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 471 | 472 | } 473 | # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) 474 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { 475 | create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 476 | } 477 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] 478 | if { $obj != "" } { 479 | set_property -name "options.max_paths" -value "10" -objects $obj 480 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 481 | 482 | } 483 | # Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) 484 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { 485 | create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 486 | } 487 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] 488 | if { $obj != "" } { 489 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 490 | 491 | } 492 | set obj [get_runs impl_1] 493 | set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj 494 | set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj 495 | set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj 496 | 497 | # set the current impl run 498 | current_run -implementation [get_runs impl_1] 499 | 500 | puts "INFO: Project created:${_xil_proj_name_}" 501 | # Create 'drc_1' gadget (if not found) 502 | if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { 503 | create_dashboard_gadget -name {drc_1} -type drc 504 | } 505 | set obj [get_dashboard_gadgets [ list "drc_1" ] ] 506 | set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj 507 | 508 | # Create 'methodology_1' gadget (if not found) 509 | if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { 510 | create_dashboard_gadget -name {methodology_1} -type methodology 511 | } 512 | set obj [get_dashboard_gadgets [ list "methodology_1" ] ] 513 | set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj 514 | 515 | # Create 'power_1' gadget (if not found) 516 | if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { 517 | create_dashboard_gadget -name {power_1} -type power 518 | } 519 | set obj [get_dashboard_gadgets [ list "power_1" ] ] 520 | set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj 521 | 522 | # Create 'timing_1' gadget (if not found) 523 | if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { 524 | create_dashboard_gadget -name {timing_1} -type timing 525 | } 526 | set obj [get_dashboard_gadgets [ list "timing_1" ] ] 527 | set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj 528 | 529 | # Create 'utilization_1' gadget (if not found) 530 | if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { 531 | create_dashboard_gadget -name {utilization_1} -type utilization 532 | } 533 | set obj [get_dashboard_gadgets [ list "utilization_1" ] ] 534 | set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj 535 | set_property -name "run.step" -value "synth_design" -objects $obj 536 | set_property -name "run.type" -value "synthesis" -objects $obj 537 | 538 | # Create 'utilization_2' gadget (if not found) 539 | if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { 540 | create_dashboard_gadget -name {utilization_2} -type utilization 541 | } 542 | set obj [get_dashboard_gadgets [ list "utilization_2" ] ] 543 | set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj 544 | 545 | move_dashboard_gadget -name {utilization_1} -row 0 -col 0 546 | move_dashboard_gadget -name {power_1} -row 1 -col 0 547 | move_dashboard_gadget -name {drc_1} -row 2 -col 0 548 | move_dashboard_gadget -name {timing_1} -row 0 -col 1 549 | move_dashboard_gadget -name {utilization_2} -row 1 -col 1 550 | move_dashboard_gadget -name {methodology_1} -row 2 -col 1 551 | -------------------------------------------------------------------------------- /chnn_rcvr/draw.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falwat/code_repo/cb72281f9c58a4d48d2b15299823f9f7160cf52f/chnn_rcvr/draw.odg -------------------------------------------------------------------------------- /chnn_rcvr/hdl/axi_cmult.v: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | * this software and associated documentation files (the "Software"), to deal in 6 | * the Software without restriction, including without limitation the rights to 7 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | * the Software, and to permit persons to whom the Software is furnished to do so, 9 | * subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | `timescale 1ns / 1ps 22 | ////////////////////////////////////////////////////////////////////////////////// 23 | // Company: 24 | // Engineer: 25 | // Jackie Wang(falwat@163.com) 26 | // Create Date: 2021/11/14 14:43:32 27 | // Design Name: 28 | // Module Name: axi_cmult 29 | // Project Name: 30 | // Target Devices: 31 | // Tool Versions: 32 | // Description: 33 | // Complex multiplier with AXI-Stream interface. 34 | // 35 | // Dependencies: 36 | // - common\cmult.v 37 | // - common\pipe_delay.v 38 | // 39 | // Revision: 40 | // Revision 0.01 - File Created 41 | // Additional Comments: 42 | // 43 | ////////////////////////////////////////////////////////////////////////////////// 44 | 45 | /** 46 | axi_cmult #( 47 | .C_A_WIDTH(32), 48 | .C_B_WIDTH(32), 49 | .C_OUT_WIDTH(64), 50 | .BITS_TRUNK(31) 51 | ) u_axi_cmult ( 52 | .aclk(aclk), 53 | .s_axis_a_tdata(s_axis_a_tdata), 54 | .s_axis_a_tvalid(s_axis_a_tvalid), 55 | .s_axis_b_tdata(s_axis_b_tdata), 56 | .s_axis_b_tvalid(s_axis_b_tvalid), 57 | .m_axis_dout_tdata(m_axis_dout_tdata), 58 | .m_axis_dout_tvalid(m_axis_dout_tvalid) 59 | ); 60 | */ 61 | 62 | module axi_cmult #( 63 | parameter C_A_WIDTH = 32, 64 | parameter C_B_WIDTH = 32, 65 | parameter C_OUT_WIDTH = 32, 66 | parameter BITS_TRUNK = 31 67 | )( 68 | input aclk, 69 | input [C_A_WIDTH-1:0] s_axis_a_tdata, 70 | input s_axis_a_tvalid, 71 | input [C_B_WIDTH-1:0] s_axis_b_tdata, 72 | input s_axis_b_tvalid, 73 | output [C_OUT_WIDTH-1:0] m_axis_dout_tdata, 74 | output m_axis_dout_tvalid 75 | ); 76 | 77 | localparam AWIDTH = C_A_WIDTH / 2; 78 | localparam BWIDTH = C_B_WIDTH / 2; 79 | localparam PWIDTH = AWIDTH + BWIDTH - 1; 80 | wire [AWIDTH - 1 : 0] ar = s_axis_a_tdata[0 +: AWIDTH]; 81 | wire [AWIDTH - 1 : 0] ai = s_axis_a_tdata[AWIDTH +: AWIDTH]; 82 | wire [BWIDTH - 1 : 0] br = s_axis_b_tdata[0 +: BWIDTH]; 83 | wire [BWIDTH - 1 : 0] bi = s_axis_b_tdata[BWIDTH +: BWIDTH]; 84 | wire [PWIDTH - 1 : 0] pr, pi; 85 | 86 | cmult # ( 87 | .AWIDTH(AWIDTH), 88 | .BWIDTH(BWIDTH) 89 | ) 90 | u_cmult 91 | ( 92 | .clk(aclk), 93 | .ar(ar), 94 | .ai(ai), 95 | .br(br), 96 | .bi(bi), 97 | .pr(pr), 98 | .pi(pi) 99 | ); 100 | 101 | localparam OUT_WIDTH = C_OUT_WIDTH / 2; 102 | assign m_axis_dout_tdata[0 +: OUT_WIDTH] = pr[BITS_TRUNK +: OUT_WIDTH]; 103 | assign m_axis_dout_tdata[OUT_WIDTH +: OUT_WIDTH] = pi[BITS_TRUNK +: OUT_WIDTH]; 104 | 105 | pipe_delay #( 106 | .DATA_WIDTH(1), // DATA_WIDTH = 1,2... 107 | .DELAY_CLKS(6) // DELAY_CLKS = 0,1,... 108 | ) u_pipe_delay ( 109 | .rst(1'b0), // input wire rst; 110 | .clk(aclk), // input wire clk; 111 | .clk_en(1'b1), // input wire clk_en; 112 | .din(s_axis_a_tvalid & s_axis_b_tvalid), // input wire [DATA_WIDTH-1:0] din; 113 | .dout(m_axis_dout_tvalid) // output wire [DATA_WIDTH-1:0] dout; 114 | ); 115 | 116 | endmodule 117 | -------------------------------------------------------------------------------- /chnn_rcvr/hdl/chnn_rcvr.v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falwat/code_repo/cb72281f9c58a4d48d2b15299823f9f7160cf52f/chnn_rcvr/hdl/chnn_rcvr.v -------------------------------------------------------------------------------- /chnn_rcvr/hdl/exp_mult.v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falwat/code_repo/cb72281f9c58a4d48d2b15299823f9f7160cf52f/chnn_rcvr/hdl/exp_mult.v -------------------------------------------------------------------------------- /chnn_rcvr/readme_zh.md: -------------------------------------------------------------------------------- 1 | # 基于多相滤波的数字信道化接收模块设计 2 | 3 | ## 概述 4 | 5 | 该设计实现了一个通道数和滤波器系数均可配置的多相滤波数字信道化模块. 6 | 7 | - 通道数: 支持2, 4, 8, 16, 32 信道. 8 | 9 | ### 创建工程 10 | 11 | - 使用`git`工具克隆此仓库. 12 | 13 | ```sh 14 | git clone https://github.com/falwat/code_repo.git 15 | ``` 16 | 17 | - 打开`vivado tcl shell`, 使用`cd`命令切换至`chnn_rcvr`目录 18 | - 运行`source ./create_project.tcl`,创建测试工程 19 | ```sh 20 | cd <仓库所在文件夹/code_repo/chnn_rcvr> 21 | source ./create_project.tcl 22 | ``` 23 | 24 | ### 文件组成 25 | 26 | 文件|说明 27 | -|- 28 | [./create_project.tcl](./create_project.tcl) | 用于生成测试工程的tcl脚本. 29 | [./readme_zh.md](./readme_zh.md) | 说明文件(中文) 30 | [./hdl/axi_cmult.v](./hdl/axi_cmult.v) | AXI-Stream总线接口的复数乘法器 31 | [./hdl/exp_mult.v](./hdl/exp_mult.v) | 实现$(-1)^{(K-1)m}$ 的乘法器 32 | [./hdl/chnn_rcvr.v](./hdl/chnn_rcvr.v) | **信道化接收模块顶层** 33 | [./script/fir_coe_gen.py](./script/fir_coe_gen.py) | 用于生成FIR滤波器系数文件的脚本 34 | [./script/rotate_factor_gen.py](./script/rotate_factor_gen.py) | 用于生成旋转因子序列的脚本 35 | [./script/sig_gen.py](./script/sig_gen.py) | 用于生成测试数据文件的脚本 36 | [./script/sim_chnn_rcvr.py](./script/sim_chnn_rcvr.py) | 用于仿真测试的脚本 37 | [./sim/sim_chnn_rcvr.v](./sim/sim_chnn_rcvr.v) | 仿真测试激励文件 38 | [../common/cmult.v](../common/cmult.v) | 复数乘法器 39 | [../common/pipe_delay.v](../common/pipe_delay.v) | 延迟模块 40 | [../fir/fir.v](../fir/fir.v) | FIR滤波器模块顶层, 参见[fir readme](../fir/readme_zh.md) 41 | [../fir/multadd.v](../fir/multadd.v) | FIR 滤波器的子模块, 参见[fir readme](../fir/readme_zh.md) 42 | [../pfft/butterfly.v](../pfft/butterfly.v) | 并行FFT模块的子模块,参见[pfft readme](../pfft/readme_zh.md) 43 | [../pfft/butterfly_block.v](../pfft/butterfly_block.v) | 并行FFT模块的子模块,参见[pfft readme](../pfft/readme_zh.md) 44 | [../pfft/pfft.v](../pfft/pfft.v) | 并行FFT模块顶层, 参见[pfft readme](../pfft/readme_zh.md) 45 | 46 | ## 参数说明 47 | 48 | 名称|类型|描述 49 | -|-|- 50 | CHN_NUM | integer | 信道个数, 支持2, 4, 8, 16, 32 信道. 51 | DATA_WIDTH | integer | 复数数据位宽. 该参数应为偶数. 52 | C_COEF_FILE | string | 多相FIR滤波器系数文件, 请使用[./script/fir_coe_gen.py](./script/fir_coe_gen.py)脚本生成系数文件. 53 | C_COEF_WIDTH | integer | 多相FIR滤波器系数位宽. 54 | C_NUM_TAPS | integer | FIR原型滤波器系数序列长度, 该参数应为信道个数的整数倍. 55 | 56 | ## 端口描述 57 | 58 | 名称|I/O|描述 59 | -|:-:|- 60 | aclk | I | 上升沿触发. 61 | aresetn | I | 同步复位信号. 低电平有效. 62 | s_axis_data_tvalid | I | 输入数据总线的TVALID端口. 63 | s_axis_data_tdata | I | 输入数据总线的TDATA端口.
位宽: CHN_NUM * DATA_WIDTH.
内容: {X[N-1].imag, X[N-1].real,..., X[1].imag, X[1].real, X[0].imag, X[0]. real} 64 | m_axis_data_tvalid | O | 输出数据总线的TVAILD端口. 65 | m_axis_data_tdata | O | 输出数据总线的TDATA端口.
位宽: CHN_NUM * DATA_WIDTH
内容: {Y[N-1].imag, Y[N-1].real,..., Y[1].imag, Y[1].real, Y[0].imag, Y[0]. real} 66 | 67 | ## 资源消耗 68 | 69 | DSP48E在FIR滤波器, 复数乘法器和并行FFT三个子模块中使用. DSP48E 的使用量满足如下公式: 70 | $$ 71 | 3 * 2^{N-1} * (\log_2(N) - 1) 72 | $$ 73 | 对于16点的PFFT, 需要的DSP48E的数量为: 3 * 8 * 3 = 72 74 | 75 | 实际综合后的资源消耗如下表所示: 76 | N-点FFT | Slice LUTs | Slice Registers | DSPs 77 | :-:|-:|-:|-: 78 | 8 | 1667 | 2372 | 24 79 | 16 | 4611 | 6560 | 72 80 | 32 | 11779 | 16754 | 192 81 | 64 | 28678 | 40751 | 480 82 | 83 | ## 时延 84 | 85 | 数据输入到N点FFT计算结果输出所需的时延满足如下计算公式: 86 | $$ 87 | Latency(N) = (\log_2(N)-1) * 8 + 2 88 | $$ 89 | 90 | N点FFT的时延如下表: 91 | N点FFT|时延(clks) 92 | :-:|-: 93 | 2 | 2 94 | 4 | 10 95 | 8 | 18 96 | 16 | 26 97 | 32 | 34 98 | 64 | 42 99 | 100 | 101 | ## 测试 102 | 103 | - 根据需要修改[./pfft.v](./pfft.v)中参数`FFT_ORDER`的值. 104 | - 修改[./sim_data_gen.py](./sim_data_gen.py)中`fft_len`参数的值. `fft_len`表示计算FFT的点数. 105 | - 运行[./sim_data_gen.py](./sim_data_gen.py), 生成测试数据文件`numbers.txt`, 默认保存路径为`D:\`. 106 | - 在`Vivado`中,点击`Flow Navigator`中的`Run Simulation`,或使用菜单`Flow|Run Simulation` 107 | - 运行仿真后, 在`D:\`下会生成输出数据文件`output.dat`. 108 | - 运行[./sim_pfft.py](./sim_pfft.py),查看测试结果. 打印信息中,`x`代表输入数据的值, `vhd`表示pfft模块输出的计算结果, `myfft`为python实现的基-2 DIT-FFT函数的输出结果, `fft` 为numpy.fft.fft函数输出的计算结果,`diff`为PFFT模块输出结果与python函数`myfft`计算结果的偏差. -------------------------------------------------------------------------------- /chnn_rcvr/script/channelizer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | Created on Sat Nov 27 14:40:17 2021 23 | 24 | @author: falwa 25 | """ 26 | 27 | """ 28 | Channelizer class. 29 | """ 30 | 31 | __all__ = ['Channelizer'] 32 | 33 | import numpy 34 | import scipy.signal 35 | import scipy.fft 36 | import matplotlib.pyplot as plt 37 | 38 | 39 | class Channelizer(object): 40 | """ 41 | Channelizer object. 42 | \param filter_coeffs: Filter coefficient array. 43 | """ 44 | 45 | _channel_num: int 46 | _filter_coeffs: numpy.ndarray 47 | 48 | def __init__( 49 | self, 50 | filter_coeffs: numpy.ndarray, 51 | channel_num: int = 8): 52 | 53 | assert isinstance(channel_num, int) 54 | 55 | self._filter_coeffs = numpy.reshape(filter_coeffs, (channel_num, -1), order='F') 56 | self._channel_num = channel_num 57 | 58 | def dispatch( 59 | self, 60 | data: numpy.ndarray 61 | ) -> numpy.ndarray: 62 | 63 | # Make the data length an integer multiple of the number of channels. 64 | disp_len = int(numpy.ceil(data.size / self._channel_num)) 65 | patch_size = int(disp_len * self._channel_num - data.size) 66 | patch_data = numpy.concatenate((data, numpy.zeros(patch_size))) 67 | 68 | # Reshape data. 69 | reshape_data = numpy.reshape(patch_data, (self._channel_num, -1), order='F') 70 | polyphase_data = numpy.flipud(reshape_data) 71 | 72 | nv = numpy.arange(disp_len) 73 | prefilt_data = polyphase_data * ((-1) ** nv) 74 | 75 | # Polyphase filter bank 76 | filt_data = numpy.zeros(prefilt_data.shape, dtype=complex) 77 | for k in range(self._channel_num): 78 | # zi = scipy.signal.lfilter_zi(self._filter_coeffs[k], 1) 79 | filt_data[k] = scipy.signal.lfilter(self._filter_coeffs[k], 1, prefilt_data[k]) 80 | 81 | postfilt_data = numpy.zeros(prefilt_data.shape, dtype=complex) 82 | for k in range(self._channel_num): 83 | postfilt_data[k] = filt_data[k] * numpy.exp(-1j * numpy.pi * k / self._channel_num) 84 | 85 | # return postfilt_data 86 | 87 | dispatch_data = scipy.fft.fft(numpy.flipud(postfilt_data), axis=0) 88 | 89 | return dispatch_data 90 | 91 | def sweep_freqz(self, N: int = 0) -> numpy.ndarray: 92 | """ 93 | Compute the frequency response of each channel using sweep signal. 94 | 95 | Parameters: 96 | ---------- 97 | 98 | N : the number of sample point. 99 | 100 | Return: 101 | ------- 102 | a: Amplitude in dB. 103 | f: Digital frequence point. 104 | 105 | Example: 106 | -------- 107 | import scipy 108 | import matplotlib.pyplot as plt 109 | from polyphase import Channelizer 110 | 111 | # Design FIR Filter 112 | channel_num = 8 113 | cutoff = 1 / channel_num / 2 # Desired cutoff digital frequency 114 | trans_width = cutoff / 10 # Width of transition from pass band to stop band 115 | numtaps = 512 # Size of the FIR filter. 116 | taps = scipy.signal.remez(numtaps, [0, cutoff - trans_width, cutoff + trans_width, 0.5],[1, 0]) 117 | 118 | channelizer = Channelizer(taps, channel_num) 119 | 120 | w, a = channelizer.sweep_freqz() 121 | 122 | plt.plot(w,a.T) 123 | plt.title('Digital channelizer frequency response') 124 | plt.xlabel('Frequency [*rad/sample]') 125 | plt.ylabel('Amplitude [dB]') 126 | plt.show() 127 | 128 | """ 129 | assert isinstance(N, int) 130 | 131 | if N == 0: 132 | N = self._filter_coeffs.size * 100 133 | 134 | w = numpy.linspace(0, 1, N) 135 | p = 2 * numpy.pi * numpy.cumsum(w) 136 | s = numpy.exp(1j * p) 137 | a = 20*numpy.log10(numpy.abs(self.dispatch(s))) 138 | w = numpy.linspace(0, 1, a.shape[1]) 139 | return w, a 140 | -------------------------------------------------------------------------------- /chnn_rcvr/script/fir_coe_gen.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | import scipy 23 | from scipy import signal 24 | import matplotlib.pyplot as plt 25 | from polyphase import Channelizer 26 | from numpy import reshape 27 | import numpy as np 28 | 29 | # Calculate two complement of a list 30 | def complement2(lst, bit_width): 31 | return [int(n) if n > 0 else int(n + 2 ** bit_width) for n in lst] 32 | 33 | def num2hex(lst, field_width): 34 | return ['{0:0{1}x}'.format(int(v), field_width) for v in lst] 35 | 36 | channel_num = 4 37 | coe_width = 24 38 | 39 | # Design FIR Filter 40 | cutoff = 1 / channel_num / 2 # Desired cutoff digital frequency 41 | trans_width = cutoff / 10 # Width of transition from pass band to stop band 42 | numtaps = 32 # Size of the FIR filter. 43 | taps = signal.remez(numtaps, [0, cutoff - trans_width, cutoff + trans_width, 0.5],[1, 0]) 44 | 45 | w, h = signal.freqz(taps) 46 | ax1 = plt.subplot(211) 47 | ax1.set_title('Digital filter frequency response') 48 | ax1.plot(w, 20 * np.log10(abs(h)), 'b') 49 | ax1.set_ylabel('Amplitude [dB]', color='b') 50 | ax1.set_xlabel('Frequency [rad/sample]') 51 | ax2 = ax1.twinx() 52 | angles = np.unwrap(np.angle(h)) 53 | ax2.plot(w, angles, 'g') 54 | ax2.set_ylabel('Angle (radians)', color='g') 55 | ax2.grid() 56 | ax2.axis('tight') 57 | ax3 = plt.subplot(212) 58 | ax3.plot(taps) 59 | plt.show() 60 | 61 | channelizer = Channelizer(taps, channel_num) 62 | 63 | w, a = channelizer.sweep_freqz() 64 | 65 | plt.figure() 66 | plt.plot(w,a.T) 67 | plt.title('Digital channelizer frequency response') 68 | plt.xlabel('Frequency [*rad/sample]') 69 | plt.ylabel('Amplitude [dB]') 70 | plt.show() 71 | 72 | # Generate coefficients for FIR filter with multi-sets. 73 | taps = reshape(taps, (-1, channel_num)) * channel_num 74 | filename = 'D:/fir.coe' 75 | with open(filename, 'w') as f: 76 | for t in taps: 77 | t = t * 2 ** (coe_width - 1) 78 | taps_compl2 = complement2(t, coe_width) 79 | field_width = int(np.ceil(coe_width / 4)) 80 | coes = num2hex(taps_compl2, field_width) 81 | f.write(''.join(coes) + '\n') 82 | print('INFO: Coefficients File for FIR filter has been created. Filename: ', filename) 83 | 84 | -------------------------------------------------------------------------------- /chnn_rcvr/script/rotate_factor_gen.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | from numpy import arange, exp, real, imag, pi, round 23 | 24 | channel_num = 32 25 | 26 | # 数据位宽 27 | bits = 24 28 | 29 | # 生成旋转因子系数 30 | 31 | imax = 2**(bits-2) 32 | 33 | k = arange(channel_num, 0, -1) - 1 34 | 35 | tf = exp(-1j*pi*k/channel_num) 36 | 37 | im = [int(i) if i >= 0 else int(i) + 2**bits for i in imag(tf) * imax] 38 | 39 | re= [int(r) if r >=0 else int(r) + 2**bits for r in real(tf) * imax] 40 | 41 | # rf = ['{:08x}\n'.format((i << 16) + r) for i,r in zip(im, re)] 42 | 43 | # filename = 'rotate_factors_ch{}.coe'.format(channel_num) 44 | # with open(filename, 'w') as f: 45 | # f.writelines(rf) 46 | 47 | rf = ['{}\'h{:06x}_{:06x}'.format(bits * 2, i, r) for i,r in zip(im, re)] 48 | 49 | for p in rf: 50 | print(p) 51 | -------------------------------------------------------------------------------- /chnn_rcvr/script/sig_gen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | """ 21 | import numpy as np 22 | 23 | chn_num = 4 24 | w = 0.04 25 | N = chn_num * 256 26 | amp = 0.5 27 | 28 | n = np.arange(N) 29 | s = np.exp(2j*np.pi*w*n) * amp 30 | 31 | sir = np.array((np.imag(s), np.real(s))) 32 | 33 | sir_int = np.int16(sir * 2 **15) 34 | 35 | s1 = np.fliplr(np.reshape(sir_int.T, (-1,chn_num * 2))) 36 | 37 | filename = 'D:/data.dat' 38 | with open(filename, 'w') as f: 39 | for a in s1: 40 | h = ['{:04x}'.format(v) for v in a.astype(np.uint16)] 41 | f.write(''.join(h) + '\n') 42 | 43 | print('INFO: The data file has been created. Filename: ', filename) 44 | 45 | -------------------------------------------------------------------------------- /chnn_rcvr/script/sim_chnn_rcvr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | 23 | import scipy 24 | import scipy.signal as signal 25 | import numpy as np 26 | import matplotlib.pyplot as plt 27 | from polyphase import Channelizer 28 | 29 | 30 | coe_filename = r'D:/fir.coe' 31 | data_filename = r'D:/data.dat' 32 | dout_filename = r'D:/output.dat' 33 | coe_width = 24 34 | data_width = 16 35 | 36 | 37 | def read_fir_coes(filename, bit_width): 38 | field_width = int(bit_width / 4) 39 | with open(filename, 'r') as f: 40 | lines = f.readlines() 41 | coes = [] 42 | for d in lines: 43 | coe_row = [int(d[k:k+field_width],base=16) for k in range(0, len(d)-1, field_width)] 44 | coe_row_compl2 = [c if c < 2**(bit_width-1) else (c - 2**bit_width) for c in coe_row] 45 | coes.append(coe_row_compl2) 46 | return coes 47 | 48 | def read_data(filename, bit_width): 49 | field_width = int(bit_width / 4) 50 | with open(filename, 'r') as f: 51 | lines = f.readlines() 52 | data = [] 53 | for d in lines: 54 | data_row = [int(d[k:k+4],base=16) for k in range(0, len(d)-1, field_width)] 55 | data_row_compl2 = [c if c < 2**(bit_width-1) else (c - 2**bit_width) for c in data_row] 56 | data.append(data_row_compl2) 57 | return data 58 | 59 | 60 | taps = read_fir_coes(coe_filename, coe_width) 61 | taps = np.array(taps) 62 | channel_num = taps.shape[1] 63 | taps = np.reshape(taps, (1,-1))[0,:] 64 | taps = taps / (2**(coe_width-1)) 65 | # Plot Digital filter frequency response 66 | w, h = signal.freqz(taps) 67 | plt.figure() 68 | ax1 = plt.subplot(211) 69 | ax1.set_title('Digital filter frequency response') 70 | ax1.plot(w, 20 * np.log10(abs(h)), 'b') 71 | ax1.set_ylabel('Amplitude [dB]', color='b') 72 | ax1.set_xlabel('Frequency [rad/sample]') 73 | ax2 = ax1.twinx() 74 | angles = np.unwrap(np.angle(h)) 75 | ax2.plot(w, angles, 'g') 76 | ax2.set_ylabel('Angle (radians)', color='g') 77 | ax2.grid() 78 | ax2.axis('tight') 79 | ax3 = plt.subplot(212) 80 | ax3.plot(taps) 81 | plt.show() 82 | 83 | 84 | x = np.array(read_data(data_filename, data_width)).T 85 | xr = np.flipud(x[1::2]) 86 | xi = np.flipud(x[::2]) 87 | s = xi * 1j + xr 88 | sigs = np.reshape(s.T, (1,-1))[0] 89 | 90 | numtaps = len(taps) 91 | 92 | 93 | channelizer = Channelizer(taps, channel_num) 94 | 95 | # w, a = channelizer.sweep_freqz() 96 | 97 | # plt.plot(w,a.T) 98 | # plt.title('Digital channelizer frequency response') 99 | # plt.xlabel('Frequency [*rad/sample]') 100 | # plt.ylabel('Amplitude [dB]') 101 | # plt.show() 102 | 103 | 104 | ss = channelizer.dispatch(sigs) / channel_num 105 | plt.figure() 106 | plt.subplot(311) 107 | plt.plot(np.real(ss.T)) 108 | plt.subplot(312) 109 | plt.plot(np.imag(ss.T)) 110 | plt.subplot(313) 111 | h = np.abs(np.fft.fft(ss)) 112 | plt.plot(h.T) 113 | plt.show() 114 | 115 | 116 | y = np.array(read_data(dout_filename, data_width)).T 117 | 118 | yr = np.flipud(y[1::2]) 119 | yi = np.flipud(y[::2]) 120 | data = yi * 1j + yr 121 | 122 | plt.figure() 123 | plt.subplot(311) 124 | plt.plot(np.real(data.T)) 125 | plt.subplot(312) 126 | plt.plot(np.imag(data.T)) 127 | plt.subplot(313) 128 | h = np.abs(np.fft.fft(data)) 129 | plt.plot(h.T) 130 | plt.show() 131 | 132 | # ss = np.flipud(ss) 133 | dff = np.abs(data - ss)**2 / (np.abs(data) * np.abs(ss)) 134 | 135 | print(np.max(dff)) 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /chnn_rcvr/sim/sim_chnn_rcvr.v: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | * this software and associated documentation files (the "Software"), to deal in 6 | * the Software without restriction, including without limitation the rights to 7 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | * the Software, and to permit persons to whom the Software is furnished to do so, 9 | * subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | `timescale 1ns / 1ps 22 | ////////////////////////////////////////////////////////////////////////////////// 23 | // Company: 24 | // Engineer: 25 | // 26 | // Create Date: 2021/11/15 20:20:15 27 | // Design Name: 28 | // Module Name: sim_chnn_rcvr 29 | // Project Name: 30 | // Target Devices: 31 | // Tool Versions: 32 | // Description: 33 | // 34 | // Dependencies: 35 | // 36 | // Revision: 37 | // Revision 0.01 - File Created 38 | // Additional Comments: 39 | // 40 | ////////////////////////////////////////////////////////////////////////////////// 41 | 42 | 43 | module sim_chnn_rcvr; 44 | 45 | parameter CHN_NUM = 4; 46 | parameter DATA_WIDTH = 32; // complex data width 47 | parameter C_COEF_FILE = "D:/fir.coe"; 48 | parameter C_COEF_WIDTH = 24; 49 | parameter C_NUM_TAPS = 32; 50 | 51 | parameter C_S_DATA_TDATA_WIDTH = DATA_WIDTH * CHN_NUM; 52 | parameter C_M_DATA_TDATA_WIDTH = C_S_DATA_TDATA_WIDTH; 53 | 54 | reg aclk; 55 | reg aresetn; 56 | reg s_axis_data_tvalid; 57 | reg [C_S_DATA_TDATA_WIDTH - 1 : 0] s_axis_data_tdata; 58 | wire m_axis_data_tvalid; 59 | wire [C_M_DATA_TDATA_WIDTH - 1 : 0] m_axis_data_tdata; 60 | 61 | chnn_rcvr #( 62 | .CHN_NUM(CHN_NUM), 63 | .DATA_WIDTH(DATA_WIDTH), 64 | .C_COEF_FILE(C_COEF_FILE), 65 | .C_COEF_WIDTH(C_COEF_WIDTH), 66 | .C_NUM_TAPS(C_NUM_TAPS) 67 | ) u_chnn_rcvr ( 68 | .aclk(aclk), 69 | .aresetn(aresetn), 70 | .s_axis_data_tvalid(s_axis_data_tvalid), 71 | .s_axis_data_tdata(s_axis_data_tdata), 72 | .m_axis_data_tvalid(m_axis_data_tvalid), 73 | .m_axis_data_tdata(m_axis_data_tdata) 74 | ); 75 | 76 | // Define file handle integer 77 | integer outfile; 78 | 79 | initial begin 80 | // Open file output.dat for writing 81 | outfile = $fopen("D:/output.dat", "w"); 82 | 83 | // Check if file was properly opened and if not, produce error and exit 84 | if (outfile == 0) begin 85 | $display("Error: File, output.dat could not be opened.\nExiting Simulation."); 86 | $finish; 87 | end 88 | 89 | @(posedge m_axis_data_tvalid); 90 | 91 | while(m_axis_data_tvalid == 1) begin 92 | @(posedge aclk) if(m_axis_data_tvalid == 1) begin 93 | $fdisplay(outfile, "%h", m_axis_data_tdata); 94 | end 95 | end 96 | #100; 97 | 98 | // Close file to end monitoring 99 | $fclose(outfile); 100 | 101 | $display("Simulation ended normally"); 102 | $stop; 103 | end 104 | 105 | // Define integers for file handling 106 | integer number_file; 107 | integer i=1; 108 | reg [C_S_DATA_TDATA_WIDTH - 1 : 0] data; 109 | initial begin 110 | aclk = 0; 111 | aresetn = 0; 112 | s_axis_data_tvalid = 0; 113 | s_axis_data_tdata = 0; 114 | 115 | // Open file numbers.txt for reading 116 | number_file = $fopen("D:/data.dat", "r"); 117 | // Produce error and exit if file could not be opened 118 | if (number_file == 0) begin 119 | $display("Error: Failed to open file, data.dat\nExiting Simulation."); 120 | $finish; 121 | end 122 | 123 | #100; 124 | aresetn = 1; 125 | #100; 126 | 127 | // Loop while data is being read from file 128 | // (i will be -1 when end of file or 0 for blank line) 129 | while (i>0) begin 130 | i=$fscanf(number_file, "%h", data); 131 | @(posedge aclk); 132 | #1; 133 | s_axis_data_tdata = data; 134 | s_axis_data_tvalid = 1; 135 | end 136 | // Close out file when finished reading 137 | $fclose(number_file); 138 | s_axis_data_tvalid = 0; 139 | #1000; 140 | end 141 | 142 | 143 | always #5 aclk = ~aclk; 144 | 145 | endmodule 146 | -------------------------------------------------------------------------------- /common/cmult.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | /* 3 | * This module was copied from the Vivado language template. 4 | */ 5 | 6 | // Complex Multiplier 7 | // The following code implements a parameterizable complex multiplier 8 | // The style described uses 3 DSP's to implement the complex multiplier 9 | // taking advantage of the pre-adder, so widths chosen should be less than what the architecture supports or else extra-logic/extra DSPs will be inferred 10 | module cmult # ( 11 | parameter AWIDTH = 16, // size of 1st input of multiplier 12 | parameter BWIDTH = 18 // size of 2nd input of multiplier 13 | ) 14 | ( 15 | input clk, 16 | input signed [AWIDTH-1:0] ar, ai, 17 | input signed [BWIDTH-1:0] br, bi, 18 | output signed [AWIDTH+BWIDTH:0] pr, pi 19 | ); 20 | 21 | reg signed [AWIDTH-1:0] ai_d, ai_dd, ai_ddd, ai_dddd; 22 | reg signed [AWIDTH-1:0] ar_d, ar_dd, ar_ddd, ar_dddd; 23 | reg signed [BWIDTH-1:0] bi_d, bi_dd, bi_ddd, br_d, br_dd, br_ddd; 24 | reg signed [AWIDTH:0] addcommon; 25 | reg signed [BWIDTH:0] addr, addi; 26 | reg signed [AWIDTH+BWIDTH:0] mult0, multr, multi, pr_int, pi_int; 27 | reg signed [AWIDTH+BWIDTH:0] common, commonr1, commonr2; 28 | 29 | always @(posedge clk) 30 | begin 31 | ar_d <= ar; 32 | ar_dd <= ar_d; 33 | ai_d <= ai; 34 | ai_dd <= ai_d; 35 | br_d <= br; 36 | br_dd <= br_d; 37 | br_ddd <= br_dd; 38 | bi_d <= bi; 39 | bi_dd <= bi_d; 40 | bi_ddd <= bi_dd; 41 | end 42 | 43 | // Common factor (ar ai) x bi, shared for the calculations of the real and imaginary final products 44 | // 45 | always @(posedge clk) 46 | begin 47 | addcommon <= ar_d - ai_d; 48 | mult0 <= addcommon * bi_dd; 49 | common <= mult0; 50 | end 51 | 52 | // Real product 53 | // 54 | always @(posedge clk) 55 | begin 56 | ar_ddd <= ar_dd; 57 | ar_dddd <= ar_ddd; 58 | addr <= br_ddd - bi_ddd; 59 | multr <= addr * ar_dddd; 60 | commonr1 <= common; 61 | pr_int <= multr + commonr1; 62 | end 63 | 64 | // Imaginary product 65 | // 66 | always @(posedge clk) 67 | begin 68 | ai_ddd <= ai_dd; 69 | ai_dddd <= ai_ddd; 70 | addi <= br_ddd + bi_ddd; 71 | multi <= addi * ai_dddd; 72 | commonr2 <= common; 73 | pi_int <= multi + commonr2; 74 | end 75 | 76 | assign pr = pr_int; 77 | assign pi = pi_int; 78 | 79 | endmodule // cmult 80 | // The following is an instantiation template for cmult 81 | /* 82 | cmult # (.AWIDTH(16), 83 | .BWIDTH(18) 84 | ) 85 | your_instance_name 86 | ( 87 | .clk(clk), 88 | .ar(ar), 89 | .ai(ai), 90 | .br(br), 91 | .bi(bi), 92 | .pr(pr), 93 | .pi(pi) 94 | ); 95 | */ 96 | 97 | 98 | -------------------------------------------------------------------------------- /common/pipe_delay.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | /* 3 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * 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, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | // Company: 25 | // Engineer: 26 | // Jackie Wang(falwat@163.com) 27 | // 28 | // Create Date: 2016/01/03 08:32:36 29 | // Design Name: 30 | // Module Name: pipe_delay 31 | // Project Name: 32 | // Target Devices: 33 | // Tool Versions: 34 | // Description: 35 | // This module realizes the data from inport `din` to outport `dout` after 36 | // `DELAY_CLKS` clock delay. 37 | // 38 | // Dependencies: 39 | // 40 | // Revision: 41 | // Revision 0.01 - File Created 42 | // Additional Comments: 43 | // 44 | ////////////////////////////////////////////////////////////////////////////////// 45 | 46 | /* instance template 47 | pipe_delay #( 48 | .DATA_WIDTH(16), // DATA_WIDTH = 1,2... 49 | .DELAY_CLKS(2) // DELAY_CLKS = 0,1,... 50 | ) instance_name ( 51 | .rst(rst), // input wire rst; 52 | .clk(clk), // input wire clk; 53 | .clk_en(clk_en), // input wire clk_en; 54 | .din(din), // input wire [DATA_WIDTH-1:0] din; 55 | .dout(dout) // output wire [DATA_WIDTH-1:0] dout; 56 | ); 57 | 58 | */ 59 | module pipe_delay #( 60 | parameter DATA_WIDTH = 16, // DATA_WIDTH = 1,2... 61 | parameter integer DELAY_CLKS = 2 // DELAY_CLKS = 0,1,... 62 | ) 63 | ( 64 | input rst, 65 | input clk, 66 | input clk_en, 67 | input [DATA_WIDTH-1:0] din, 68 | output [DATA_WIDTH-1:0] dout 69 | ); 70 | 71 | genvar iter; 72 | generate 73 | if(DELAY_CLKS==0) begin: clk0_gen 74 | assign dout = din; 75 | end else if(DELAY_CLKS==1) begin: clk1_gen 76 | reg [DATA_WIDTH-1:0] reg_tmp; 77 | assign dout = reg_tmp; 78 | always @(posedge clk) 79 | if(rst) 80 | reg_tmp <= {DATA_WIDTH{1'b0}}; 81 | else if(clk_en) 82 | reg_tmp <= din; 83 | end else begin: clkm_gen 84 | reg [DATA_WIDTH-1:0] reg_tmp[0:DELAY_CLKS-1]; 85 | assign dout = reg_tmp[DELAY_CLKS-1]; 86 | for (iter=0; iter < DELAY_CLKS; iter=iter+1) 87 | begin: loop_gen 88 | always @(posedge clk) 89 | if(rst) 90 | reg_tmp[iter] <= {DATA_WIDTH{1'b0}}; 91 | else if(clk_en) 92 | if(iter==0) 93 | reg_tmp[iter] <= din; 94 | else 95 | reg_tmp[iter] <= reg_tmp[iter-1]; 96 | end 97 | end 98 | endgenerate 99 | 100 | endmodule 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /common/rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 2021/11/26 17:46:11 7 | // Design Name: 8 | // Module Name: rom 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | /* instance template 24 | rom #( 25 | .ROM_TYPE("block"), // ROM_TYPE = "block" or "distributed" 26 | .ROM_WIDTH(32), // data out width 27 | .ROM_DEPTH(256), 28 | .ROM_ADDR_BITS(8), // address bit width 29 | .DATA_FILE("") // please assign a data file 30 | ) instance_name ( 31 | .clk(clk), 32 | .clk_en(clk_en), 33 | .addr(addr), // wire [ROM_ADDR_BITS-1:0] addr; 34 | .dout(dout) // wire [ROM_WIDTH-1:0] dout; 35 | ); 36 | */ 37 | 38 | 39 | module rom #( 40 | parameter ROM_TYPE = "block", // ROM_TYPE = "block" or "distributed" 41 | parameter ROM_WIDTH = 32, // data out width; 42 | parameter ROM_DEPTH = 64, 43 | parameter ROM_ADDR_BITS = 6, 44 | parameter DATA_FILE = "" // please assign a data file 45 | ) 46 | ( 47 | input clk, 48 | input clk_en, 49 | input [ROM_ADDR_BITS-1:0] addr, 50 | output reg [ROM_WIDTH-1:0] dout 51 | ); 52 | 53 | 54 | (* rom_style= ROM_TYPE *) 55 | reg [ROM_WIDTH-1:0] mems [ROM_DEPTH-1:0]; 56 | 57 | initial 58 | $readmemh(DATA_FILE, mems, 0, ROM_DEPTH-1); 59 | 60 | always @(posedge clk) 61 | if (clk_en) 62 | dout <= mems[addr]; 63 | 64 | endmodule 65 | -------------------------------------------------------------------------------- /fir/create_project.tcl: -------------------------------------------------------------------------------- 1 | #***************************************************************************************** 2 | # Vivado (TM) v2018.3 (64-bit) 3 | # 4 | # create_project.tcl: Tcl script for re-creating project 'fir' 5 | # 6 | # Generated by Vivado on Fri Nov 26 13:27:06 +0800 2021 7 | # IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 8 | # 9 | # This file contains the Vivado Tcl commands for re-creating the project to the state* 10 | # when this script was generated. In order to re-create the project, please source this 11 | # file in the Vivado Tcl Shell. 12 | # 13 | # * Note that the runs in the created project will be configured the same way as the 14 | # original project, however they will not be launched automatically. To regenerate the 15 | # run results please launch the synthesis/implementation runs as needed. 16 | # 17 | #***************************************************************************************** 18 | # NOTE: In order to use this script for source control purposes, please make sure that the 19 | # following files are added to the source control system:- 20 | # 21 | # 1. This project restoration tcl script (create_project.tcl) that was generated. 22 | # 23 | # 2. The following source(s) files that were local or imported into the original project. 24 | # (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) 25 | # 26 | # 27 | # 28 | # 3. The following remote source files that were added to the original project:- 29 | # 30 | # "C:/Users/falwa/workspace/code_repo/fir/multadd.v" 31 | # "C:/Users/falwa/workspace/code_repo/common/pipe_delay.v" 32 | # "C:/Users/falwa/workspace/code_repo/fir/fir.v" 33 | # "C:/Users/falwa/workspace/code_repo/fir/sim_fir.v" 34 | # 35 | #***************************************************************************************** 36 | 37 | # Set the reference directory for source file relative paths (by default the value is script directory path) 38 | set origin_dir "." 39 | 40 | # Use origin directory path location variable, if specified in the tcl shell 41 | if { [info exists ::origin_dir_loc] } { 42 | set origin_dir $::origin_dir_loc 43 | } 44 | 45 | # Set the project name 46 | set _xil_proj_name_ "fir" 47 | 48 | # Use project name variable, if specified in the tcl shell 49 | if { [info exists ::user_project_name] } { 50 | set _xil_proj_name_ $::user_project_name 51 | } 52 | 53 | variable script_file 54 | set script_file "create_project.tcl" 55 | 56 | # Help information for this script 57 | proc print_help {} { 58 | variable script_file 59 | puts "\nDescription:" 60 | puts "Recreate a Vivado project from this script. The created project will be" 61 | puts "functionally equivalent to the original project for which this script was" 62 | puts "generated. The script contains commands for creating a project, filesets," 63 | puts "runs, adding/importing sources and setting properties on various objects.\n" 64 | puts "Syntax:" 65 | puts "$script_file" 66 | puts "$script_file -tclargs \[--origin_dir \]" 67 | puts "$script_file -tclargs \[--project_name \]" 68 | puts "$script_file -tclargs \[--help\]\n" 69 | puts "Usage:" 70 | puts "Name Description" 71 | puts "-------------------------------------------------------------------------" 72 | puts "\[--origin_dir \] Determine source file paths wrt this path. Default" 73 | puts " origin_dir path value is \".\", otherwise, the value" 74 | puts " that was set with the \"-paths_relative_to\" switch" 75 | puts " when this script was generated.\n" 76 | puts "\[--project_name \] Create project with the specified name. Default" 77 | puts " name is the name of the project from where this" 78 | puts " script was generated.\n" 79 | puts "\[--help\] Print help information for this script" 80 | puts "-------------------------------------------------------------------------\n" 81 | exit 0 82 | } 83 | 84 | if { $::argc > 0 } { 85 | for {set i 0} {$i < $::argc} {incr i} { 86 | set option [string trim [lindex $::argv $i]] 87 | switch -regexp -- $option { 88 | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } 89 | "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } 90 | "--help" { print_help } 91 | default { 92 | if { [regexp {^-} $option] } { 93 | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" 94 | return 1 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | # Set the directory path for the original project from where this script was exported 102 | set orig_proj_dir "[file normalize "$origin_dir/proj"]" 103 | 104 | # Create project 105 | create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7vx690tffg1761-2 106 | 107 | # Set the directory path for the new project 108 | set proj_dir [get_property directory [current_project]] 109 | 110 | # Set project properties 111 | set obj [current_project] 112 | set_property -name "board_part" -value "xilinx.com:vc709:part0:1.8" -objects $obj 113 | set_property -name "default_lib" -value "xil_defaultlib" -objects $obj 114 | set_property -name "dsa.accelerator_binary_content" -value "bitstream" -objects $obj 115 | set_property -name "dsa.accelerator_binary_format" -value "xclbin2" -objects $obj 116 | set_property -name "dsa.board_id" -value "vc709" -objects $obj 117 | set_property -name "dsa.description" -value "Vivado generated DSA" -objects $obj 118 | set_property -name "dsa.dr_bd_base_address" -value "0" -objects $obj 119 | set_property -name "dsa.emu_dir" -value "emu" -objects $obj 120 | set_property -name "dsa.flash_interface_type" -value "bpix16" -objects $obj 121 | set_property -name "dsa.flash_offset_address" -value "0" -objects $obj 122 | set_property -name "dsa.flash_size" -value "1024" -objects $obj 123 | set_property -name "dsa.host_architecture" -value "x86_64" -objects $obj 124 | set_property -name "dsa.host_interface" -value "pcie" -objects $obj 125 | set_property -name "dsa.num_compute_units" -value "60" -objects $obj 126 | set_property -name "dsa.platform_state" -value "pre_synth" -objects $obj 127 | set_property -name "dsa.vendor" -value "xilinx" -objects $obj 128 | set_property -name "dsa.version" -value "0.0" -objects $obj 129 | set_property -name "enable_vhdl_2008" -value "1" -objects $obj 130 | set_property -name "ip_cache_permissions" -value "read write" -objects $obj 131 | set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj 132 | set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj 133 | set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj 134 | set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj 135 | set_property -name "simulator_language" -value "Mixed" -objects $obj 136 | set_property -name "webtalk.xsim_launch_sim" -value "28" -objects $obj 137 | 138 | # Create 'sources_1' fileset (if not found) 139 | if {[string equal [get_filesets -quiet sources_1] ""]} { 140 | create_fileset -srcset sources_1 141 | } 142 | 143 | # Set 'sources_1' fileset object 144 | set obj [get_filesets sources_1] 145 | set files [list \ 146 | [file normalize "${origin_dir}/multadd.v"] \ 147 | [file normalize "${origin_dir}/../common/pipe_delay.v"] \ 148 | [file normalize "${origin_dir}/fir.v"] \ 149 | ] 150 | add_files -norecurse -fileset $obj $files 151 | 152 | # Set 'sources_1' fileset file properties for remote files 153 | # None 154 | 155 | # Set 'sources_1' fileset file properties for local files 156 | # None 157 | 158 | # Set 'sources_1' fileset properties 159 | set obj [get_filesets sources_1] 160 | set_property -name "top" -value "fir" -objects $obj 161 | 162 | # Create 'constrs_1' fileset (if not found) 163 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 164 | create_fileset -constrset constrs_1 165 | } 166 | 167 | # Set 'constrs_1' fileset object 168 | set obj [get_filesets constrs_1] 169 | 170 | # Empty (no sources present) 171 | 172 | # Set 'constrs_1' fileset properties 173 | set obj [get_filesets constrs_1] 174 | 175 | # Create 'sim_1' fileset (if not found) 176 | if {[string equal [get_filesets -quiet sim_1] ""]} { 177 | create_fileset -simset sim_1 178 | } 179 | 180 | # Set 'sim_1' fileset object 181 | set obj [get_filesets sim_1] 182 | set files [list \ 183 | [file normalize "${origin_dir}/sim_fir.v"] \ 184 | ] 185 | add_files -norecurse -fileset $obj $files 186 | 187 | # Set 'sim_1' fileset file properties for remote files 188 | # None 189 | 190 | # Set 'sim_1' fileset file properties for local files 191 | # None 192 | 193 | # Set 'sim_1' fileset properties 194 | set obj [get_filesets sim_1] 195 | set_property -name "top" -value "sim_fir" -objects $obj 196 | set_property -name "top_auto_set" -value "0" -objects $obj 197 | set_property -name "top_lib" -value "xil_defaultlib" -objects $obj 198 | 199 | # Set 'utils_1' fileset object 200 | set obj [get_filesets utils_1] 201 | # Empty (no sources present) 202 | 203 | # Set 'utils_1' fileset properties 204 | set obj [get_filesets utils_1] 205 | 206 | # Create 'synth_1' run (if not found) 207 | if {[string equal [get_runs -quiet synth_1] ""]} { 208 | create_run -name synth_1 -part xc7vx690tffg1761-2 -flow {Vivado Synthesis 2018} -strategy "Synthesis_OOC" -report_strategy {No Reports} -constrset constrs_1 209 | } else { 210 | set_property strategy "Synthesis_OOC" [get_runs synth_1] 211 | set_property flow "Vivado Synthesis 2018" [get_runs synth_1] 212 | } 213 | set obj [get_runs synth_1] 214 | set_property set_report_strategy_name 1 $obj 215 | set_property report_strategy {Vivado Synthesis Default Reports} $obj 216 | set_property set_report_strategy_name 0 $obj 217 | # Create 'synth_1_synth_report_utilization_0' report (if not found) 218 | if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { 219 | create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 220 | } 221 | set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] 222 | if { $obj != "" } { 223 | set_property -name "display_name" -value "synth_1_synth_report_utilization_0" -objects $obj 224 | 225 | } 226 | set obj [get_runs synth_1] 227 | set_property -name "strategy" -value "Synthesis_OOC" -objects $obj 228 | 229 | # set the current synth run 230 | current_run -synthesis [get_runs synth_1] 231 | 232 | # Create 'impl_1' run (if not found) 233 | if {[string equal [get_runs -quiet impl_1] ""]} { 234 | create_run -name impl_1 -part xc7vx690tffg1761-2 -flow {Vivado Implementation 2018} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 235 | } else { 236 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 237 | set_property flow "Vivado Implementation 2018" [get_runs impl_1] 238 | } 239 | set obj [get_runs impl_1] 240 | set_property set_report_strategy_name 1 $obj 241 | set_property report_strategy {Vivado Implementation Default Reports} $obj 242 | set_property set_report_strategy_name 0 $obj 243 | # Create 'impl_1_init_report_timing_summary_0' report (if not found) 244 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { 245 | create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 246 | } 247 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] 248 | if { $obj != "" } { 249 | set_property -name "is_enabled" -value "0" -objects $obj 250 | set_property -name "display_name" -value "impl_1_init_report_timing_summary_0" -objects $obj 251 | 252 | } 253 | # Create 'impl_1_opt_report_drc_0' report (if not found) 254 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { 255 | create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 256 | } 257 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] 258 | if { $obj != "" } { 259 | set_property -name "display_name" -value "impl_1_opt_report_drc_0" -objects $obj 260 | 261 | } 262 | # Create 'impl_1_opt_report_timing_summary_0' report (if not found) 263 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { 264 | create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 265 | } 266 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] 267 | if { $obj != "" } { 268 | set_property -name "is_enabled" -value "0" -objects $obj 269 | set_property -name "display_name" -value "impl_1_opt_report_timing_summary_0" -objects $obj 270 | 271 | } 272 | # Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) 273 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { 274 | create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 275 | } 276 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] 277 | if { $obj != "" } { 278 | set_property -name "is_enabled" -value "0" -objects $obj 279 | set_property -name "display_name" -value "impl_1_power_opt_report_timing_summary_0" -objects $obj 280 | 281 | } 282 | # Create 'impl_1_place_report_io_0' report (if not found) 283 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { 284 | create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 285 | } 286 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] 287 | if { $obj != "" } { 288 | set_property -name "display_name" -value "impl_1_place_report_io_0" -objects $obj 289 | 290 | } 291 | # Create 'impl_1_place_report_utilization_0' report (if not found) 292 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { 293 | create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 294 | } 295 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] 296 | if { $obj != "" } { 297 | set_property -name "display_name" -value "impl_1_place_report_utilization_0" -objects $obj 298 | 299 | } 300 | # Create 'impl_1_place_report_control_sets_0' report (if not found) 301 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { 302 | create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 303 | } 304 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] 305 | if { $obj != "" } { 306 | set_property -name "display_name" -value "impl_1_place_report_control_sets_0" -objects $obj 307 | 308 | } 309 | # Create 'impl_1_place_report_incremental_reuse_0' report (if not found) 310 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { 311 | create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 312 | } 313 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] 314 | if { $obj != "" } { 315 | set_property -name "is_enabled" -value "0" -objects $obj 316 | set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_0" -objects $obj 317 | 318 | } 319 | # Create 'impl_1_place_report_incremental_reuse_1' report (if not found) 320 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { 321 | create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 322 | } 323 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] 324 | if { $obj != "" } { 325 | set_property -name "is_enabled" -value "0" -objects $obj 326 | set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_1" -objects $obj 327 | 328 | } 329 | # Create 'impl_1_place_report_timing_summary_0' report (if not found) 330 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { 331 | create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 332 | } 333 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] 334 | if { $obj != "" } { 335 | set_property -name "is_enabled" -value "0" -objects $obj 336 | set_property -name "display_name" -value "impl_1_place_report_timing_summary_0" -objects $obj 337 | 338 | } 339 | # Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) 340 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { 341 | create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 342 | } 343 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] 344 | if { $obj != "" } { 345 | set_property -name "is_enabled" -value "0" -objects $obj 346 | set_property -name "display_name" -value "impl_1_post_place_power_opt_report_timing_summary_0" -objects $obj 347 | 348 | } 349 | # Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) 350 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { 351 | create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 352 | } 353 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] 354 | if { $obj != "" } { 355 | set_property -name "is_enabled" -value "0" -objects $obj 356 | set_property -name "display_name" -value "impl_1_phys_opt_report_timing_summary_0" -objects $obj 357 | 358 | } 359 | # Create 'impl_1_route_report_drc_0' report (if not found) 360 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { 361 | create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 362 | } 363 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] 364 | if { $obj != "" } { 365 | set_property -name "display_name" -value "impl_1_route_report_drc_0" -objects $obj 366 | 367 | } 368 | # Create 'impl_1_route_report_methodology_0' report (if not found) 369 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { 370 | create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 371 | } 372 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] 373 | if { $obj != "" } { 374 | set_property -name "display_name" -value "impl_1_route_report_methodology_0" -objects $obj 375 | 376 | } 377 | # Create 'impl_1_route_report_power_0' report (if not found) 378 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { 379 | create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 380 | } 381 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] 382 | if { $obj != "" } { 383 | set_property -name "display_name" -value "impl_1_route_report_power_0" -objects $obj 384 | 385 | } 386 | # Create 'impl_1_route_report_route_status_0' report (if not found) 387 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { 388 | create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 389 | } 390 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] 391 | if { $obj != "" } { 392 | set_property -name "display_name" -value "impl_1_route_report_route_status_0" -objects $obj 393 | 394 | } 395 | # Create 'impl_1_route_report_timing_summary_0' report (if not found) 396 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { 397 | create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 398 | } 399 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] 400 | if { $obj != "" } { 401 | set_property -name "display_name" -value "impl_1_route_report_timing_summary_0" -objects $obj 402 | 403 | } 404 | # Create 'impl_1_route_report_incremental_reuse_0' report (if not found) 405 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { 406 | create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 407 | } 408 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] 409 | if { $obj != "" } { 410 | set_property -name "display_name" -value "impl_1_route_report_incremental_reuse_0" -objects $obj 411 | 412 | } 413 | # Create 'impl_1_route_report_clock_utilization_0' report (if not found) 414 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { 415 | create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 416 | } 417 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] 418 | if { $obj != "" } { 419 | set_property -name "display_name" -value "impl_1_route_report_clock_utilization_0" -objects $obj 420 | 421 | } 422 | # Create 'impl_1_route_report_bus_skew_0' report (if not found) 423 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { 424 | create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 425 | } 426 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] 427 | if { $obj != "" } { 428 | set_property -name "display_name" -value "impl_1_route_report_bus_skew_0" -objects $obj 429 | 430 | } 431 | # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) 432 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { 433 | create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 434 | } 435 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] 436 | if { $obj != "" } { 437 | set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_timing_summary_0" -objects $obj 438 | 439 | } 440 | # Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) 441 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { 442 | create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 443 | } 444 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] 445 | if { $obj != "" } { 446 | set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_bus_skew_0" -objects $obj 447 | 448 | } 449 | set obj [get_runs impl_1] 450 | set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj 451 | set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj 452 | set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj 453 | 454 | # set the current impl run 455 | current_run -implementation [get_runs impl_1] 456 | 457 | puts "INFO: Project created:${_xil_proj_name_}" 458 | set obj [get_dashboards default_dashboard] 459 | 460 | # Create 'drc_1' gadget (if not found) 461 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] ""]} { 462 | create_dashboard_gadget -name {drc_1} -type drc 463 | } 464 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] 465 | set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj 466 | 467 | # Create 'methodology_1' gadget (if not found) 468 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] ""]} { 469 | create_dashboard_gadget -name {methodology_1} -type methodology 470 | } 471 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] 472 | set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj 473 | 474 | # Create 'power_1' gadget (if not found) 475 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] ""]} { 476 | create_dashboard_gadget -name {power_1} -type power 477 | } 478 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] 479 | set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj 480 | 481 | # Create 'timing_1' gadget (if not found) 482 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] ""]} { 483 | create_dashboard_gadget -name {timing_1} -type timing 484 | } 485 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] 486 | set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj 487 | 488 | # Create 'utilization_1' gadget (if not found) 489 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] ""]} { 490 | create_dashboard_gadget -name {utilization_1} -type utilization 491 | } 492 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] 493 | set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj 494 | set_property -name "run.step" -value "synth_design" -objects $obj 495 | set_property -name "run.type" -value "synthesis" -objects $obj 496 | 497 | # Create 'utilization_2' gadget (if not found) 498 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] ""]} { 499 | create_dashboard_gadget -name {utilization_2} -type utilization 500 | } 501 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] 502 | set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj 503 | 504 | move_dashboard_gadget -name {utilization_1} -row 0 -col 0 505 | move_dashboard_gadget -name {power_1} -row 1 -col 0 506 | move_dashboard_gadget -name {drc_1} -row 2 -col 0 507 | move_dashboard_gadget -name {timing_1} -row 0 -col 1 508 | move_dashboard_gadget -name {utilization_2} -row 1 -col 1 509 | move_dashboard_gadget -name {methodology_1} -row 2 -col 1 510 | # Set current dashboard to 'default_dashboard' 511 | current_dashboard default_dashboard 512 | -------------------------------------------------------------------------------- /fir/data_gen.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import numpy.random as random 3 | import matplotlib.pyplot as plt 4 | 5 | # Calculate two complement of a list 6 | def complement2(lst, bit_width): 7 | return [int(n) if n > 0 else int(n + 2 ** bit_width) for n in lst] 8 | 9 | def num2hex(lst, field_width): 10 | return ['{0:0{1}x}'.format(int(v), field_width) for v in lst] 11 | 12 | data_width = 16 13 | n = 1000 14 | s = random.randn(n) 15 | s = s / max(np.abs(s)) 16 | s = s * (2 ** (data_width - 1) - 1) 17 | 18 | s = complement2(s, data_width) 19 | plt.figure() 20 | plt.hist(s,64) 21 | # plt.plot(h) 22 | plt.show() 23 | 24 | # Generate coefficients for FIR filter 25 | filename = 'D:/data.dat' 26 | with open(filename, 'w') as f: 27 | field_width = int(np.ceil(data_width / 4)) 28 | data = num2hex(s, field_width) 29 | f.write('\n'.join(data)) 30 | print('INFO: the data file for test has been created. Filename: ', filename) 31 | 32 | -------------------------------------------------------------------------------- /fir/fir.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 2021/11/08 09:52:43 7 | // Design Name: 8 | // Module Name: fir 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | /** 23 | fir #( 24 | .C_S_DATA_TDATA_WIDTH(16), 25 | .C_M_DATA_TDATA_WIDTH(16), 26 | .C_RELOAD_TDATA_WIDTH(16), 27 | .DATA_PATH(DATA_PATH), 28 | .C_COEF_FILE(""), 29 | .C_NUM_TAPS(4) 30 | ) instance_name ( 31 | .aclk(aclk), 32 | .aresetn(aresetn), 33 | .s_axis_reload_tvalid(s_axis_reload_tvalid), 34 | .s_axis_reload_tlast(s_axis_reload_tlast), 35 | .s_axis_reload_tdata(s_axis_reload_tdata), 36 | .s_axis_data_tvalid(s_axis_data_tvalid), 37 | .s_axis_data_tdata(s_axis_data_tdata), 38 | .m_axis_data_tvalid(m_axis_data_tvalid), 39 | .m_axis_data_tdata(m_axis_data_tdata) 40 | ); 41 | */ 42 | 43 | module fir #( 44 | parameter C_S_DATA_TDATA_WIDTH = 16, 45 | parameter C_M_DATA_TDATA_WIDTH = 16, 46 | parameter C_RELOAD_TDATA_WIDTH = 16, 47 | parameter DATA_PATH = 1, 48 | parameter C_COEF_FILE = "", 49 | // parameter C_SYMMETRY = 0, // 0: non-symmetry, 1: symmetry. 50 | // parameter C_NUM_FILTS = 1, 51 | parameter C_NUM_TAPS = 4 52 | )( 53 | input aclk, 54 | input aresetn, 55 | input s_axis_reload_tvalid, 56 | input s_axis_reload_tlast, 57 | input [C_RELOAD_TDATA_WIDTH - 1 : 0] s_axis_reload_tdata, // fix{N}_{N-1} 58 | input s_axis_data_tvalid, 59 | input [C_S_DATA_TDATA_WIDTH * DATA_PATH - 1 : 0] s_axis_data_tdata, 60 | output m_axis_data_tvalid, 61 | output [C_M_DATA_TDATA_WIDTH * DATA_PATH - 1 : 0]m_axis_data_tdata 62 | ); 63 | 64 | // The following function calculates the address width based on specified RAM depth 65 | function integer clogb2; 66 | input integer depth; 67 | for (clogb2=0; depth>0; clogb2=clogb2+1) 68 | depth = depth >> 1; 69 | endfunction 70 | 71 | localparam P_WIDTH = C_S_DATA_TDATA_WIDTH + C_RELOAD_TDATA_WIDTH; 72 | reg [clogb2(C_RELOAD_TDATA_WIDTH - 1) - 1 : 0] coe_idxr; 73 | reg [C_RELOAD_TDATA_WIDTH - 1 :0] coe_vector[C_NUM_TAPS - 1 : 0]; 74 | always @(posedge aclk) begin 75 | if(~aresetn) begin 76 | coe_idxr <= 0; 77 | end else if(s_axis_reload_tvalid) begin 78 | if(s_axis_reload_tlast) begin 79 | coe_idxr <= 0; 80 | end else begin 81 | coe_idxr <= coe_idxr + 1; 82 | end 83 | end else begin 84 | coe_idxr <= coe_idxr; 85 | end 86 | end 87 | 88 | // The following code either initializes the memory values to a specified file or to all zeros to match hardware 89 | generate 90 | if (C_COEF_FILE != "") begin: use_coef_file 91 | initial begin 92 | $readmemh(C_COEF_FILE, coe_vector, 0, C_NUM_TAPS-1); 93 | end 94 | end else begin: init_bram_to_zero 95 | integer ram_index; 96 | initial begin 97 | for (ram_index = 0; ram_index < C_NUM_TAPS; ram_index = ram_index + 1) begin 98 | coe_vector[ram_index] = {C_RELOAD_TDATA_WIDTH{1'b0}}; 99 | end 100 | end 101 | end 102 | endgenerate 103 | 104 | always @(posedge aclk) begin 105 | if(s_axis_reload_tvalid && coe_idxr < C_NUM_TAPS) begin 106 | coe_vector[coe_idxr] <= s_axis_reload_tdata; 107 | end 108 | end 109 | 110 | wire rst = ~aresetn; 111 | 112 | genvar i, k; 113 | generate 114 | for(k = 0; k < DATA_PATH; k = k + 1) begin: gen_dpath 115 | wire [P_WIDTH - 1 : 0] p[C_NUM_TAPS : 0]; 116 | assign p[0] = 0; 117 | for(i = 0; i < C_NUM_TAPS; i = i + 1) begin: gen_node 118 | multadd # ( 119 | .AWIDTH(C_S_DATA_TDATA_WIDTH), 120 | .BWIDTH(C_RELOAD_TDATA_WIDTH), 121 | .PIN_WIDTH(P_WIDTH), 122 | .POUT_WIDTH(P_WIDTH) 123 | ) 124 | u_multadd 125 | ( 126 | .clk(aclk), 127 | .ce(s_axis_data_tvalid), 128 | .rst(rst), 129 | .a_in(s_axis_data_tdata[k * C_S_DATA_TDATA_WIDTH +: C_S_DATA_TDATA_WIDTH]), 130 | .b_in(coe_vector[C_NUM_TAPS - 1 - i]), 131 | .p_in(p[i]), 132 | .p_out(p[i+1]) 133 | ); 134 | end 135 | assign m_axis_data_tdata[k * C_M_DATA_TDATA_WIDTH +: C_M_DATA_TDATA_WIDTH] = 136 | p[C_NUM_TAPS][P_WIDTH-2 -: C_M_DATA_TDATA_WIDTH]; 137 | end 138 | endgenerate 139 | 140 | pipe_delay #( 141 | .DATA_WIDTH(1), // DATA_WIDTH = 1,2... 142 | .DELAY_CLKS(1) // DELAY_CLKS = 0,1,... 143 | ) u_pipe_delay ( 144 | .rst(rst), // input wire rst; 145 | .clk(aclk), // input wire clk; 146 | .clk_en(1'b1), // input wire clk_en; 147 | .din(s_axis_data_tvalid), // input wire [DATA_WIDTH-1:0] din; 148 | .dout(m_axis_data_tvalid) // output wire [DATA_WIDTH-1:0] dout; 149 | ); 150 | 151 | endmodule 152 | -------------------------------------------------------------------------------- /fir/fir_coe_gen.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy import signal 3 | import matplotlib.pyplot as plt 4 | 5 | # Calculate two complement of a list 6 | def complement2(lst, bit_width): 7 | return [int(n) if n > 0 else int(n + 2 ** bit_width) for n in lst] 8 | 9 | def num2hex(lst, field_width): 10 | return ['{0:0{1}x}'.format(int(v), field_width) for v in lst] 11 | 12 | coe_width = 24 13 | # Design FIR Filter 14 | cutoff = 0.125 # Desired cutoff digital frequency 15 | trans_width = cutoff / 10 # Width of transition from pass band to stop band 16 | numtaps = 63 # Size of the FIR filter. 17 | taps = signal.remez(numtaps, [0, cutoff - trans_width, cutoff + trans_width, 0.5],[1, 0]) 18 | 19 | # b = signal.firwin(20, 0.125, window=('kaiser', 8)) 20 | w, h = signal.freqz(taps) 21 | ax1 = plt.subplot(211) 22 | ax1.set_title('Digital filter frequency response') 23 | ax1.plot(w, 20 * np.log10(abs(h)), 'b') 24 | ax1.set_ylabel('Amplitude [dB]', color='b') 25 | ax1.set_xlabel('Frequency [rad/sample]') 26 | ax2 = ax1.twinx() 27 | angles = np.unwrap(np.angle(h)) 28 | ax2.plot(w, angles, 'g') 29 | ax2.set_ylabel('Angle (radians)', color='g') 30 | ax2.grid() 31 | ax2.axis('tight') 32 | ax3 = plt.subplot(212) 33 | ax3.plot(taps) 34 | plt.show() 35 | 36 | # Generate coefficients for FIR filter 37 | filename = 'D:/fir.coe' 38 | with open(filename, 'w') as f: 39 | taps = taps * 2 ** (coe_width - 1) 40 | taps_compl2 = complement2(taps, coe_width) 41 | field_width = int(np.ceil(coe_width / 4)) 42 | coes = num2hex(taps_compl2, field_width) 43 | f.write('\n'.join(coes)) 44 | print('INFO: Coefficients File for FIR filter has been created. Filename: ', filename) 45 | -------------------------------------------------------------------------------- /fir/image/df_fir.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falwat/code_repo/cb72281f9c58a4d48d2b15299823f9f7160cf52f/fir/image/df_fir.PNG -------------------------------------------------------------------------------- /fir/image/fir_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falwat/code_repo/cb72281f9c58a4d48d2b15299823f9f7160cf52f/fir/image/fir_1.PNG -------------------------------------------------------------------------------- /fir/multadd.v: -------------------------------------------------------------------------------- 1 | 2 | // This can be packed into 1 DSP block (Ultrascale architecture) 3 | // Make sure the widths are less than what is supported by the architecture 4 | // p_out = p_in + a_in * b_in 5 | module multadd #( 6 | parameter AWIDTH = 16, // Width of multiplier's 1st input 7 | BWIDTH = 16, // Width of multiplier's 2nd input 8 | PIN_WIDTH = 32, // Width of Adder input 9 | POUT_WIDTH = 33 // Output width 10 | )( 11 | input clk, // Clock 12 | input ce, // Clock enable 13 | input rst, // Reset 14 | input signed [AWIDTH-1:0] a_in, // Multipler input 15 | input signed [BWIDTH-1:0] b_in, // Multiplier input 16 | input signed [PIN_WIDTH-1:0] p_in, // Adder input 17 | output signed [POUT_WIDTH-1:0] p_out // p_out(n) = p_in(n-1) + a_in(n-1) * b_in 18 | ); 19 | 20 | reg signed [POUT_WIDTH-1:0] p_out_r; 21 | 22 | always @ (posedge clk) begin 23 | if(rst) begin 24 | p_out_r <= 0; 25 | end else begin 26 | if(ce) begin 27 | p_out_r <= a_in * b_in + p_in; 28 | end 29 | end 30 | end 31 | assign p_out = p_out_r; 32 | 33 | endmodule 34 | /* 35 | The following is an instantation template for mult_add_3 36 | 37 | multadd # ( 38 | .AWIDTH(AWIDTH), 39 | .BWIDTH(BWIDTH), 40 | .PIN_WIDTH(PIN_WIDTH), 41 | .POUT_WIDTH(POUT_WIDTH) 42 | ) 43 | your_instance_name 44 | ( 45 | .clk(clk), 46 | .ce(ce), 47 | .rst(rst), 48 | .a_in(a), 49 | .b_in(b), 50 | .p_in(c), 51 | .a_out(a_out), 52 | .p_out(p) 53 | ); 54 | */ 55 | 56 | -------------------------------------------------------------------------------- /fir/readme_zh.md: -------------------------------------------------------------------------------- 1 | # FIR 滤波器模块设计 2 | 3 | ## 概述 4 | 5 | 该工程实现了一个单速率(single-rate)有限冲激响应(FIR)滤波器模块的设计. 单速率FIR滤波器完成如下公式所示的卷积运算: 6 | 7 | $$ 8 | y(k) = \sum_{n=0}^{N-1}h(n)x(k-n) 9 | $$ 10 | 11 | 下图为直接型FIR滤波器的常规结构, 该图便于理解FIR滤波器的处理流程, 但实际在FPGA上的设计实现并不采用此方法 *(截取自[pg149-fir-compiler.pdf](https://www.xilinx.com/support/documentation/ip_documentation/fir_compiler/v7_2/pg149-fir-compiler.pdf))*. 12 | 13 | ![fir_1.png](./image/fir_1.png) 14 | 15 | 下图给出直接型FIR滤波器的变换形式, 这里采用此方法完成FIR滤波器的设计. *(截取自[pg149-fir-compiler.pdf](https://www.xilinx.com/support/documentation/ip_documentation/fir_compiler/v7_2/pg149-fir-compiler.pdf))*. 16 | ![df_fir.png](./image/df_fir.png) 17 | 18 | ### 创建工程 19 | 20 | - 使用`git`工具克隆此仓库. 21 | 22 | ```sh 23 | git clone https://github.com/falwat/code_repo.git 24 | ``` 25 | 26 | - 打开`vivado tcl shell`, 使用`cd`命令切换至`fir`目录 27 | - 运行`source ./create_project.tcl`,创建测试工程 28 | ```sh 29 | cd <仓库所在文件夹/code_repo/fir> 30 | source ./create_project.tcl 31 | ``` 32 | 33 | ### 34 | 35 | 文件|说明 36 | -|- 37 | [./create_project.tcl](./create_project.tcl) | 创建工程的tcl脚本. 38 | [./data_gen.py](./data_gen.py) | 生成测试数据的python脚本, 供仿真使用. 39 | [./fir_coe_gen.py](./fir_coe_gen.py) | 生成滤波器系数文件的脚本. 40 | [./fir.v](./fir.v) | **FIR顶层模块** 41 | [./multadd.v](./multadd.v) | FIR中的乘法-加法计算模块 42 | [./readme_zh.md](./readme_zh.md) | 说明文件(中文) 43 | [./sim_fir.py](./sim_fir.py) | FIR模块的测试分析脚本 44 | [./sim_fir.v](./sim_fir.v) | FIR模块的测试激励文件 45 | [../common/pipe_delay.v](../common/pipe_delay.v) | 延迟模块 46 | 47 | ## 参数说明 48 | 49 | 名称|类型|描述 50 | -|-|- 51 | C_S_DATA_TDATA_WIDTH | integer | 输入数据总线位宽. 52 | C_M_DATA_TDATA_WIDTH | integer | 输出数据总线位宽. 53 | C_RELOAD_TDATA_WIDTH | integer | 重载滤波器系数总线位宽. 54 | C_COEF_FILE | string | FIR系数文件. 55 | C_NUM_TAPS | integer | 滤波器系数数组长度. 56 | 57 | ## 端口说明 58 | 59 | 名称|I/O|描述 60 | -|:-:|- 61 | aclk | I | 上升沿触发. 62 | aresetn | I | 同步复位信号. 低电平有效. 63 | s_axis_reload_tvalid | I | 重载系数总线TVALID端口 64 | s_axis_reload_tlast | I | 重载系数总线TLAST端口 65 | s_axis_reload_tdata | I | 重载系数总线TDATA端口 66 | s_axis_data_tvalid | I | 输入数据总线的TVALID端口 67 | s_axis_data_tdata | I | 输入数据总线的 TDATA 端口 68 | m_axis_data_tvalid | O | 输出数据总线的 TVALID 端口 69 | m_axis_data_tdat | O | 输出数据总线的 TDATA 端口 70 | 71 | ## 资源消耗 72 | 73 | 当数据位宽和系数位宽不超过DSP48E的输入数据端口位宽时, 每个乘法-加法运算单元需要一个 DSP48E, 故 DSP48E 的使用量 N 为: N = C_NUM_TAPS 74 | 75 | ## 时延 76 | 77 | 输入数据有效(s_axis_data_tvalid==1)到输出数据有效(m_axis_data_tvalid==1)的时延为1 clocks. 78 | 79 | ## 测试 80 | 81 | - 根据需要修改[sim_fir.v](./sim_fir.v)中参数值. 82 | - 修改[data_gen.py](./data_gen.py)中`data_width`变量的值. 该变量的值应与[sim_fir.v](./sim_fir.v)中 `C_S_DATA_TDATA_WIDTH`参数的值一致. 83 | - 运行[data_gen.py](./data_gen.py), 生成测试数据文件`data.dat`, 默认保存路径为`D:/`. 84 | - 修改[fir_coe_gen.py](./fir_coe_gen.py)中`coe_width`变量的值, 该变量的值应与[sim_fir.v](./sim_fir.v)中`C_RELOAD_TDATA_WIDTH`参数的值一致. 85 | - 运行[fir_coe_gen.py](./fir_coe_gen.py), 生成滤波器系数文件`fir.coe`, 默认保存路径为`D:/`. 86 | - 在`Vivado`中,点击`Flow Navigator`中的`Run Simulation`,或使用菜单`Flow|Run Simulation` 87 | - 点击菜单`Run | Run All(F3)`运行仿真, 运行停止后, 在`D:/`下会生成输出数据文件`output.dat`. 88 | - 修改[sim_fir.py](./sim_fir.py)中`coe_width`变量和`data_width`变量的值. 89 | - 运行[sim_fir.py](./sim_fir.py),查看测试结果. 打印如下内容, 表明测试成功. 90 | 91 | ``` 92 | diff y with y_: 0.0 93 | ``` -------------------------------------------------------------------------------- /fir/sim_fir.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import scipy.signal as signal 3 | import numpy as np 4 | import numpy.fft as fft 5 | 6 | 7 | coe_filename = r'D:/fir.coe' 8 | data_filename = r'D:/data.dat' 9 | dout_filename = r'D:/output.dat' 10 | coe_width = 24 11 | data_width = 16 12 | 13 | def read_fir_coes(filename, bit_width): 14 | with open(filename, 'r') as f: 15 | lines = f.readlines() 16 | coes = [int(e, base=16) for e in lines] 17 | b = [coe if coe < (2**(bit_width-1)) else (coe - 2**bit_width) for coe in coes] 18 | return [bb / (2**(bit_width-1)) for bb in b ] 19 | 20 | def read_data(filename, bit_width): 21 | with open(filename, 'r') as f: 22 | lines = f.readlines() 23 | data = [int(n, base=16) for n in lines] 24 | data = [d if d < (2 ** (bit_width - 1)) else (d - 2**bit_width) for d in data] 25 | return data 26 | 27 | b = read_fir_coes(coe_filename, coe_width) 28 | x = read_data(data_filename, data_width) 29 | y_ = np.array(read_data(dout_filename, data_width)) 30 | 31 | w, h = signal.freqz(b) 32 | ax1 = plt.subplot(211) 33 | ax1.set_title('Digital filter frequency response') 34 | ax1.plot(w, 20 * np.log10(abs(h)), 'b') 35 | ax1.set_ylabel('Amplitude [dB]', color='b') 36 | ax1.set_xlabel('Frequency [rad/sample]') 37 | ax2 = ax1.twinx() 38 | angles = np.unwrap(np.angle(h)) 39 | ax2.plot(w, angles, 'g') 40 | ax2.set_ylabel('Angle (radians)', color='g') 41 | ax2.grid() 42 | ax2.axis('tight') 43 | ax3 = plt.subplot(212) 44 | ax3.plot(b) 45 | plt.show() 46 | 47 | y = signal.lfilter(b, 1, x) 48 | y = np.floor(y) 49 | plt.figure() 50 | ax1 = plt.subplot(221) 51 | ax1.plot(y_) 52 | ax2 = plt.subplot(222) 53 | ax2.plot(abs(fft.fft(y_))) 54 | ax3 = plt.subplot(223) 55 | ax3.plot(y) 56 | ax4 = plt.subplot(224) 57 | ax4.plot(abs(fft.fft(y))) 58 | plt.show() 59 | 60 | print('diff y with y_:', sum(abs(y - y_))) 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /fir/sim_fir.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 2021/11/08 11:08:21 7 | // Design Name: 8 | // Module Name: sim_fir 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module sim_fir; 24 | 25 | parameter C_S_DATA_TDATA_WIDTH = 16; 26 | parameter C_M_DATA_TDATA_WIDTH = 16; 27 | parameter C_RELOAD_TDATA_WIDTH = 24; 28 | parameter C_NUM_TAPS = 63; 29 | // !!!Please use "/" not "\" for filepath!!! 30 | parameter C_COEF_FILE = "D:/fir.coe"; 31 | 32 | reg aclk; 33 | reg aresetn; 34 | reg s_axis_reload_tvalid; 35 | reg s_axis_reload_tlast; 36 | reg [C_RELOAD_TDATA_WIDTH - 1 : 0] s_axis_reload_tdata; 37 | reg s_axis_data_tvalid; 38 | reg [C_S_DATA_TDATA_WIDTH - 1 : 0] s_axis_data_tdata; 39 | wire m_axis_data_tvalid; 40 | wire [C_M_DATA_TDATA_WIDTH - 1 : 0]m_axis_data_tdata; 41 | 42 | fir #( 43 | .C_S_DATA_TDATA_WIDTH (C_S_DATA_TDATA_WIDTH), 44 | .C_M_DATA_TDATA_WIDTH (C_M_DATA_TDATA_WIDTH), 45 | .C_RELOAD_TDATA_WIDTH (C_RELOAD_TDATA_WIDTH), 46 | .C_NUM_TAPS (C_NUM_TAPS), 47 | .C_COEF_FILE (C_COEF_FILE) 48 | ) u_fir ( 49 | .aclk(aclk), 50 | .aresetn(aresetn), 51 | .s_axis_reload_tvalid(s_axis_reload_tvalid), 52 | .s_axis_reload_tlast(s_axis_reload_tlast), 53 | .s_axis_reload_tdata(s_axis_reload_tdata), 54 | .s_axis_data_tvalid(s_axis_data_tvalid), 55 | .s_axis_data_tdata(s_axis_data_tdata), 56 | .m_axis_data_tvalid(m_axis_data_tvalid), 57 | .m_axis_data_tdata(m_axis_data_tdata) 58 | ); 59 | 60 | initial begin 61 | aclk = 0; 62 | aresetn = 0; 63 | s_axis_data_tvalid = 0; 64 | s_axis_data_tdata <= 0; 65 | 66 | #100 aresetn = 1; 67 | 68 | #200 s_axis_data_tvalid = 1; 69 | s_axis_data_tdata = 16'h0100; 70 | 71 | end 72 | 73 | // Define file handle integer 74 | integer outfile; 75 | 76 | initial begin 77 | // Open file output.dat for writing 78 | outfile = $fopen("D:/output.dat", "w"); 79 | 80 | // Check if file was properly opened and if not, produce error and exit 81 | if (outfile == 0) begin 82 | $display("Error: File, output.dat could not be opened.\nExiting Simulation."); 83 | $finish; 84 | end 85 | 86 | @(posedge m_axis_data_tvalid); 87 | 88 | while(m_axis_data_tvalid == 1) begin 89 | @(posedge aclk) if(m_axis_data_tvalid == 1) begin 90 | $fdisplay(outfile, "%h", m_axis_data_tdata); 91 | end 92 | end 93 | #100; 94 | 95 | // Close file to end monitoring 96 | $fclose(outfile); 97 | end 98 | 99 | // Define integers for file handling 100 | integer number_file; 101 | integer i=1; 102 | reg [C_S_DATA_TDATA_WIDTH - 1 : 0] data; 103 | initial begin 104 | aclk = 0; 105 | aresetn = 0; 106 | s_axis_reload_tvalid = 0; 107 | s_axis_reload_tlast = 0; 108 | s_axis_reload_tdata = 0; 109 | s_axis_data_tvalid = 0; 110 | s_axis_data_tdata = 0; 111 | 112 | // Open file numbers.txt for reading 113 | number_file = $fopen("D:/data.dat", "r"); 114 | // Produce error and exit if file could not be opened 115 | if (number_file == 0) begin 116 | $display("Error: Failed to open file, data.dat\nExiting Simulation."); 117 | $finish; 118 | end 119 | 120 | #100; 121 | aresetn = 1; 122 | #100; 123 | 124 | // Loop while data is being read from file 125 | // (i will be -1 when end of file or 0 for blank line) 126 | while (i>0) begin 127 | i=$fscanf(number_file, "%h", data); 128 | @(posedge aclk); 129 | s_axis_data_tdata = data; 130 | s_axis_data_tvalid = 1; 131 | end 132 | // Close out file when finished reading 133 | $fclose(number_file); 134 | s_axis_data_tvalid = 0; 135 | #200; 136 | $display("Simulation ended normally"); 137 | $stop; 138 | end 139 | 140 | 141 | always #5 aclk = ~aclk; 142 | 143 | endmodule 144 | -------------------------------------------------------------------------------- /pfft/butterfly.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | /* 3 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * 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, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | // Company: 25 | // Engineer: 26 | // Jackie Wang(falwat@163.com) 27 | // 28 | // Create Date: 2021/11/05 10:57:00 29 | // Design Name: 30 | // Module Name: butterfly 31 | // Project Name: 32 | // Target Devices: 33 | // Tool Versions: 34 | // Description: 35 | // P0 = A0 + B * A1 36 | // P1 = A0 - B * A1 37 | // Dependencies: 38 | // 39 | // Revision: 40 | // Revision 0.01 - File Created 41 | // Additional Comments: 42 | // 43 | ////////////////////////////////////////////////////////////////////////////////// 44 | 45 | 46 | module butterfly #( 47 | parameter COMPLEX_A_DWIDTH = 32, 48 | parameter COMPLEX_B_DWIDTH = 32 49 | ) 50 | ( 51 | input aclk, 52 | input aresetn, 53 | input scale_en, 54 | input [COMPLEX_A_DWIDTH - 1 : 0] din_a0, 55 | input [COMPLEX_A_DWIDTH - 1 : 0] din_a1, 56 | input [COMPLEX_B_DWIDTH - 1 : 0] din_b, 57 | output [COMPLEX_A_DWIDTH - 1: 0] dout_p0, 58 | output [COMPLEX_A_DWIDTH - 1: 0] dout_p1, 59 | output event_overflow 60 | ); 61 | 62 | localparam CMULT_AWIDTH = COMPLEX_A_DWIDTH / 2; 63 | localparam CMULT_BWIDTH = COMPLEX_B_DWIDTH / 2; 64 | localparam DELAY_CLKS = 6; 65 | 66 | wire [COMPLEX_A_DWIDTH - 1 : 0] din_a0_dly; 67 | 68 | wire signed [CMULT_AWIDTH - 1 : 0] a0_r = din_a0_dly[CMULT_AWIDTH - 1 : 0]; 69 | wire signed [CMULT_AWIDTH - 1 : 0] a0_i = din_a0_dly[COMPLEX_A_DWIDTH - 1 : CMULT_AWIDTH]; 70 | wire signed [CMULT_AWIDTH - 1 : 0] a1_r = din_a1[CMULT_AWIDTH - 1 : 0]; 71 | wire signed [CMULT_AWIDTH - 1 : 0] a1_i = din_a1[COMPLEX_A_DWIDTH - 1 : CMULT_AWIDTH]; 72 | wire signed [CMULT_BWIDTH - 1 : 0] br = din_b[CMULT_BWIDTH - 1 : 0]; 73 | wire signed [CMULT_BWIDTH - 1 : 0] bi = din_b[COMPLEX_B_DWIDTH - 1 : CMULT_BWIDTH]; 74 | 75 | wire signed [CMULT_AWIDTH + CMULT_BWIDTH - 1 : 0] pr, pi; 76 | wire signed [CMULT_AWIDTH - 1 : 0] pr_slice, pi_slice; 77 | assign pr_slice = pr[CMULT_BWIDTH - 2 +: CMULT_AWIDTH]; 78 | assign pi_slice = pi[CMULT_BWIDTH - 2 +: CMULT_AWIDTH]; 79 | wire signed [CMULT_AWIDTH : 0] pmax, pmin; 80 | assign pmax = 2 ** (CMULT_AWIDTH - 1) - 1; 81 | assign pmin = -(2 ** (CMULT_AWIDTH - 1)); 82 | 83 | reg signed [CMULT_AWIDTH : 0] p0_r, p0_i, p1_r, p1_i; 84 | reg signed [CMULT_AWIDTH - 1 : 0] p0_scale_r, p0_scale_i, p1_scale_r, p1_scale_i; 85 | reg event_overflow_r; 86 | 87 | pipe_delay #( 88 | .DATA_WIDTH(COMPLEX_A_DWIDTH), // DATA_WIDTH = 1,2... 89 | .DELAY_CLKS(DELAY_CLKS) // DELAY_CLKS = 0,1,... 90 | ) u_pipe_delay_a0 ( 91 | .rst(~aresetn), // input wire rst; 92 | .clk(aclk), // input wire clk; 93 | .clk_en(1'b1), // input wire clk_en; 94 | .din(din_a0), // input wire [DATA_WIDTH-1:0] din; 95 | .dout(din_a0_dly) // output wire [DATA_WIDTH-1:0] dout; 96 | ); 97 | 98 | 99 | always @(posedge aclk) begin 100 | if(~aresetn) begin 101 | p0_r <= 0; 102 | p0_i <= 0; 103 | p1_r <= 0; 104 | p1_i <= 0; 105 | p0_scale_r <= 0; 106 | p0_scale_i <= 0; 107 | p1_scale_r <= 0; 108 | p1_scale_i <= 0; 109 | end else begin 110 | p0_r <= a0_r + pr_slice; 111 | p0_i <= a0_i + pi_slice; 112 | p1_r <= a0_r - pr_slice; 113 | p1_i <= a0_i - pi_slice; 114 | if(scale_en) begin 115 | p0_scale_r <= p0_r[CMULT_AWIDTH : 1]; 116 | p0_scale_i <= p0_i[CMULT_AWIDTH : 1]; 117 | p1_scale_r <= p1_r[CMULT_AWIDTH : 1]; 118 | p1_scale_i <= p1_i[CMULT_AWIDTH : 1]; 119 | end else begin 120 | p0_scale_r <= p0_r[CMULT_AWIDTH - 1 : 0]; 121 | p0_scale_i <= p0_i[CMULT_AWIDTH - 1 : 0]; 122 | p1_scale_r <= p1_r[CMULT_AWIDTH - 1 : 0]; 123 | p1_scale_i <= p1_i[CMULT_AWIDTH - 1 : 0]; 124 | end 125 | end 126 | end 127 | 128 | always @(posedge aclk) begin 129 | if(~aresetn) begin 130 | event_overflow_r <= 0; 131 | end else if(p0_r > pmax || p0_r < pmin || 132 | p0_i > pmax || p0_i < pmin || 133 | p1_r > pmax || p1_r < pmin || 134 | p1_i > pmax || p1_i < pmin) begin 135 | event_overflow_r <= 1; 136 | end else begin 137 | event_overflow_r <= 0; 138 | end 139 | end 140 | 141 | cmult # ( 142 | .AWIDTH(CMULT_AWIDTH), 143 | .BWIDTH(CMULT_BWIDTH) 144 | ) 145 | u_cmult 146 | ( 147 | .clk(aclk), 148 | .ar(a1_r), 149 | .ai(a1_i), 150 | .br(br), 151 | .bi(bi), 152 | .pr(pr), 153 | .pi(pi) 154 | ); 155 | 156 | assign dout_p0 = {p0_scale_i, p0_scale_r}; 157 | assign dout_p1 = {p1_scale_i, p1_scale_r}; 158 | 159 | endmodule 160 | -------------------------------------------------------------------------------- /pfft/butterfly_block.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | /* 3 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * 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, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | // Company: 25 | // Engineer: 26 | // Jackie Wang(falwat@163.com) 27 | // 28 | // Create Date: 2021/11/05 15:04:09 29 | // Design Name: 30 | // Module Name: butterfly_block 31 | // Project Name: 32 | // Target Devices: 33 | // Tool Versions: 34 | // Description: 35 | // 36 | // This is a nested module using the Radix-2 decimation-in-time(DIT) 37 | // decomposition method for computing the DFT. 38 | // 39 | // The input data is divided into two groups according to odd and even 40 | // subscripts. And each group is input separately to the butterfly_block 41 | // submodule. Then these two submodules output data will perform butterfly 42 | // computation separately. 43 | // 44 | // Dependencies: 45 | // 46 | // Revision: 47 | // Revision 0.01 - File Created 48 | // Additional Comments: 49 | // 50 | ////////////////////////////////////////////////////////////////////////////////// 51 | 52 | module butterfly_block #( 53 | parameter FFT_ORDER = 3, 54 | parameter COMPLEX_A_DWIDTH = 32, 55 | parameter COMPLEX_B_DWIDTH = 32 56 | )( 57 | // Positive edge trigger 58 | input aclk, 59 | // Active Low 60 | input aresetn, 61 | // Scaling schedule. Each bit control one stage 62 | input [FFT_ORDER - 1 : 0]scale_sch, 63 | input din_valid, 64 | // input data 65 | input [2 ** FFT_ORDER * COMPLEX_A_DWIDTH - 1 : 0] din_a, 66 | // input coefficient Wn 67 | input [2 ** (FFT_ORDER - 1) * COMPLEX_B_DWIDTH - 1 : 0] din_b, 68 | output dout_valid, 69 | // output data 70 | output [2 ** FFT_ORDER * COMPLEX_A_DWIDTH - 1 : 0] dout_p 71 | ); 72 | 73 | localparam DATA_WIDTH = COMPLEX_A_DWIDTH / 2; 74 | localparam CHN_NUM = 2 ** FFT_ORDER; 75 | 76 | genvar k,i,m; 77 | generate 78 | if(FFT_ORDER == 1) begin: gen_fft_1 79 | reg din_valid_dly, din_valid_dly_2; 80 | wire signed [DATA_WIDTH - 1 : 0] a0_r, a0_i, a1_r, a1_i; 81 | reg signed [DATA_WIDTH : 0] p0_r, p0_i, p1_r, p1_i; 82 | reg signed [DATA_WIDTH - 1: 0] p0_scale_r, p0_scale_i, p1_scale_r, p1_scale_i; 83 | assign a0_r = din_a[0 * DATA_WIDTH +: DATA_WIDTH]; 84 | assign a0_i = din_a[1 * DATA_WIDTH +: DATA_WIDTH]; 85 | assign a1_r = din_a[2 * DATA_WIDTH +: DATA_WIDTH]; 86 | assign a1_i = din_a[3 * DATA_WIDTH +: DATA_WIDTH]; 87 | 88 | always @(posedge aclk) begin 89 | if(~aresetn) begin 90 | din_valid_dly <= 0; 91 | din_valid_dly_2 <= 0; 92 | p0_r <= 0; 93 | p0_i <= 0; 94 | p1_r <= 0; 95 | p1_i <= 0; 96 | p0_scale_r <= 0; 97 | p0_scale_i <= 0; 98 | p1_scale_r <= 0; 99 | p1_scale_i <= 0; 100 | end else begin 101 | din_valid_dly <= din_valid; 102 | din_valid_dly_2 <= din_valid_dly; 103 | p0_r <= a0_r + a1_r; 104 | p0_i <= a0_i + a1_i; 105 | p1_r <= a0_r - a1_r; 106 | p1_i <= a0_i - a1_i; 107 | 108 | if(scale_sch[0] == 1) begin 109 | p0_scale_r <= p0_r[DATA_WIDTH : 1]; 110 | p0_scale_i <= p0_i[DATA_WIDTH : 1]; 111 | p1_scale_r <= p1_r[DATA_WIDTH : 1]; 112 | p1_scale_i <= p1_i[DATA_WIDTH : 1]; 113 | end else begin 114 | p0_scale_r <= p0_r[DATA_WIDTH - 1 : 0]; 115 | p0_scale_i <= p0_i[DATA_WIDTH - 1 : 0]; 116 | p1_scale_r <= p1_r[DATA_WIDTH - 1 : 0]; 117 | p1_scale_i <= p1_i[DATA_WIDTH - 1 : 0]; 118 | end 119 | end 120 | end 121 | 122 | assign dout_valid = din_valid_dly_2; 123 | assign dout_p = {p1_scale_i, p1_scale_r, p0_scale_i, p0_scale_r}; 124 | 125 | // end else if(FFT_ORDER == 2) begin: gen_fft_2 126 | 127 | end else begin: gen_fft_n 128 | wire [CHN_NUM / 2 * COMPLEX_A_DWIDTH - 1 : 0]din_a_subset[1:0]; 129 | wire [CHN_NUM / 2 * COMPLEX_B_DWIDTH - 1 : 0]din_b_subset; 130 | wire dout_valid_0; 131 | wire [CHN_NUM / 2 * COMPLEX_A_DWIDTH - 1 : 0]dout_p_subset[1:0]; 132 | for(k=0; k < CHN_NUM / 2; k=k+1) begin: gen_din_a 133 | // Even number part 134 | assign din_a_subset[0][COMPLEX_A_DWIDTH * k +: COMPLEX_A_DWIDTH] = din_a[(2 * k) * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]; 135 | // Odd number part 136 | assign din_a_subset[1][COMPLEX_A_DWIDTH * k +: COMPLEX_A_DWIDTH] = din_a[(2 * k + 1) * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]; 137 | end 138 | 139 | for(m=0; m < CHN_NUM / 4; m=m+1) begin: gen_din_b 140 | assign din_b_subset[COMPLEX_B_DWIDTH * m +: COMPLEX_B_DWIDTH] = din_b[(2 * m) * COMPLEX_B_DWIDTH +: COMPLEX_B_DWIDTH]; 141 | end 142 | 143 | butterfly_block #( 144 | .FFT_ORDER(FFT_ORDER - 1), 145 | .COMPLEX_A_DWIDTH(COMPLEX_A_DWIDTH), 146 | .COMPLEX_B_DWIDTH(COMPLEX_B_DWIDTH) 147 | ) u_bfb_0 ( 148 | .aclk(aclk), 149 | .aresetn(aresetn), 150 | .scale_sch(scale_sch[FFT_ORDER - 1 : 1]), 151 | .din_valid(din_valid), 152 | .din_a(din_a_subset[0]), 153 | .din_b(din_b_subset), 154 | .dout_valid(dout_valid_0), 155 | .dout_p(dout_p_subset[0]) 156 | ); 157 | 158 | butterfly_block #( 159 | .FFT_ORDER(FFT_ORDER - 1), 160 | .COMPLEX_A_DWIDTH(COMPLEX_A_DWIDTH), 161 | .COMPLEX_B_DWIDTH(COMPLEX_B_DWIDTH) 162 | ) u_bfb_1 ( 163 | .aclk(aclk), 164 | .aresetn(aresetn), 165 | .scale_sch(scale_sch[FFT_ORDER - 1 : 1]), 166 | .din_valid(din_valid), 167 | .din_a(din_a_subset[1]), 168 | .din_b(din_b_subset), 169 | .dout_valid(), 170 | .dout_p(dout_p_subset[1]) 171 | ); 172 | 173 | pipe_delay #( 174 | .DATA_WIDTH(1), // DATA_WIDTH = 1,2... 175 | .DELAY_CLKS(8) // DELAY_CLKS = 0,1,... 176 | ) u_pipe_delay_a0 ( 177 | .rst(~aresetn), // input wire rst; 178 | .clk(aclk), // input wire clk; 179 | .clk_en(1'b1), // input wire clk_en; 180 | .din(dout_valid_0), // input wire [DATA_WIDTH-1:0] din; 181 | .dout(dout_valid) // output wire [DATA_WIDTH-1:0] dout; 182 | ); 183 | 184 | for (i=0; i < CHN_NUM / 2; i=i+1) begin: gen_bf 185 | butterfly #( 186 | .COMPLEX_A_DWIDTH(COMPLEX_A_DWIDTH), 187 | .COMPLEX_B_DWIDTH(COMPLEX_B_DWIDTH) 188 | ) u_bf ( 189 | .aclk (aclk), 190 | .aresetn (aresetn), 191 | .scale_en(scale_sch[0]), 192 | .din_a0 (dout_p_subset[0][i * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]), 193 | .din_a1 (dout_p_subset[1][i * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]), 194 | .din_b (din_b[i * COMPLEX_B_DWIDTH +: COMPLEX_B_DWIDTH]), 195 | .dout_p0 (dout_p[i * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]), 196 | .dout_p1 (dout_p[(i + CHN_NUM / 2) * COMPLEX_A_DWIDTH +: COMPLEX_A_DWIDTH]) 197 | ); 198 | end 199 | end 200 | 201 | endgenerate 202 | 203 | endmodule 204 | 205 | -------------------------------------------------------------------------------- /pfft/create_project.tcl: -------------------------------------------------------------------------------- 1 | #***************************************************************************************** 2 | # Vivado (TM) v2018.3 (64-bit) 3 | # 4 | # create_project.tcl: Tcl script for re-creating project 'pfft' 5 | # 6 | # Generated by Vivado on Sun Nov 07 21:48:53 +0800 2021 7 | # IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 8 | # 9 | # This file contains the Vivado Tcl commands for re-creating the project to the state* 10 | # when this script was generated. In order to re-create the project, please source this 11 | # file in the Vivado Tcl Shell. 12 | # 13 | # * Note that the runs in the created project will be configured the same way as the 14 | # original project, however they will not be launched automatically. To regenerate the 15 | # run results please launch the synthesis/implementation runs as needed. 16 | # 17 | #***************************************************************************************** 18 | # NOTE: In order to use this script for source control purposes, please make sure that the 19 | # following files are added to the source control system:- 20 | # 21 | # 1. This project restoration tcl script (create_project.tcl) that was generated. 22 | # 23 | # 2. The following source(s) files that were local or imported into the original project. 24 | # (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) 25 | # 26 | # 27 | # 28 | # 3. The following remote source files that were added to the original project:- 29 | # 30 | # "C:/Users/falwa/code_repo/pfft/butterfly.v" 31 | # "C:/Users/falwa/code_repo/pfft/butterfly_block.v" 32 | # "C:/Users/falwa/code_repo/common/cmult.v" 33 | # "C:/Users/falwa/code_repo/common/pipe_delay.v" 34 | # "C:/Users/falwa/code_repo/pfft/pfft.v" 35 | # "C:/Users/falwa/code_repo/pfft/sim_pfft.v" 36 | # "C:/Users/falwa/code_repo/pfft/sim_butterfly.v" 37 | # 38 | #***************************************************************************************** 39 | 40 | # Set the reference directory for source file relative paths (by default the value is script directory path) 41 | set origin_dir "." 42 | 43 | # Use origin directory path location variable, if specified in the tcl shell 44 | if { [info exists ::origin_dir_loc] } { 45 | set origin_dir $::origin_dir_loc 46 | } 47 | 48 | # Set the project name 49 | set _xil_proj_name_ "pfft" 50 | 51 | # Use project name variable, if specified in the tcl shell 52 | if { [info exists ::user_project_name] } { 53 | set _xil_proj_name_ $::user_project_name 54 | } 55 | 56 | variable script_file 57 | set script_file "create_project.tcl" 58 | 59 | # Help information for this script 60 | proc print_help {} { 61 | variable script_file 62 | puts "\nDescription:" 63 | puts "Recreate a Vivado project from this script. The created project will be" 64 | puts "functionally equivalent to the original project for which this script was" 65 | puts "generated. The script contains commands for creating a project, filesets," 66 | puts "runs, adding/importing sources and setting properties on various objects.\n" 67 | puts "Syntax:" 68 | puts "$script_file" 69 | puts "$script_file -tclargs \[--origin_dir \]" 70 | puts "$script_file -tclargs \[--project_name \]" 71 | puts "$script_file -tclargs \[--help\]\n" 72 | puts "Usage:" 73 | puts "Name Description" 74 | puts "-------------------------------------------------------------------------" 75 | puts "\[--origin_dir \] Determine source file paths wrt this path. Default" 76 | puts " origin_dir path value is \".\", otherwise, the value" 77 | puts " that was set with the \"-paths_relative_to\" switch" 78 | puts " when this script was generated.\n" 79 | puts "\[--project_name \] Create project with the specified name. Default" 80 | puts " name is the name of the project from where this" 81 | puts " script was generated.\n" 82 | puts "\[--help\] Print help information for this script" 83 | puts "-------------------------------------------------------------------------\n" 84 | exit 0 85 | } 86 | 87 | if { $::argc > 0 } { 88 | for {set i 0} {$i < $::argc} {incr i} { 89 | set option [string trim [lindex $::argv $i]] 90 | switch -regexp -- $option { 91 | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } 92 | "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } 93 | "--help" { print_help } 94 | default { 95 | if { [regexp {^-} $option] } { 96 | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" 97 | return 1 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | # Set the directory path for the original project from where this script was exported 105 | set orig_proj_dir "[file normalize "$origin_dir/proj"]" 106 | 107 | # Create project 108 | create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7vx690tffg1761-2 109 | 110 | # Set the directory path for the new project 111 | set proj_dir [get_property directory [current_project]] 112 | 113 | # Set project properties 114 | set obj [current_project] 115 | set_property -name "board_part" -value "xilinx.com:vc709:part0:1.8" -objects $obj 116 | set_property -name "default_lib" -value "xil_defaultlib" -objects $obj 117 | set_property -name "dsa.accelerator_binary_content" -value "bitstream" -objects $obj 118 | set_property -name "dsa.accelerator_binary_format" -value "xclbin2" -objects $obj 119 | set_property -name "dsa.board_id" -value "vc709" -objects $obj 120 | set_property -name "dsa.description" -value "Vivado generated DSA" -objects $obj 121 | set_property -name "dsa.dr_bd_base_address" -value "0" -objects $obj 122 | set_property -name "dsa.emu_dir" -value "emu" -objects $obj 123 | set_property -name "dsa.flash_interface_type" -value "bpix16" -objects $obj 124 | set_property -name "dsa.flash_offset_address" -value "0" -objects $obj 125 | set_property -name "dsa.flash_size" -value "1024" -objects $obj 126 | set_property -name "dsa.host_architecture" -value "x86_64" -objects $obj 127 | set_property -name "dsa.host_interface" -value "pcie" -objects $obj 128 | set_property -name "dsa.num_compute_units" -value "60" -objects $obj 129 | set_property -name "dsa.platform_state" -value "pre_synth" -objects $obj 130 | set_property -name "dsa.vendor" -value "xilinx" -objects $obj 131 | set_property -name "dsa.version" -value "0.0" -objects $obj 132 | set_property -name "enable_vhdl_2008" -value "1" -objects $obj 133 | set_property -name "ip_cache_permissions" -value "read write" -objects $obj 134 | set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj 135 | set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj 136 | set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj 137 | set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj 138 | set_property -name "simulator_language" -value "Mixed" -objects $obj 139 | 140 | # Create 'sources_1' fileset (if not found) 141 | if {[string equal [get_filesets -quiet sources_1] ""]} { 142 | create_fileset -srcset sources_1 143 | } 144 | 145 | # Set 'sources_1' fileset object 146 | set obj [get_filesets sources_1] 147 | set files [list \ 148 | [file normalize "${origin_dir}/butterfly.v"] \ 149 | [file normalize "${origin_dir}/butterfly_block.v"] \ 150 | [file normalize "${origin_dir}/../common/cmult.v"] \ 151 | [file normalize "${origin_dir}/../common/pipe_delay.v"] \ 152 | [file normalize "${origin_dir}/pfft.v"] \ 153 | ] 154 | add_files -norecurse -fileset $obj $files 155 | 156 | # Set 'sources_1' fileset file properties for remote files 157 | # None 158 | 159 | # Set 'sources_1' fileset file properties for local files 160 | # None 161 | 162 | # Set 'sources_1' fileset properties 163 | set obj [get_filesets sources_1] 164 | set_property -name "top" -value "pfft" -objects $obj 165 | 166 | # Create 'constrs_1' fileset (if not found) 167 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 168 | create_fileset -constrset constrs_1 169 | } 170 | 171 | # Set 'constrs_1' fileset object 172 | set obj [get_filesets constrs_1] 173 | 174 | # Empty (no sources present) 175 | 176 | # Set 'constrs_1' fileset properties 177 | set obj [get_filesets constrs_1] 178 | 179 | # Create 'sim_1' fileset (if not found) 180 | if {[string equal [get_filesets -quiet sim_1] ""]} { 181 | create_fileset -simset sim_1 182 | } 183 | 184 | # Set 'sim_1' fileset object 185 | set obj [get_filesets sim_1] 186 | set files [list \ 187 | [file normalize "${origin_dir}/sim_pfft.v"] \ 188 | [file normalize "${origin_dir}/sim_butterfly.v"] \ 189 | ] 190 | add_files -norecurse -fileset $obj $files 191 | 192 | # Set 'sim_1' fileset file properties for remote files 193 | # None 194 | 195 | # Set 'sim_1' fileset file properties for local files 196 | # None 197 | 198 | # Set 'sim_1' fileset properties 199 | set obj [get_filesets sim_1] 200 | set_property -name "top" -value "sim_pfft" -objects $obj 201 | set_property -name "top_auto_set" -value "0" -objects $obj 202 | set_property -name "top_lib" -value "xil_defaultlib" -objects $obj 203 | 204 | # Set 'utils_1' fileset object 205 | set obj [get_filesets utils_1] 206 | # Empty (no sources present) 207 | 208 | # Set 'utils_1' fileset properties 209 | set obj [get_filesets utils_1] 210 | 211 | # Create 'synth_1' run (if not found) 212 | if {[string equal [get_runs -quiet synth_1] ""]} { 213 | create_run -name synth_1 -part xc7vx690tffg1761-2 -flow {Vivado Synthesis 2018} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 214 | } else { 215 | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] 216 | set_property flow "Vivado Synthesis 2018" [get_runs synth_1] 217 | } 218 | set obj [get_runs synth_1] 219 | set_property set_report_strategy_name 1 $obj 220 | set_property report_strategy {Vivado Synthesis Default Reports} $obj 221 | set_property set_report_strategy_name 0 $obj 222 | # Create 'synth_1_synth_report_utilization_0' report (if not found) 223 | if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { 224 | create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 225 | } 226 | set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] 227 | if { $obj != "" } { 228 | set_property -name "display_name" -value "synth_1_synth_report_utilization_0" -objects $obj 229 | 230 | } 231 | set obj [get_runs synth_1] 232 | set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj 233 | set_property -name "steps.synth_design.args.more options" -value "-mode out_of_context" -objects $obj 234 | 235 | # set the current synth run 236 | current_run -synthesis [get_runs synth_1] 237 | 238 | # Create 'impl_1' run (if not found) 239 | if {[string equal [get_runs -quiet impl_1] ""]} { 240 | create_run -name impl_1 -part xc7vx690tffg1761-2 -flow {Vivado Implementation 2018} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 241 | } else { 242 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 243 | set_property flow "Vivado Implementation 2018" [get_runs impl_1] 244 | } 245 | set obj [get_runs impl_1] 246 | set_property set_report_strategy_name 1 $obj 247 | set_property report_strategy {Vivado Implementation Default Reports} $obj 248 | set_property set_report_strategy_name 0 $obj 249 | # Create 'impl_1_init_report_timing_summary_0' report (if not found) 250 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { 251 | create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 252 | } 253 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] 254 | if { $obj != "" } { 255 | set_property -name "is_enabled" -value "0" -objects $obj 256 | set_property -name "display_name" -value "impl_1_init_report_timing_summary_0" -objects $obj 257 | 258 | } 259 | # Create 'impl_1_opt_report_drc_0' report (if not found) 260 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { 261 | create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 262 | } 263 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] 264 | if { $obj != "" } { 265 | set_property -name "display_name" -value "impl_1_opt_report_drc_0" -objects $obj 266 | 267 | } 268 | # Create 'impl_1_opt_report_timing_summary_0' report (if not found) 269 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { 270 | create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 271 | } 272 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] 273 | if { $obj != "" } { 274 | set_property -name "is_enabled" -value "0" -objects $obj 275 | set_property -name "display_name" -value "impl_1_opt_report_timing_summary_0" -objects $obj 276 | 277 | } 278 | # Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) 279 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { 280 | create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 281 | } 282 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] 283 | if { $obj != "" } { 284 | set_property -name "is_enabled" -value "0" -objects $obj 285 | set_property -name "display_name" -value "impl_1_power_opt_report_timing_summary_0" -objects $obj 286 | 287 | } 288 | # Create 'impl_1_place_report_io_0' report (if not found) 289 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { 290 | create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 291 | } 292 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] 293 | if { $obj != "" } { 294 | set_property -name "display_name" -value "impl_1_place_report_io_0" -objects $obj 295 | 296 | } 297 | # Create 'impl_1_place_report_utilization_0' report (if not found) 298 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { 299 | create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 300 | } 301 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] 302 | if { $obj != "" } { 303 | set_property -name "display_name" -value "impl_1_place_report_utilization_0" -objects $obj 304 | 305 | } 306 | # Create 'impl_1_place_report_control_sets_0' report (if not found) 307 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { 308 | create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 309 | } 310 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] 311 | if { $obj != "" } { 312 | set_property -name "display_name" -value "impl_1_place_report_control_sets_0" -objects $obj 313 | 314 | } 315 | # Create 'impl_1_place_report_incremental_reuse_0' report (if not found) 316 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { 317 | create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 318 | } 319 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] 320 | if { $obj != "" } { 321 | set_property -name "is_enabled" -value "0" -objects $obj 322 | set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_0" -objects $obj 323 | 324 | } 325 | # Create 'impl_1_place_report_incremental_reuse_1' report (if not found) 326 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { 327 | create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 328 | } 329 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] 330 | if { $obj != "" } { 331 | set_property -name "is_enabled" -value "0" -objects $obj 332 | set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_1" -objects $obj 333 | 334 | } 335 | # Create 'impl_1_place_report_timing_summary_0' report (if not found) 336 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { 337 | create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 338 | } 339 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] 340 | if { $obj != "" } { 341 | set_property -name "is_enabled" -value "0" -objects $obj 342 | set_property -name "display_name" -value "impl_1_place_report_timing_summary_0" -objects $obj 343 | 344 | } 345 | # Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) 346 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { 347 | create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 348 | } 349 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] 350 | if { $obj != "" } { 351 | set_property -name "is_enabled" -value "0" -objects $obj 352 | set_property -name "display_name" -value "impl_1_post_place_power_opt_report_timing_summary_0" -objects $obj 353 | 354 | } 355 | # Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) 356 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { 357 | create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 358 | } 359 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] 360 | if { $obj != "" } { 361 | set_property -name "is_enabled" -value "0" -objects $obj 362 | set_property -name "display_name" -value "impl_1_phys_opt_report_timing_summary_0" -objects $obj 363 | 364 | } 365 | # Create 'impl_1_route_report_drc_0' report (if not found) 366 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { 367 | create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 368 | } 369 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] 370 | if { $obj != "" } { 371 | set_property -name "display_name" -value "impl_1_route_report_drc_0" -objects $obj 372 | 373 | } 374 | # Create 'impl_1_route_report_methodology_0' report (if not found) 375 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { 376 | create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 377 | } 378 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] 379 | if { $obj != "" } { 380 | set_property -name "display_name" -value "impl_1_route_report_methodology_0" -objects $obj 381 | 382 | } 383 | # Create 'impl_1_route_report_power_0' report (if not found) 384 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { 385 | create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 386 | } 387 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] 388 | if { $obj != "" } { 389 | set_property -name "display_name" -value "impl_1_route_report_power_0" -objects $obj 390 | 391 | } 392 | # Create 'impl_1_route_report_route_status_0' report (if not found) 393 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { 394 | create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 395 | } 396 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] 397 | if { $obj != "" } { 398 | set_property -name "display_name" -value "impl_1_route_report_route_status_0" -objects $obj 399 | 400 | } 401 | # Create 'impl_1_route_report_timing_summary_0' report (if not found) 402 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { 403 | create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 404 | } 405 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] 406 | if { $obj != "" } { 407 | set_property -name "display_name" -value "impl_1_route_report_timing_summary_0" -objects $obj 408 | 409 | } 410 | # Create 'impl_1_route_report_incremental_reuse_0' report (if not found) 411 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { 412 | create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 413 | } 414 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] 415 | if { $obj != "" } { 416 | set_property -name "display_name" -value "impl_1_route_report_incremental_reuse_0" -objects $obj 417 | 418 | } 419 | # Create 'impl_1_route_report_clock_utilization_0' report (if not found) 420 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { 421 | create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 422 | } 423 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] 424 | if { $obj != "" } { 425 | set_property -name "display_name" -value "impl_1_route_report_clock_utilization_0" -objects $obj 426 | 427 | } 428 | # Create 'impl_1_route_report_bus_skew_0' report (if not found) 429 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { 430 | create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 431 | } 432 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] 433 | if { $obj != "" } { 434 | set_property -name "display_name" -value "impl_1_route_report_bus_skew_0" -objects $obj 435 | 436 | } 437 | # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) 438 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { 439 | create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 440 | } 441 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] 442 | if { $obj != "" } { 443 | set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_timing_summary_0" -objects $obj 444 | 445 | } 446 | # Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) 447 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { 448 | create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 449 | } 450 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] 451 | if { $obj != "" } { 452 | set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_bus_skew_0" -objects $obj 453 | 454 | } 455 | set obj [get_runs impl_1] 456 | set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj 457 | set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj 458 | set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj 459 | 460 | # set the current impl run 461 | current_run -implementation [get_runs impl_1] 462 | 463 | puts "INFO: Project created:${_xil_proj_name_}" 464 | set obj [get_dashboards default_dashboard] 465 | 466 | # Create 'drc_1' gadget (if not found) 467 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] ""]} { 468 | create_dashboard_gadget -name {drc_1} -type drc 469 | } 470 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] 471 | set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj 472 | 473 | # Create 'methodology_1' gadget (if not found) 474 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] ""]} { 475 | create_dashboard_gadget -name {methodology_1} -type methodology 476 | } 477 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] 478 | set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj 479 | 480 | # Create 'power_1' gadget (if not found) 481 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] ""]} { 482 | create_dashboard_gadget -name {power_1} -type power 483 | } 484 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] 485 | set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj 486 | 487 | # Create 'timing_1' gadget (if not found) 488 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] ""]} { 489 | create_dashboard_gadget -name {timing_1} -type timing 490 | } 491 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] 492 | set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj 493 | 494 | # Create 'utilization_1' gadget (if not found) 495 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] ""]} { 496 | create_dashboard_gadget -name {utilization_1} -type utilization 497 | } 498 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] 499 | set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj 500 | set_property -name "run.step" -value "synth_design" -objects $obj 501 | set_property -name "run.type" -value "synthesis" -objects $obj 502 | 503 | # Create 'utilization_2' gadget (if not found) 504 | if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] ""]} { 505 | create_dashboard_gadget -name {utilization_2} -type utilization 506 | } 507 | set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] 508 | set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj 509 | 510 | move_dashboard_gadget -name {utilization_1} -row 0 -col 0 511 | move_dashboard_gadget -name {power_1} -row 1 -col 0 512 | move_dashboard_gadget -name {drc_1} -row 2 -col 0 513 | move_dashboard_gadget -name {timing_1} -row 0 -col 1 514 | move_dashboard_gadget -name {utilization_2} -row 1 -col 1 515 | move_dashboard_gadget -name {methodology_1} -row 2 -col 1 516 | # Set current dashboard to 'default_dashboard' 517 | current_dashboard default_dashboard 518 | -------------------------------------------------------------------------------- /pfft/pfft.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | /* 3 | * Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * 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, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | // Company: 25 | // Engineer: 26 | // Jackie Wang(falwat@163.com) 27 | // 28 | // Create Date: 2021/11/05 15:01:02 29 | // Design Name: 30 | // Module Name: pfft 31 | // Project Name: 32 | // Target Devices: 33 | // Tool Versions: 34 | // Description: 35 | // 36 | // Parallel FFT processing Module(PFFT). 37 | // 38 | // The PFFT module uses the Radix-2 decimation-in-time(DIT) decomposition method 39 | // for computing the DFT. 40 | // 41 | // The PFFT module computes an N-Point forward DFT where N is 2^FFT_ORDER, 42 | // the value of parameter FFT_ORDER can be 1,2,..,6. For larger N, you need to modify 43 | // the source code appropriately. 44 | // 45 | // The main difference with Xilinx FFT LogiCORE IP is that PFFT can perform 46 | // one FFT operation per clock, but Xilinx FFT LogiCORE IP need N+1 clocks. 47 | // 48 | // Dependencies: 49 | // 50 | // Revision: 51 | // Revision 0.01 - File Created 52 | // Additional Comments: 53 | // 54 | ////////////////////////////////////////////////////////////////////////////////// 55 | /* 56 | pfft #( 57 | .FFT_ORDER(4), // {1:2, 2:4,3:8,4:16,5:32,6:64} FFT_ORDER = log2(N) 58 | .COMPLEX_DWIDTH(32) 59 | ) instance_name ( 60 | .aclk(aclk), 61 | .aresetn(aresetn), 62 | .scale_sch(scale_sch), 63 | .s_axis_tvalid(s_axis_tvalid), 64 | .s_axis_tdata(s_axis_tdata), 65 | .m_axis_tvalid(m_axis_tvalid), 66 | .m_axis_tdata(m_axis_tdata), 67 | ); 68 | */ 69 | 70 | module pfft #( 71 | parameter FFT_ORDER = 4, // {1:2, 2:4,3:8,4:16,5:32,6:64} FFT_ORDER = log2(N) 72 | parameter COMPLEX_DWIDTH = 32 73 | )( 74 | // Positive edge trigger 75 | input aclk, 76 | // Active Low 77 | input aresetn, 78 | // Scaling schedule. Each bit control one stage 79 | input [FFT_ORDER - 1 : 0]scale_sch, 80 | // AXI4-Stream Slave Interface for Data Input Channel. 81 | input s_axis_tvalid, 82 | // {x[N-1].imag, x[N-1].real, ..., x[1].imag, x[1].real, x[0].imag, x[0].real} 83 | input [2 ** FFT_ORDER * COMPLEX_DWIDTH - 1 : 0] s_axis_tdata, 84 | // AXI4-Stream Master Interface for Data Output Channel. 85 | output m_axis_tvalid, 86 | // {X[N-1].imag, X[N-1].real, ..., X[1].imag, X[1].real, X[0].imag, X[0].real} 87 | output [2 ** FFT_ORDER * COMPLEX_DWIDTH - 1 : 0] m_axis_tdata 88 | ); 89 | 90 | 91 | localparam COMPLEX_B_DWIDTH = 48; 92 | localparam COE_NUM = 2 ** (FFT_ORDER - 1); 93 | wire [COE_NUM * COMPLEX_B_DWIDTH - 1 : 0] b; 94 | // wn[k] = exp(-j*2*pi*k/N) 95 | wire [32 * COMPLEX_B_DWIDTH - 1 : 0] wn; 96 | initial begin 97 | if(FFT_ORDER > 6) 98 | $error("For the configure of FFT_ORDER > 6, please modify the value of wn!!"); 99 | end 100 | assign wn = { 101 | 48'hf9ba17_c04ee5, 48'hf383a4_c13ad1, 48'hed6bfa_c2c17e, 48'he7821e_c4df29, 102 | 48'he1d4a3_c78e9b, 48'hdc718a_cac934, 48'hd7661a_ce8700, 48'hd2bec4_d2bec4, 103 | 48'hce8700_d7661a, 48'hcac934_dc718a, 48'hc78e9b_e1d4a3, 48'hc4df29_e7821e, 104 | 48'hc2c17e_ed6bfa, 48'hc13ad1_f383a4, 48'hc04ee5_f9ba17, 48'hc00000_000000, 105 | 48'hc04ee5_0645e9, 48'hc13ad1_0c7c5c, 48'hc2c17e_129406, 48'hc4df29_187de2, 106 | 48'hc78e9b_1e2b5d, 48'hcac934_238e76, 48'hce8700_2899e6, 48'hd2bec4_2d413c, 107 | 48'hd7661a_317900, 48'hdc718a_3536cc, 48'he1d4a3_387165, 48'he7821e_3b20d7, 108 | 48'hed6bfa_3d3e82, 48'hf383a4_3ec52f, 48'hf9ba17_3fb11b, 48'h000000_400000 109 | }; 110 | 111 | genvar i; 112 | generate 113 | for (i=0; i < COE_NUM; i=i+1) begin: gen_b 114 | assign b[i * COMPLEX_B_DWIDTH +: COMPLEX_B_DWIDTH] = wn[i * (32 / COE_NUM) * COMPLEX_B_DWIDTH +: COMPLEX_B_DWIDTH]; 115 | end 116 | endgenerate 117 | 118 | butterfly_block #( 119 | .FFT_ORDER(FFT_ORDER), 120 | .COMPLEX_A_DWIDTH(COMPLEX_DWIDTH), 121 | .COMPLEX_B_DWIDTH(COMPLEX_B_DWIDTH) 122 | ) u_bfb_1 ( 123 | .aclk(aclk), 124 | .aresetn(aresetn), 125 | .scale_sch(scale_sch), 126 | .din_valid(s_axis_tvalid), 127 | .din_a(s_axis_tdata), 128 | .din_b(b), 129 | .dout_valid(m_axis_tvalid), 130 | .dout_p(m_axis_tdata) 131 | ); 132 | 133 | endmodule 134 | -------------------------------------------------------------------------------- /pfft/readme.md: -------------------------------------------------------------------------------- 1 | # PFFT(Parallel Fast Fourier Transform) Module 2 | 3 | The `PFFT` module uses the Radix-2 decimation-in-time(DIT) decomposition method for computing the DFT. 4 | 5 | The `PFFT` module computes an N-Point forward DFT where N is 2^FFT_ORDER, 6 | the value of parameter FFT_ORDER can be 1,2,..,6. For larger N, you need to modify 7 | the source code appropriately. 8 | 9 | The main difference with Xilinx FFT LogiCORE IP is that `PFFT` can perform one FFT operation per clock, but Xilinx FFT LogiCORE IP need N+1 clocks. 10 | 11 | -------------------------------------------------------------------------------- /pfft/readme_zh.md: -------------------------------------------------------------------------------- 1 | # PFFT(并行快速傅里叶变换模块) 2 | 3 | - [PFFT(并行快速傅里叶变换模块)](#pfft并行快速傅里叶变换模块) 4 | - [概述](#概述) 5 | - [创建工程](#创建工程) 6 | - [文件组成](#文件组成) 7 | - [参数说明](#参数说明) 8 | - [端口描述](#端口描述) 9 | - [资源消耗](#资源消耗) 10 | - [时延](#时延) 11 | - [测试](#测试) 12 | 13 | ## 概述 14 | 15 | PFFT 模块采用时域抽取基-2分解方法来计算N点DFT, N为2的指数幂(2^FFT_ORDER, FFT_ORDER = 1,2,...,6).对于64点(2^6)以上的FFT计算, 需要对代码进行适当修改. 16 | 17 | ### 创建工程 18 | 19 | - 使用`git`工具克隆此仓库. 20 | 21 | ```sh 22 | git clone https://github.com/falwat/code_repo.git 23 | ``` 24 | 25 | - 打开`vivado tcl shell`, 使用`cd`命令切换至pfft目录 26 | - 运行`source ./create_project.tcl`,创建测试工程 27 | ```sh 28 | cd <仓库所在文件夹/code_repo/pfft> 29 | source ./create_project.tcl 30 | ``` 31 | 32 | ### 文件组成 33 | 34 | 文件|说明 35 | -|- 36 | [./pfft.v](./pfft.v) | 并行FFT模块. 37 | [./butterfly_block.v](./butterfly_block.v) | DIT-FFT 的一次分解模块. 在`pfft`模块和自己内部实例化
由两个子一级的`butterfly_block `和 一层蝶形运算模块`butterfly`构成. 38 | [./butterfly.v](./butterfly.v) | 蝶形运算模块 39 | [../common/cmult.v](../common/cmult.v) | 复数乘法器. 在`butterfly`模块中实例化. 40 | [./sim_butterfly.v](./sim_butterfly.v) | `butterfly`模块的测试激励文件 41 | [./sim_pfft.v](./sim_pfft.v) | `pfft`模块的测试激励文件 42 | [./sim_pfft.py](./sim_pfft.py) | `pfft`模块测试分析脚本 43 | [./sim_data_gen.py](./sim_data_gen.py) | 为`pfft`模块测试激励文件生成测试数据. 44 | [./create_project.tcl](./create_project.tcl) | 用于生成测试工程的tcl脚本. 45 | [./readme.md](./readme.md) | 说明文件(英文) 46 | [./readme_zh.md](./readme_zh.md) | 说明文件(中文) 47 | 48 | ## 参数说明 49 | 50 | 名称|类型|描述 51 | -|-|- 52 | FFT_ORDER | integer | FFT的阶数. `FFT_ORDER = log2(N), N = 2,4,8,16,32,64.` 53 | COMPLEX_DWIDTH | integer | 数据位宽. 54 | 55 | ## 端口描述 56 | 57 | 名称|I/O|描述 58 | -|:-:|- 59 | aclk | I | 上升沿触发. 60 | aresetn | I | 同步复位信号. 低电平有效. 61 | scale_sch | I | 缩放控制. 每个位控制一级蝶形运算模块.
0: 不对蝶形运算的输出进行缩放;
1: 对蝶形运算的输出缩小到1/2. 62 | s_axis_tvalid | I | 数据输入通道的TVALID端口. 1表示输入数据有效. 63 | s_axis_tdata | I | 数据输入通道的TDATA端口. 位宽由参数`FFT_ORDER` 和 `COMPLEX_DWIDTH` 决定, 通过如下公式进行计算: `2 ** FFT_ORDER * COMPLEX_DWIDTH`.
输入数据`x`在端口的映射为: `{x[N-1].imag, x[N-1].real, ..., x[1].imag, x[1].real, x[0].imag, x[0].real}` 64 | m_axis_tvalid | O | 数据输出通道的TVALID端口. 1表示输出数据有效. 65 | m_axis_tdata | O | 数据输出通道的TDATA端口. 位宽由参数`FFT_ORDER` 和 `COMPLEX_DWIDTH` 决定, 通过如下公式进行计算: `2 ** FFT_ORDER * COMPLEX_DWIDTH`.
输出数据`X`在端口的映射为: `{X[N-1].imag, X[N-1].real, ..., X[1].imag, X[1].real, X[0].imag, X[0].real}` 66 | 67 | ## 资源消耗 68 | 69 | DSP48E 的使用量满足如下公式: 70 | $$ 71 | 3 * 2^{N-1} * (\log_2(N) - 1) 72 | $$ 73 | 对于16点的PFFT, 需要的DSP48E的数量为: 3 * 8 * 3 = 72 74 | 75 | 实际综合后的资源消耗如下表所示: 76 | N-点FFT | Slice LUTs | Slice Registers | DSPs 77 | :-:|-:|-:|-: 78 | 8 | 1667 | 2372 | 24 79 | 16 | 4611 | 6560 | 72 80 | 32 | 11779 | 16754 | 192 81 | 64 | 28678 | 40751 | 480 82 | 83 | ## 时延 84 | 85 | 数据输入到N点FFT计算结果输出所需的时延满足如下计算公式: 86 | $$ 87 | Latency(N) = (\log_2(N)-1) * 8 + 2 88 | $$ 89 | 90 | N点FFT的时延如下表: 91 | N点FFT|时延(clks) 92 | :-:|-: 93 | 2 | 2 94 | 4 | 10 95 | 8 | 18 96 | 16 | 26 97 | 32 | 34 98 | 64 | 42 99 | 100 | 101 | ## 测试 102 | 103 | - 根据需要修改[./pfft.v](./pfft.v)中参数`FFT_ORDER`的值. 104 | - 修改[./sim_data_gen.py](./sim_data_gen.py)中`fft_len`参数的值. `fft_len`表示计算FFT的点数. 105 | - 运行[./sim_data_gen.py](./sim_data_gen.py), 生成测试数据文件`numbers.txt`, 默认保存路径为`D:\`. 106 | - 在`Vivado`中,点击`Flow Navigator`中的`Run Simulation`,或使用菜单`Flow|Run Simulation` 107 | - 运行仿真后, 在`D:\`下会生成输出数据文件`output.dat`. 108 | - 运行[./sim_pfft.py](./sim_pfft.py),查看测试结果. 打印信息中,`x`代表输入数据的值, `vhd`表示pfft模块输出的计算结果, `myfft`为python实现的基-2 DIT-FFT函数的输出结果, `fft` 为numpy.fft.fft函数输出的计算结果,`diff`为PFFT模块输出结果与python函数`myfft`计算结果的偏差. 109 | -------------------------------------------------------------------------------- /pfft/sim_butterfly.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 2021/11/05 15:59:46 7 | // Design Name: 8 | // Module Name: sim_butterfly 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module sim_butterfly; 24 | 25 | parameter COMPLEX_A_DWIDTH = 32; 26 | parameter COMPLEX_B_DWIDTH = 32; 27 | 28 | reg aclk; 29 | reg aresetn; 30 | reg [COMPLEX_A_DWIDTH - 1 : 0] din_a0; 31 | reg [COMPLEX_A_DWIDTH - 1 : 0] din_a1; 32 | reg [COMPLEX_B_DWIDTH - 1 : 0] din_b; 33 | 34 | wire [COMPLEX_A_DWIDTH + 1: 0] dout_p0; 35 | wire [COMPLEX_A_DWIDTH + 1: 0] dout_p1; 36 | 37 | butterfly #( 38 | .COMPLEX_A_DWIDTH(COMPLEX_A_DWIDTH), 39 | .COMPLEX_B_DWIDTH(COMPLEX_B_DWIDTH) 40 | ) u_bf ( 41 | .aclk (aclk), 42 | .aresetn (aresetn), 43 | .din_a0 (din_a0), 44 | .din_a1 (din_a1), 45 | .din_b (din_b), 46 | .dout_p0 (dout_p0), 47 | .dout_p1 (dout_p1) 48 | ); 49 | 50 | // Define integers for file handling 51 | integer number_file; 52 | integer i=1; 53 | 54 | initial begin 55 | aresetn = 0; 56 | aclk = 0; 57 | din_a0 = 0; 58 | din_a1 = 0; 59 | din_b = 0; 60 | 61 | // Open file numbers.txt for reading 62 | number_file = $fopen("D:/numbers.txt", "r"); 63 | // Produce error and exit if file could not be opened 64 | if (number_file == 0) begin 65 | $display("Error: Failed to open file, numbers.txt\nExiting Simulation."); 66 | $finish; 67 | end 68 | 69 | #100 aresetn = 1; 70 | #100; 71 | // Loop while data is being read from file 72 | // (i will be -1 when end of file or 0 for blank line) 73 | while (i>0) begin 74 | @(posedge aclk); 75 | $display("i = %d", i); 76 | i=$fscanf(number_file, "%h, %h, %h", din_a0, din_a1, din_b); 77 | $display("a0 : %h, a1 : %h, b : %h", din_a0, din_a1, din_b); 78 | end 79 | // Close out file when finished reading 80 | $fclose(number_file); 81 | #200; 82 | $display("Simulation ended normally"); 83 | $stop; 84 | end 85 | 86 | 87 | always #5 aclk = ~aclk; 88 | 89 | 90 | endmodule 91 | -------------------------------------------------------------------------------- /pfft/sim_data_gen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | """ 21 | import numpy as np 22 | 23 | fft_len = 16 24 | 25 | def num2hex(lst): 26 | return ['{:04x}'.format(v) for v in lst] 27 | 28 | 29 | with open('D:/numbers.txt', 'w') as f: 30 | for k in range(10): 31 | arr = np.random.randint(-100, 100, (fft_len * 2)) * 10 32 | lst = [int(v) if v >= 0 else v + 2**16 for v in arr] 33 | f.write(''.join(num2hex(lst)) + '\n') 34 | -------------------------------------------------------------------------------- /pfft/sim_pfft.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2021 Jackie Wang(falwat@163.com). All Rights Reserved. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | """ 21 | import numpy as np 22 | 23 | def splitvalue(v, dw): 24 | i = v >> dw 25 | i = i if i < 2**(dw - 1) else (i - 2 ** dw) 26 | r = v % (2 ** dw) 27 | r = r if r < 2**(dw - 1) else (r - 2 ** dw) 28 | return r + i*1j 29 | 30 | def butterfly(a0, a1, b, s): 31 | 32 | p0 = [(aa0 + aa1 * bb) / (2**s) for aa0, aa1, bb in zip(a0,a1,b)] 33 | p1 = [(aa0 - aa1 * bb) / (2**s) for aa0, aa1, bb in zip(a0,a1,b)] 34 | return p0 + p1 35 | 36 | def myfft(x,scale_sch): 37 | if(len(x) == 2): 38 | return [(x[0] + x[1]) / 2 ** scale_sch[0], (x[0] - x[1]) / 2 ** scale_sch[0]] 39 | else: 40 | x0 = [x[k] for k in range(0, len(x), 2)] 41 | x1 = [x[k] for k in range(1, len(x), 2)] 42 | a0 = myfft(x0, scale_sch[1::]) 43 | a1 = myfft(x1, scale_sch[1::]) 44 | # print('a0:', a0, 'a1:',a1) 45 | k = np.arange(len(x0)) 46 | b = np.exp(-2j * np.pi * k/ len(x)) 47 | return butterfly(a0, a1, b, scale_sch[0]) 48 | 49 | if __name__ == '__main__': 50 | skip = 0 51 | scale_sch = [1,1] 52 | ys = [] 53 | 54 | with open('D:/output.dat', 'r') as f: 55 | lines = f.readlines() 56 | for line in lines: 57 | if skip < 1: 58 | skip += 1 59 | continue 60 | data = [int(line[k:k+4], base=16) for k in range(0,len(line)-1,4)] 61 | data = [d if d < 2**15 else d - 2**16 for d in data] 62 | y = [data[k]*1j + data[k+1] for k in range(0, len(data), 2)] 63 | y = y[::-1] 64 | ys.append(y) 65 | # print(y) 66 | 67 | with open('D:/numbers.txt','r') as f: 68 | lines = f.readlines() 69 | n = 0 70 | for line in lines: 71 | data = [int(line[k:k+4], base=16) for k in range(0,len(line)-1,4)] 72 | data = [d if d < 2**15 else d - 2**16 for d in data] 73 | x = [data[k]*1j + data[k+1] for k in range(0, len(data), 2)] 74 | x = x[::-1] 75 | y = myfft(x, scale_sch) 76 | y0 = np.fft.fft(x) / (2 ** sum(scale_sch)) 77 | d = [int(abs(y0 - y1)) for y0, y1 in zip(y, ys[n])] 78 | print('-------------------------------------') 79 | print('x: ', x, '\nfft: ', y0, '\nvhd:', ys[n] , '\nmyfft: ', y, '\ndiff: ', d) 80 | 81 | n += 1 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /pfft/sim_pfft.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 2021/11/06 14:43:47 7 | // Design Name: 8 | // Module Name: sim_pfft 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | module sim_pfft; 24 | 25 | parameter FFT_ORDER = 2; 26 | parameter COMPLEX_DWIDTH = 32; 27 | 28 | reg aclk; 29 | reg aresetn; 30 | reg s_axis_tvalid; 31 | reg [2 ** FFT_ORDER * COMPLEX_DWIDTH - 1 : 0] s_axis_tdata; 32 | wire m_axis_tvalid; 33 | wire [2 ** FFT_ORDER * COMPLEX_DWIDTH - 1 : 0] m_axis_tdata; 34 | reg [2 ** FFT_ORDER * COMPLEX_DWIDTH - 1 : 0] data; 35 | 36 | pfft #( 37 | .FFT_ORDER(FFT_ORDER), 38 | .COMPLEX_DWIDTH(32) 39 | ) u_pfft ( 40 | .aclk(aclk), 41 | .aresetn(aresetn), 42 | .scale_sch({FFT_ORDER{1'b1}}), 43 | .s_axis_tvalid(s_axis_tvalid), 44 | .s_axis_tdata(s_axis_tdata), 45 | .m_axis_tvalid(m_axis_tvalid), 46 | .m_axis_tdata(m_axis_tdata) 47 | ); 48 | 49 | always #5 aclk = ~aclk; 50 | 51 | // Define file handle integer 52 | integer outfile; 53 | 54 | initial begin 55 | // Open file output.dat for writing 56 | outfile = $fopen("D:/output.dat", "w"); 57 | 58 | // Check if file was properly opened and if not, produce error and exit 59 | if (outfile == 0) begin 60 | $display("Error: File, output.dat could not be opened.\nExiting Simulation."); 61 | $finish; 62 | end 63 | 64 | @(posedge s_axis_tvalid); 65 | 66 | // Write monitor data to a file 67 | $fmonitor (outfile, "%h", m_axis_tdata); 68 | 69 | // Wait for 1 ms and end monitoring 70 | @(negedge m_axis_tvalid); 71 | #100; 72 | 73 | // Close file to end monitoring 74 | $fclose(outfile); 75 | end 76 | 77 | // Define integers for file handling 78 | integer number_file; 79 | integer i=1; 80 | 81 | initial begin 82 | aclk = 0; 83 | aresetn = 0; 84 | s_axis_tvalid = 0; 85 | s_axis_tdata = 0; 86 | 87 | // Open file numbers.txt for reading 88 | number_file = $fopen("D:/numbers.txt", "r"); 89 | // Produce error and exit if file could not be opened 90 | if (number_file == 0) begin 91 | $display("Error: Failed to open file, numbers.txt\nExiting Simulation."); 92 | $finish; 93 | end 94 | 95 | #100; 96 | aresetn = 1; 97 | #100; 98 | 99 | // Loop while data is being read from file 100 | // (i will be -1 when end of file or 0 for blank line) 101 | while (i>0) begin 102 | i=$fscanf(number_file, "%h", data); 103 | @(posedge aclk); 104 | #1; 105 | s_axis_tdata = data; 106 | s_axis_tvalid = 1; 107 | end 108 | // Close out file when finished reading 109 | $fclose(number_file); 110 | s_axis_tvalid = 0; 111 | #200; 112 | $display("Simulation ended normally"); 113 | $stop; 114 | end 115 | 116 | 117 | endmodule 118 | --------------------------------------------------------------------------------