当前位置: 首页 > article >正文

verilog测试平台设计与verilog的synthesis

verilog测试平台的设计与verilog的synthesis

verilog模块代码在写好后,还需要进行调试和仿真,这有些类似于hspice中的测试文件,也要包括声明,激励定义,结果处理。Testbench(测试平台)是数字电路设计验证中的核心工具,用于模拟和验证硬件设计(DUT, Design Under Test)的功能正确性。其核心原理是通过仿真环境生成输入激励、监测输出响应,并与预期结果对比。以下是编写原理的详细说明:

一个典型的 Testbench 包含以下模块:

  • DUT 实例化:将被测设计连接到 Testbench。
  • 激励生成模块:模拟输入信号(如时钟、复位、数据等)。
  • 监控模块:实时捕获 DUT 的输出信号。
  • 自动检查模块:对比输出结果与预期值(Golden Model)。

DUT实例化

DUT就是design under test,DUT模块在被设计好后需要在testbench中进行实例化。DUT示例化的示例代码如下:

module counter (//模块定义
  input clk,       // 输入端口:时钟
  input reset,     // 输入端口:复位
  input enable,    // 输入端口:使能
  output [3:0] count  // 输出端口:计数值
);
module testbench;
  reg tb_clk;      // 测试平台生成的时钟信号(reg类型,驱动DUT输入)
  reg tb_reset;    // 测试平台生成的复位信号
  reg tb_enable;
  wire [3:0] tb_count;  // 接收DUT的输出(wire类型)
endmodule
counter dut (//实例化,通常是模块端口名在前而测试平台的信号名在后
  .clk(tb_clk),     // DUT的clk端口 <—— 测试平台的tb_clk信号
  .reset(tb_reset), 
  .enable(tb_enable),
  .count(tb_count)  
);

二者之间的映射关系具体如下所示:

在这里插入图片描述

激励生成

在Verilog测试平台设计中,激励生成对于测试模块编写的正确性至关重要。这里主要介绍三个部分的激励生成:

时钟与复位:基础激励,需严格同步。

数据激励:支持确定性和随机生成。

同步控制:使用 @(edge)#delay 控制时序。

// 示例:生成50MHz时钟(周期20ns)
reg clk;
initial begin
  clk = 0;
  forever #10 clk = ~clk;  // 每10ns翻转一次,使用forever来无限次的循环,#10是延迟10ns
end
//示例:复位信号的生成
reg reset;
initial begin
  reset = 1;     // 初始复位有效
  #100 reset = 0; // 100ns后释放复位
end
//示例:确定性输入数据的激励生成
reg [7:0] data;
initial begin//开始Initial逻辑块
  data = 8'h00;  // 初始值
  #20 data = 8'hFF;//经典的8位二进制,二位16进制
  #20 data = 8'h55;
  #20 data = 8'hAA;
end

这里顺带补充一下在verilog测试平台开头往往要去规定测试时间步和测试精度的,规定的具体格式如下所示,一般来说,测试时间步长是1ns,测试精度是1ps.

`timescale 1ns / 1ps   // 时间单位为1ns,精度为1ps
`timescale <时间单位> / <时间精度>

监控模块

在Verilog中,监控语句用于实时跟踪信号变化、输出调试信息或验证设计行为,是测试平台(Testbench)调试和验证的关键工具。在Verilog仿真中,initial逻辑块是测试平台(Testbench)设计的核心组成部分,用于定义仿真开始时的初始化和激励生成逻辑,重要的仿真代码都是写在initial逻辑块中的,所有initial逻辑块在仿真开始的时候立刻并行执行。以下是Verilog中常用监控语句的详细说明及其应用场景:

$display(format_string, arg1, arg2, ...);  // 自动换行,dsiplay和write是直接输出相关信息的,类似于printf函数
$write(format_string, arg1, arg2, ...);    // 不换行
initial begin//initial逻辑块
  $display("仿真开始,时间:%t", $time);  // 显示当前仿真时间
  #10;
  $write("信号A=%b, ", a);              // 不换行输出
  $display("信号B=%h", b);              // 换行输出
end

monitor语句持续监控指定信号变化,当任何被监控信号发生变化时,自动触发输出。而且重要的是全局只有一个monitor语句会生效,其余的都会被最后出现的覆盖掉。

initial begin
    $monitor("时间=%t, a=%b, b=%h", $time, a, b); // 监控a和b的变化,当 a 或 b 的值变化时,自动打印当前时间和信号值。

end

相关的格式化字符与其对应的含义如下:

