目录
[Run Analysis -> Schematic](#Run Analysis -> Schematic)
[SYNTHESIS -> Run Synthesis](#SYNTHESIS -> Run Synthesis)
[添加VIO IP](#添加VIO IP)
[Set Up Debug](#Set Up Debug)
[生成Bit Stream](#生成Bit Stream)
[下载Bit Stream](#下载Bit Stream)
[添加 VIO dashboard](#添加 VIO dashboard)
======
新建工程

======

======

======
添加源文件
design source



===
constrain source



======
编辑源文件
编辑source文件
// Encoding: GB2312
// Generate_PWM.v
/*
实际设计要点与建议
(一)端口声明规则:
牢记输入端口和双向端口只能是 wire 型
输出端口则根据驱动方式决定:若在过程块内赋值,声明为 output reg;若用 assign 驱动,声明为 output wire(或直接省略 wire)
(二)变量选择原则:
先根据设计意图(组合逻辑还是时序逻辑)选择使用 assign 还是 always 块。
再根据赋值位置决定变量类型,在 always 块中操作的变量应声明为 reg,即使最终综合出来的是组合逻辑
(三)避免常见陷阱:
不可在 always 块中对 wire 型变量进行赋值
不可使用 assign 语句对 reg 型变量进行赋值
用于描述时序逻辑的 always 块中,推荐使用非阻塞赋值 (<=) 来避免仿真竞争风险。
(四)理解这些关键字的关键在于跳出"软件编程"思维,时刻思考其对应的硬件电路结构:
wire 是导线, assign 是连接关系;
reg 是存储单元或中间变量, always 是根据条件触发的行为描述。
只有清晰地区分连续赋值(wire+assign)与过程赋值(reg+always/initial)这两大范式,才能更准确地用 Verilog 来描述所需的硬件功能。
*/
`timescale 1ns / 1ps
module Generate_PWM #(
parameter CLK_FREQ = 50_000_000, // 输入时钟频率 (50MHz)
parameter PWM_FREQ = 1_000, // 目标PWM频率 (1KHz)
parameter DUTY_CYCLE = 50 // 占空比百分比 (0-100)
) (
input wire clk_sys, // 输入时钟
(* MARK_DEBUG="true" *) output reg pwm_o // PWM输出 (* MARK_DEBUG="true" *)
);
// 计算计数器位宽和阈值
localparam COUNTER_MAX = CLK_FREQ / PWM_FREQ - 1;
localparam COUNTER_WIDTH = $clog2(COUNTER_MAX + 1);
localparam DUTY_COUNT = (COUNTER_MAX + 1) * DUTY_CYCLE / 100;
(* MARK_DEBUG="true" *) wire [0:0] rst_sys; //(* MARK_DEBUG="true" *)
wire [7:0] VLASampleFreqDivSetByVIO;
reg [COUNTER_WIDTH-1:0] counter;
always @(posedge clk_sys or negedge rst_sys) begin
if (!rst_sys) begin
counter <= 'd0;
pwm_o <= 1'b0;
end else begin
// 循环计数
if (counter == COUNTER_MAX) begin
counter <= 'd0;
end else begin
counter <= counter + 1'b1;
end
// 生成PWM波形
if (counter < DUTY_COUNT) begin
pwm_o <= 1'b1;
end else begin
pwm_o <= 1'b0;
end
end
end
(* MARK_DEBUG="true" *) reg [7:0] vla_trigger_counter; // (* MARK_DEBUG="true" *)
wire vla_trigger;
always @(posedge clk_sys or negedge rst_sys) begin
if (!rst_sys) begin
vla_trigger_counter <= 0;
end else if (vla_trigger_counter >= VLASampleFreqDivSetByVIO - 1) begin
vla_trigger_counter <= 0;
end else begin
vla_trigger_counter <= vla_trigger_counter + 1;
end
end
assign vla_trigger = (vla_trigger_counter == VLASampleFreqDivSetByVIO - 1);
endmodule
添加 (* MARK_DEBUG="true" *)

======
Run Analysis -> Schematic

===
SYNTHESIS -> Run Synthesis


======
管脚约束


时序约束

约束文件中多了时序约束的语句
set_property IOSTANDARD LVCMOS33 [get_ports clk_sys]
set_property IOSTANDARD LVCMOS33 [get_ports pwm_o]
set_property PACKAGE_PIN U18 [get_ports clk_sys]
set_property PACKAGE_PIN T14 [get_ports pwm_o]
create_clock -period 20.000 -name clk_sys -waveform {0.000 10.000} [get_ports clk_sys]
======
添加VIO IP




把复制的代码添加到源文件最后,并做如下修改
vio_0 instance_vio_0_0 (
.clk (clk_sys), // input wire clk
.probe_out0(rst_sys), // output wire [15 : 0] probe_out0
.probe_out1(VLASampleFreqDivSetByVIO) // output wire [15 : 0] probe_out0
);
完整代码如下
// Encoding: GB2312
// .v
/*
实际设计要点与建议
(一)端口声明规则:
牢记输入端口和双向端口只能是 wire 型
输出端口则根据驱动方式决定:若在过程块内赋值,声明为 output reg;若用 assign 驱动,声明为 output wire(或直接省略 wire)
(二)变量选择原则:
先根据设计意图(组合逻辑还是时序逻辑)选择使用 assign 还是 always 块。
再根据赋值位置决定变量类型,在 always 块中操作的变量应声明为 reg,即使最终综合出来的是组合逻辑
(三)避免常见陷阱:
不可在 always 块中对 wire 型变量进行赋值
不可使用 assign 语句对 reg 型变量进行赋值
用于描述时序逻辑的 always 块中,推荐使用非阻塞赋值 (<=) 来避免仿真竞争风险。
(四)理解这些关键字的关键在于跳出"软件编程"思维,时刻思考其对应的硬件电路结构:
wire 是导线, assign 是连接关系;
reg 是存储单元或中间变量, always 是根据条件触发的行为描述。
只有清晰地区分连续赋值(wire+assign)与过程赋值(reg+always/initial)这两大范式,才能更准确地用 Verilog 来描述所需的硬件功能。
*/
`timescale 1ns / 1ps
module Generate_PWM #(
parameter CLK_FREQ = 50_000_000, // 输入时钟频率 (50MHz)
parameter PWM_FREQ = 1_000, // 目标PWM频率 (1KHz)
parameter DUTY_CYCLE = 50 // 占空比百分比 (0-100)
) (
input wire clk_sys, // 输入时钟
(* MARK_DEBUG="true" *) output reg pwm_o // PWM输出 (* MARK_DEBUG="true" *)
);
// 计算计数器位宽和阈值
localparam COUNTER_MAX = CLK_FREQ / PWM_FREQ - 1;
localparam COUNTER_WIDTH = $clog2(COUNTER_MAX + 1);
localparam DUTY_COUNT = (COUNTER_MAX + 1) * DUTY_CYCLE / 100;
(* MARK_DEBUG="true" *) wire [0:0] rst_sys; //(* MARK_DEBUG="true" *)
wire [7:0] VLASampleFreqDivSetByVIO;
reg [COUNTER_WIDTH-1:0] counter;
always @(posedge clk_sys or negedge rst_sys) begin
if (!rst_sys) begin
counter <= 'd0;
pwm_o <= 1'b0;
end else begin
// 循环计数
if (counter == COUNTER_MAX) begin
counter <= 'd0;
end else begin
counter <= counter + 1'b1;
end
// 生成PWM波形
if (counter < DUTY_COUNT) begin
pwm_o <= 1'b1;
end else begin
pwm_o <= 1'b0;
end
end
end
(* MARK_DEBUG="true" *) reg [7:0] vla_trigger_counter; // (* MARK_DEBUG="true" *)
wire vla_trigger;
always @(posedge clk_sys or negedge rst_sys) begin
if (!rst_sys) begin
vla_trigger_counter <= 0;
end else if (vla_trigger_counter >= VLASampleFreqDivSetByVIO - 1) begin
vla_trigger_counter <= 0;
end else begin
vla_trigger_counter <= vla_trigger_counter + 1;
end
end
assign vla_trigger = (vla_trigger_counter == VLASampleFreqDivSetByVIO - 1);
vio_0 instance_vio_0_0 (
.clk (clk_sys), // input wire clk
.probe_out0(rst_sys), // output wire [15 : 0] probe_out0
.probe_out1(VLASampleFreqDivSetByVIO) // output wire [15 : 0] probe_out0
);
endmodule
======
Set Up Debug
点OK关闭,通过SYNSIS -> Set Up Debug 配置Debug
配置前先保存并综合一下



======
生成Bit Stream

======
下载Bit Stream


======
调试
添加 VIO dashboard


======
运行调试
不降采样调试

降采样调试

配置不同采样频率

查看效果

======
======
======
======