# ============================================================================ # cpu21-riscv 流水线 CPU —— 一键重建 Vivado 工程 # FPGA:Nexys4DDR / xc7a100tcsg324-1(Vivado 2020.2 实测:建工程 + 综合均通过) # # 目录结构(本脚本所在目录就是工程目录): # create_project.tcl 本脚本 # srcs/rtl/*.v 处理器 RTL(顶层 cpu21_riscv_redirect_int_bpb) # srcs/board/*.v|*.vh 板级顶层、片内 ROM 初始化(含 __FAST 仿真版本) # srcs/constrs/*.xdc 引脚约束与板级母版 # srcs/tb/*.v 测试平台(中断/分支预测、无中断、板级) # srcs/rom/*.hex 测试平台加载的 ROM 镜像 # tools/、programs/ 迷你汇编器与测试程序(改程序、重生成 ROM 用) # 说明文档:cpu21_riscv_redirect_int_bpb说明.md # # 用法: # 1) 建议先删掉本目录下的 pipelined-cpu.xpr,以及 *.runs / *.sim / *.cache / # *.hw / *.gen / *.ip_user_files 等生成目录(不删会在下面报错提示); # 2) 在 Vivado Tcl Shell 里执行: source create_project.tcl # 或命令行: vivado -mode batch -source create_project.tcl -log create.log # 3) 工程就地创建:pipelined-cpu.xpr(源文件仍在 srcs/ 下,不会被搬动)。 # # 脚本用 [info script] 定位自身目录,所以整个文件夹拷到任何路径都能直接用。 # 若想用 Vivado 自动生成的版本,见说明文档“工程分享”一节。 # ============================================================================ set origin_dir [file dirname [file normalize [info script]]] set proj_name "pipelined-cpu" set part_name "xc7a100tcsg324-1" # ---------------------------------------------------------------- 自检 set required [list \ "$origin_dir/srcs/board/cpu21_board_top.v" \ "$origin_dir/srcs/board/cpu21_board_rom.vh" \ "$origin_dir/srcs/board/cpu21_board_rom_fast.vh" \ "$origin_dir/srcs/constrs/cpu21_board_top.xdc" \ "$origin_dir/srcs/tb/tb_cpu21_riscv_redirect_int_bpb.v" \ "$origin_dir/srcs/tb/tb_no_intr.v" \ "$origin_dir/srcs/tb/tb_board_top.v"] set missing {} foreach f $required { if {![file exists $f]} { lappend missing $f } } if {[llength [glob -nocomplain "$origin_dir/srcs/rtl/*.v"]] == 0} { lappend missing "$origin_dir/srcs/rtl/*.v" } if {[llength $missing] > 0} { puts "ERROR: 缺少下列文件,请确认 srcs/ 目录完整:" foreach f $missing { puts " $f" } return 1 } if {[file exists "$origin_dir/$proj_name.xpr"]} { puts "ERROR: 工程已存在:$origin_dir/$proj_name.xpr" puts " 请先删除 .xpr(以及 *.runs / *.sim 等生成目录)后重跑本脚本。" return 1 } # ---------------------------------------------------------------- 建工程 # 只用 -part 建工程,**不依赖"板卡文件"**:Vivado 默认不带 Nexys4DDR 的 board 文件, # 所以 GUI 新建向导的 Boards 页里找不到它;board 只影响"选板/板级预设", # 不影响综合与实现(引脚全在 srcs/constrs/*.xdc 里显式约束)。 # 若以后装了 Digilent 板卡文件(data/boards/board_files/nexys4-ddr),想按板卡建: # create_project $proj_name $origin_dir -part $part_name \ # -board_part digilentinc.com:nexys4ddr:part0:1.1 # (那样工程会记上板卡,别人没装板卡文件就打不开了,所以默认不这么写。) create_project $proj_name $origin_dir -part $part_name # 设计源文件:处理器 RTL + 板级顶层 + 片内 ROM 初始化 add_files -norecurse -fileset sources_1 [glob "$origin_dir/srcs/rtl/*.v"] add_files -norecurse -fileset sources_1 [list \ "$origin_dir/srcs/board/cpu21_board_top.v" \ "$origin_dir/srcs/board/cpu21_board_rom.vh"] set_property file_type {Verilog Header} \ [get_files "$origin_dir/srcs/board/cpu21_board_rom.vh"] # 默认跑哪个内置程序:中断测试程序优先,其次是扫雷,最后是走马灯 demo。 # 修改下面两个开关即可切换板上程序;同一时间只应启用一个。 set use_intrupt_ccab 1 set use_saolei 0 # 中断测试程序的 ROM 初始化。 set intrupt_ccab_rom "$origin_dir/srcs/board/risc-v-intrupt-ccab.vh" if {[file exists $intrupt_ccab_rom]} { add_files -norecurse -fileset sources_1 [list $intrupt_ccab_rom] set_property file_type {Verilog Header} [get_files $intrupt_ccab_rom] } else { puts "NOTE: 还没有 $intrupt_ccab_rom" } # 扫雷程序的 ROM 初始化(由 saolei/tools/build.ps1 生成,可能还不存在)。 # 综合/仿真时定义宏 SAOLEI_ROM 就会用它替换上面的跑马灯 ROM。 set saolei_rom "$origin_dir/srcs/board/cpu21_saolei_rom.vh" if {[file exists $saolei_rom]} { add_files -norecurse -fileset sources_1 [list $saolei_rom] set_property file_type {Verilog Header} [get_files $saolei_rom] } else { puts "NOTE: 还没有 $saolei_rom —— 需要先跑 saolei/tools/build.ps1 生成" } # 关键:sources_1 定义 SAOLEI_ROM,cpu21_board_top.v 里的 `ifdef 链才会用扫雷 ROM # (该宏只影响综合用的 sources_1,仿真 fileset 仍各自用 tb 自带的 ROM) if {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { set_property verilog_define {RISC_V_INTRUPT_CCAB_ROM} [get_filesets sources_1] puts "NOTE: sources_1 已定义 RISC_V_INTRUPT_CCAB_ROM —— 上板跑 risc-v-intrupt-ccab" } elseif {$use_saolei && [file exists $saolei_rom]} { set_property verilog_define {SAOLEI_ROM} [get_filesets sources_1] puts "NOTE: sources_1 已定义 SAOLEI_ROM —— 上板跑扫雷;想跑走马灯把本脚本里 use_saolei 改成 0" } else { puts "NOTE: 未定义 SAOLEI_ROM —— 上板跑走马灯 demo" } # 约束(cpu21_board_top.xdc 是引脚与分频时钟约束) add_files -norecurse -fileset constrs_1 [glob "$origin_dir/srcs/constrs/*.xdc"] # 仿真文件:测试平台 + ROM 镜像 + 快速版 ROM 头文件 add_files -norecurse -fileset sim_1 [list \ "$origin_dir/srcs/tb/tb_cpu21_riscv_redirect_int_bpb.v" \ "$origin_dir/srcs/tb/tb_no_intr.v" \ "$origin_dir/srcs/tb/tb_board_top.v" \ "$origin_dir/srcs/board/cpu21_board_rom_fast.vh"] add_files -norecurse -fileset sim_1 [glob "$origin_dir/srcs/rom/*.hex"] set_property file_type {Verilog Header} \ [get_files "$origin_dir/srcs/board/cpu21_board_rom_fast.vh"] # 第二个仿真 fileset:无中断测试平台(tb_no_intr) create_fileset -simset sim_2 add_files -norecurse -fileset sim_2 [list \ "$origin_dir/srcs/tb/tb_no_intr.v" \ "$origin_dir/srcs/tb/tb_cpu21_riscv_redirect_int_bpb.v"] # ---------------------------------------------------------------- 顶层与顺序 set_property top cpu21_board_top [get_filesets sources_1] set_property top tb_cpu21_riscv_redirect_int_bpb [get_filesets sim_1] set_property top tb_no_intr [get_filesets sim_2] update_compile_order -fileset sources_1 update_compile_order -fileset sim_1 update_compile_order -fileset sim_2 # GUI 仿真默认只跑 1000 ns,这里改成跑完(否则看起来像卡住) foreach fs {sim_1 sim_2} { catch { set_property -name {xsim.simulate.runtime} -value {all} -objects [get_filesets $fs] } } # ---------------------------------------------------------------- 结果汇总 puts "工程已创建:$origin_dir/$proj_name.xpr" puts " sources_1 顶层 = cpu21_board_top(上板:时钟分频 + 片内 ROM/RAM + 引脚)" if {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { set selected_program {risc-v-intrupt-ccab (RISC_V_INTRUPT_CCAB_ROM)} } elseif {$use_saolei && [file exists $saolei_rom]} { set selected_program {扫雷 (SAOLEI_ROM)} } else { set selected_program {走马灯 demo} } puts " sources_1 程序 = $selected_program" puts " sim_1 顶层 = tb_cpu21_riscv_redirect_int_bpb(中断/分支预测)" puts " sim_2 顶层 = tb_no_intr(指令集测试,ROM 镜像在 srcs/rom/)" puts " 下一步:Run Synthesis → Run Implementation → Generate Bitstream,或 Run Simulation" puts " 提示:CPU 时钟 = 100 MHz / CLK_DIV(默认 2)= 50 MHz;改分频比时" puts " cpu21_board_top.v 的 CLK_DIV 与 cpu21_board_top.xdc 的 -divide_by 要一起改。"