符号说明
%b二进制格式
%d十进制格式
%h十六进制格式
%t时间格式
%s字符串格式

strobe语句会在当前时间步结束时输出信号值,确保获取稳定的信号状态。触发时机时间步结束前(所有非阻塞赋值完成后)。示例代码如下:

always @(posedge clk) begin
  $strobe("时钟上升沿时刻:a=%d, b=%d", a, b); // 在时钟边沿后输出稳定值
end

自动检查部分

在Verilog测试平台中,自动检查(Automatic Checking) 是验证设计正确性的核心机制。其核心目标是无需手动查看波形,通过代码自动比对DUT输出与预期结果,并实时报告错误。以下是自动检查的设计原理、实现方法和最佳实践。下面的代码中是进行直接自动检查的示例:

always @(posedge clk) begin
  if (!reset && enable) begin
    // 检查计数器是否递增
      if (count !== expected_count) begin//假如count与expected_count的值不相同则报错
      $error("错误:预期值=%h,实际值=%h", expected_count, count);//报错
      $finish; // 可选:终止仿真
    end
    expected_count <= expected_count + 1; // 更新预期值
  end
end

实践与分析:

一个简单的CPU的构造如下所示

【FPGA】设计一个简单CPU—Verlog实现_fpga设计cpu-CSDN博客

在verilog中实现一个CPU步骤较为复杂, 但是若简单实现CPU的若干功能则较为简答, 下面的verilog代码实现了一个最为简单的CPU的设计和验证:

module SimpleCPU (
    input clk,
    input reset,
    output [7:0] data_out
);
    reg [7:0] PC, ACC, IR;
    reg [7:0] ROM [0:15];//Read only memory 
    reg [7:0] RAM [0:15];//random access memory
    parameter FETCH = 0, EXECUTE = 1;//两个状态,存与取
    reg state;

    // 初始化ROM(指令)
    initial begin
        ROM[0] = 8'b0000_0001; // LOAD 1 +地址
        ROM[1] = 8'b0001_0010; // ADD 2 +地址
        ROM[2] = 8'b0010_0011; // STORE 3 +地址
        ROM[3] = 8'b1111_1111; // HALT
    end

    // 初始化RAM(数据)
    initial begin
        RAM[1] = 8'h05; // 地址1存5
        RAM[2] = 8'h03; // 地址2存3
    end

    // 主状态机
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            PC <= 0;
            ACC <= 0;
            IR <= 0;
            state <= FETCH;
            // 复位时初始化RAM(可选)
            for (integer  i=0; i<16; i++) RAM[i] <= 8'h00;
            RAM[1] <= 8'h05;
            RAM[2] <= 8'h03;
        end else begin
            case (state)
                FETCH: begin
                    IR <= ROM[PC];
                    PC <= PC + 1;
                    state <= EXECUTE;
                end
                EXECUTE: begin
                    case (IR[7:4])
                        4'b0000: ACC <= RAM[IR[3:0]];  // LOAD
                        4'b0001: ACC <= ACC + RAM[IR[3:0]]; // ADD
                        4'b0010: RAM[IR[3:0]] <= ACC;  // STORE
                        4'b1111: state <= EXECUTE;     // HALT:冻结状态机,进入循环执行状态
                        default: ;
                    endcase
                    state <= FETCH;
                end
            endcase
        end
    end

    assign data_out = ACC;//输出信号
endmodule
//SimpleCpu.v
module SimpleCPU_tb;

// 信号定义
reg clk;
reg reset;
wire [7:0] data_out;

// 实例化CPU
SimpleCPU uut (
    .clk(clk),
    .reset(reset),
    .data_out(data_out)
);

// 生成时钟(周期=10ns)
initial begin
    clk = 1;
    forever #5 clk = ~clk;//这里的代码是永远每隔五ns翻转一次时钟信号
end

// 测试流程
initial begin
    reset = 1;  // 复位
    #10 reset = 0;//10ns后reset键设为0

    // 观察执行过程
    #80; // 等待8个时钟周期(LOAD -> ADD -> STORE -> HALT),每二个时钟周期会执行一次命令

    // 打印最终结果
    $display("ACC = %h", data_out);//打印输出ACC累加器寄存器的值
    $display("RAM[3] = %h", uut.RAM[3]);//打印输出RAM固定位置的值
    $stop;
end

endmodule
//应该保存为SimpleCpu_tb.v

仿真测试结果如下:

在这里插入图片描述

CPU的基础理论其实是比较简单的,实现的无非是存,取,运算三大指令。

Synthesis综合初探

在Verilog中,综合(synthesis)是将Verilog代码转换成硬件电路的过程。这个过程是由电子设计自动化(EDA)工具完成的,通常称为综合工具。ASIC库(Application-Specific Integrated Circuit Library)是一组预先设计好的、可重用的硬件模块和元件的集合,它们用于在ASIC设计中实现特定的功能。这些库通常由半导体制造商或第三方EDA(电子设计自动化)工具提供商提供,并且与特定的工艺技术紧密相关。

以下是Verilog代码的综合过程的主要步骤:

  1. 设计输入

综合过程的第一步是提供设计输入,即编写好的Verilog代码。这个代码应该遵循一些编写规则,以确保可综合性,例如避免使用不可综合的语法(如initial块、$display等)。

  1. 解析和预处理

综合工具首先解析Verilog代码,检查语法错误,并将代码分解成更小的单元,如模块、实例、端口、信号等。预处理步骤还会处理宏定义和文件包含指令。

  1. 高层次综合(High-Level Synthesis, HLS)

在这个阶段,综合工具将Verilog代码中的行为描述(如always块)转换成更高层次的架构描述。这个过程可能包括算法优化、循环展开、资源共享等。

  1. 逻辑优化

综合工具会对设计进行逻辑优化,以减少资源使用和提高性能。这可能包括:

  • 删除未使用的信号和模块。
  • 合并逻辑门。
  • 简化逻辑表达式。
  • 优化时序路径。
  1. 映射到库

综合工具会将Verilog代码中的逻辑元素映射到FPGA或ASIC库中的具体单元,如查找表(LUTs)、触发器(FFs)、乘法器、RAM等。

  1. 约束和时序分析

在这个阶段,综合工具会考虑设计者提供的时序约束(如时钟周期、建立时间和保持时间等),并尝试满足这些约束。如果无法满足,工具会报告时序违规。

  1. 生成网表

综合过程的最终输出是一个网表(netlist),这是一个包含所有逻辑单元和它们之间连接关系的描述。网表是电路的图形表示,通常以特定格式(如EDIF、VHDL等)保存。

  1. 后续流程

综合完成后,如果是ASIC设计,网表将用于后续的布局和布线(layout and routing)流程;如果是FPGA设计,网表将输入到FPGA的布局和布线工具中,最终生成配置FPGA的比特流文件。

等。

  1. 约束和时序分析

在这个阶段,综合工具会考虑设计者提供的时序约束(如时钟周期、建立时间和保持时间等),并尝试满足这些约束。如果无法满足,工具会报告时序违规。

  1. 生成网表

综合过程的最终输出是一个网表(netlist),这是一个包含所有逻辑单元和它们之间连接关系的描述。网表是电路的图形表示,通常以特定格式(如EDIF、VHDL等)保存。

  1. 后续流程

综合完成后,如果是ASIC设计,网表将用于后续的布局和布线(layout and routing)流程;如果是FPGA设计,网表将输入到FPGA的布局和布线工具中,最终生成配置FPGA的比特流文件。

比较常用的synthesis工具就有vivado综合IDE,其是赛力斯公司旗下FPGA开发板 的配套设计工具,我在大二的时候经常使用其烧录比特流并验证。


http://www.kler.cn/a/558983.html

相关文章:

  • 使用 CloudDM 和飞书流程化管理数据库变更审批
  • Swift Data 切片:data.subdata(in:) vs data[Range<Index>] 深度解析
  • 03 二层广播和三层广播
  • 进程概念、PCB及进程查看
  • MusicGPT的本地化部署与远程调用:让你的Windows电脑成为AI音乐工作站
  • 高性能GPU计算:释放计算潜力的加速利器
  • 基于拼接的宏基因组全流程
  • Day1 初识AndroidAudio
  • OpenSSL实验
  • 网络安全研究
  • Python常用的函数和功能
  • 黑马点评 面试话术
  • 蓝桥杯 Java B 组之背包问题(01背包、完全背包)
  • Pytorch使用手册-音频特征提取(专题二十一)
  • [Android] GKD v1.10.0 β1—— 开屏 及 内部信息流 广告跳过工具
  • 鸿蒙5.0实战案例:基于ArkUI的验证码实现
  • 菜鸟养成记--Java篇(一)类型转换
  • Docker入门及基本概念
  • 基于ffmpeg+openGL ES实现的视频编辑工具-添加背景音乐(十一)
  • C1车证学习笔记