基于FPGA的SystemVerilog练习

文章目录

一、认识SystemVerilog

​ SystemVerilog是一种功能强大的硬件描述语言和验证语言。随着电子设计自动化(EDA)技术的不断进步,以及对数字系统设计和验证要求的提高,SystemVerilog应运而生.

SystemVerilog的语言特性

  • 数据类型与建模能力:SystemVerilog提供了丰富的数据类型和强大的建模能力,这使得设计者能够精确地描述硬件的行为和结构。这种高级的数据类型支持,让设计更加灵活且易于理解和维护。
  • 面向对象的特性:与传统的Verilog相比,SystemVerilog增加了面向对象编程的概念,如类、继承和多态等。这使得代码模块性更强,更易于管理和复用,大大提高了开发效率和可维护性。
  • 并发处理的支持:SystemVerilog支持并发处理,允许设计者模拟真实的硬件并行操作环境,这对于描述复杂的硬件系统至关重要。
  • 接口和连接:通过引入接口这一概念,SystemVerilog简化了模块间的通信方式,提高了设计的清晰度和模块间的互操作性。

SystemVerilog的应用领域

  • ASIC与FPGA设计:SystemVerilog被广泛应用于ASIC和FPGA的设计流程中,支持从逻辑综合到验证的各个阶段,能够满足不同规模和复杂度的设计需求。
  • 验证环境构建:SystemVerilog的验证功能特别强大,它为验证工程师提供了构建全面测试套件和验证环境的能力,特别是在复杂的系统级验证中表现出色。
  • 新兴领域的应用:随着技术的发展,SystemVerilog开始在自动驾驶、人工智能、云计算等新兴领域中得到应用,用于构建和验证复杂的系统模型。

SystemVerilog的优势

  • 模块化和可重用性:面向对象的特性使得SystemVerilog的设计更加模块化,易于维护和重用,这有助于缩短产品开发周期并降低成本。
  • 集成的验证功能:SystemVerilog不仅是一个设计语言,它还集成了丰富的验证功能,如约束随机生成、功能覆盖率分析等,这些都是提高验证效率和质量的关键工具。
  • 丰富的生态系统:众多EDA厂商和开源社区的支持,为SystemVerilog提供了强大的工具链和生态系统,从而使得开发者能够更加便捷地进行设计和验证工作。

SystemVerilog的未来发展方向

  • 应用领域的拓展:随着技术的进步和市场需求的变化,SystemVerilog预计将进一步拓展其在多个新兴领域的应用,如物联网、5G通信等。

  • 语言特性的增强:为了跟上技术发展的步伐,SystemVerilog将持续更新其语言特性,包括增强建模能力、扩展验证功能等,以适应更加复杂的设计需求。

  • 工具链的优化与集成:EDA厂商将继续优化SystemVerilog相关工具的性能,提供更加集成化的解决方案,以便为用户提供更加高效和便捷的开发体验。

    ​ 总之,SystemVerilog作为一种先进的硬件描述和验证语言,它的出现极大地推动了数字系统设计和验证领域的发展。通过提供模块化、面向对象的特性,以及集成的验证功能,SystemVerilog不仅提高了设计的质量和效率,还为应对日益增长的设计复杂性提供了强有力的工具。

二、流水灯代码

流水灯部分

复制代码
module led_water_light(
    input wire clk,        // 时钟信号
    input wire rst_n,      // 复位信号,低电平有效
    output reg [7:0] led   // 8个LED灯
);

// 内部逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 8'b00000000; // 复位时所有LED熄灭
    end else begin
        integer i; // 声明整数变量
        for (i = 0; i < 8; i++) begin
            led <= (8'b00000001 << i); // 点亮第i位LED
            #125; // 等待一个时钟周期,假设为20ns,则0.5s需要250个周期
        end
    end
end

endmodule

testbench仿真文件

复制代码
// tb_led_water_light.sv
module tb_led_water_light();

// Parameters
parameter CLK_PERIOD = 20;  // 定义时钟周期参数

// Inputs
logic clk;
logic rst_n;

// Outputs
wire [7:0] led;

// 实例化被测试模块
led_water_light uut (
    .clk(clk),
    .rst_n(rst_n),
    .led(led)
);

// 时钟信号生成
always #(CLK_PERIOD / 2) clk = ~clk;

// 测试序列
initial begin
    // 初始化信号
    clk = 0;
    rst_n = 0;
    
    // 等待一个时钟周期
    #(CLK_PERIOD * 10);
    
    // 释放复位信号
    rst_n = 1;
    
    // 等待足够的时间来观察LED的变化
    #(CLK_PERIOD * 1000); // 等待50个时钟周期,即2ms
    
    // 再次触发复位
    rst_n = 0;
    #(CLK_PERIOD * 10);
    rst_n = 1;
    
    // 继续观察LED变化
    #(CLK_PERIOD * 1000); // 再次等待50个时钟周期,即2ms
    
    // 结束仿真
    $finish;
end

// 监控输出变化
initial begin
    $monitor("Time = %t, rst_n = %b, led = %b", $time, rst_n, led);
end

endmodule


这里加速了一下,实际每个灯亮0.5秒


三、用systemVerilog实现超声波测距

关于HC-SR04模块可以参考我之前stm32的博客https://blog.csdn.net/cbm2001/article/details/139374257?spm=1001.2014.3001.5501

下面是代码:

计时器

复制代码
module 	clk_us(
	input  logic		clk	, //system clock 50MHz
	input  logic		rst_n	, //reset ,low valid	   
	output logic 		clk_us 	  //
);
//Parameter Declarations
	parameter CNT_MAX = 19'd50;//1us的计数值为 50 * Tclk(20ns)

//Interrnal wire/reg declarations
	logic	[5:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 
	
//Logic Description
	
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CNT_MAX - 19'd1;
	
	assign clk_us = end_cnt;
	

endmodule 

测距部分

复制代码
module 	Echo(
	input logic 		clk		, //clock 50MHz
	input logic			clk_us	, //system clock 1MHz
	input logic 		rst_n	, //reset ,low valid  
	input logic 		echo	, //
	output logic [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);
/* 		S(um) = 17 * t 		-->  x.abc cm	*/
//Parameter Declarations
	parameter T_MAX = 16'd60_000;//510cm 对应计数值

//Interrnal wire/reg declarations
	logic			r1_echo,r2_echo; //边沿检测	
	logic			echo_pos,echo_neg; //
	
	logic	[15:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 

	logic	[18:00]	data_r	;
//Logic Description
	//如果使用clk_us 检测边沿,延时2us,差值过大
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end
	
	assign echo_pos = r1_echo & ~r2_echo;
	assign echo_neg = ~r1_echo & r2_echo;
	
	
	always @(posedge clk_us or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end 
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= cnt; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  //echo 低电平 归零
			cnt <= 'd0;  
		end  
	end 
	
	assign add_cnt = echo; 
	assign end_cnt = add_cnt && cnt >= T_MAX - 1; //超出最大测量范围则保持不变,极限
	
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			data_r <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end //always end
	
	assign data_o = data_r >> 1;

endmodule 

led部分

复制代码
module Trig(
	input  logic		clk_us	, //system clock 1MHz
	input  logic		rst_n	, //reset ,low valid	   
	output logic 		trig	  //触发测距信号
);
//Parameter Declarations
	parameter CYCLE_MAX = 19'd300_000;

//Interrnal wire/reg declarations
	logic	[18:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 

//Logic Description	
	
	always @(posedge clk_us or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CYCLE_MAX - 9'd1; 
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 

数码管部分

复制代码
module seg(
    input   logic        clk     ,
    input   logic        rst_n   ,
    input   logic [18:0] data_o  ,
    output  logic [6:0]  hex1    ,
    output  logic [6:0]  hex2    ,
    output  logic [6:0]  hex3    ,
    output  logic [6:0]  hex4    ,
    output  logic [6:0]  hex5    ,
    output  logic [6:0]  hex6    ,
    output  logic [6:0]  hex7    ,
    output  logic [6:0]  hex8     
);

parameter   NOTION  = 4'd10,
            FUSHU   = 4'd11;
parameter   MAX20us = 10'd1000;
logic [9:0]   cnt_20us;
logic [7:0]   sel_r;
logic [3:0]   number;
logic [6:0]   seg_r;
logic [6:0]   hex1_r;
logic [6:0]   hex2_r;
logic [6:0]   hex3_r;
logic [6:0]   hex4_r;
logic [6:0]   hex5_r;
logic [6:0]   hex6_r;
logic [6:0]   hex7_r;
logic [6:0]   hex8_r;



//20微妙计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_20us <= 10'd0;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        cnt_20us <= 10'd0;
    end
    else begin
        cnt_20us <= cnt_20us + 1'd1;
    end
end



//单个信号sel_r位拼接约束
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sel_r <= 8'b11_11_11_10;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        sel_r <= {sel_r[6:0],sel_r[7]};
    end
    else begin
        sel_r <= sel_r;
    end
end

/*拿到数字*/
always @(*) begin
    case (sel_r)
        8'b11_11_11_10:     number  = NOTION                                        ;
        8'b11_11_11_01:     number  = data_o/10_0000                                ;
        8'b11_11_10_11:     number  = (data_o%10_0000)/1_0000                       ;
        8'b11_11_01_11:     number  = ((data_o%10_0000)%1_0000)/1000                ;
        8'b11_10_11_11:     number  = FUSHU                                         ;
        8'b11_01_11_11:     number  = (((data_o%10_0000)%1_0000)%1000)/100          ;
        8'b10_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)/10     ;
        8'b01_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)%10     ;
        default:            number  = 4'd0                                          ;
    endcase
end

/*通过数字解析出seg值*/
always @(*) begin
    case (number)
        4'd0    :       seg_r   =  7'b100_0000;
        4'd1    :       seg_r   =  7'b111_1001;
        4'd2    :       seg_r   =  7'b010_0100;
        4'd3    :       seg_r   =  7'b011_0000;
        4'd4    :       seg_r   =  7'b001_1001;
        4'd5    :       seg_r   =  7'b001_0010;
        4'd6    :       seg_r   =  7'b000_0010;
        4'd7    :       seg_r   =  7'b111_1000;
        4'd8    :       seg_r   =  7'b000_0000;
        4'd9    :       seg_r   =  7'b001_0000;
        NOTION  :       seg_r   =  7'b111_1111;
        FUSHU   :       seg_r   =  7'b011_1111;
        default :       seg_r   =  7'b111_1111;
    endcase
end

always @(*) begin
    case (sel_r)
		8'b11_11_11_10:     hex1_r = seg_r;
		8'b11_11_11_01:     hex2_r = seg_r;
		8'b11_11_10_11:     hex3_r = seg_r;
		8'b11_11_01_11:     hex4_r = seg_r;
		8'b11_10_11_11:     hex5_r = seg_r;
		8'b11_01_11_11:     hex6_r = seg_r;
		8'b10_11_11_11:     hex7_r = seg_r;
		8'b01_11_11_11:     hex8_r = seg_r;
		default:            seg_r  = seg_r;
	endcase
end

assign  hex1 = hex1_r;
assign  hex2 = hex2_r;
assign  hex3 = hex3_r;
assign  hex4 = hex4_r;
assign  hex5 = hex5_r;
assign  hex6 = hex6_r;
assign  hex7 = hex7_r;
assign  hex8 = hex8_r;

endmodule

采样部分

复制代码
module Trig(
	input  logic		clk_us	, //system clock 1MHz
	input  logic		rst_n	, //reset ,low valid	   
	output logic 		trig	  //触发测距信号
);
//Parameter Declarations
	parameter CYCLE_MAX = 19'd300_000;

//Interrnal wire/reg declarations
	logic	[18:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 

//Logic Description	
	
	always @(posedge clk_us or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CYCLE_MAX - 9'd1; 
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 

顶层文件

复制代码
module top (
    input   logic       clk    ,
    input   logic       rst_n  ,
    input   logic       echo    ,
    output  logic       [3:0]led,
    output  logic       trig    , 

    output  logic [6:0]  hex1    ,
    output  logic [6:0]  hex2    ,
    output  logic [6:0]  hex3    ,
    output  logic [6:0]  hex4    ,
    output  logic [6:0]  hex5    ,
    output  logic [6:0]  hex6    ,
    output  logic [6:0]  hex7    ,
    output  logic [6:0]  hex8   
);

wire    [18:0]  data_o;

Trig inster_Trig(
.clk_us	   (clk_us	), //system clock 1MHz
.rst_n	   (rst_n	), //reset ,low valid
.trig	   (trig	)  //触发测距信号
);


clk_us  insert_clk_us(
.clk	    (clk	),
.rst_n	    (rst_n),
.clk_us     (clk_us)	 
);

Echo 	inster_Echo(
.clk	     (clk    	),
.clk_us	     (clk_us	),
.rst_n	     (rst_n  	),  
.echo	     (echo	    ), 
.data_o	     (data_o	) 
);

LED inster_LED(
.clk       (clk  ) ,
.rst_n     (rst_n) ,
.dis       (data_o ) ,
.led       (led  ) 
);

seg inster_seg(
   .clk    (clk   ) ,
   .rst_n  (rst_n ) ,
   .data_o (data_o) ,
   .hex1   (hex1)   ,
   .hex2   (hex2)   ,
   .hex3   (hex3)   ,
   .hex4   (hex4)   ,
   .hex5   (hex5 )  ,
   .hex6   (hex6 )  ,
   .hex7   (hex7 )  ,
   .hex8   (hex8 )  
);
endmodule

引脚绑定


注意HC-SR04模块的连线以自己接线为准

效果

距离<10cm,亮两个灯,那个减号是小数点

距离在10~20cm亮一个灯

距离>20cm,亮三个灯

四、SysTemVerilog与verilog的区别

​ SystemVerilog并不是与Verilog完全相同,而是Verilog的扩展和超集。虽然SystemVerilog继承了Verilog的基本结构和语法,但是它通过引入面向对象编程、动态线程控制、高层抽象数据类型等先进特性,极大地扩展了Verilog的功能。下面是SystemVerilog相对于Verilog的几个主要差异:

1.语言功能的增强

  • 面向对象的特性:SystemVerilog引入了类、继承、多态等面向对象的概念,这不仅提高了代码的重用性和模块化,还使得测试平台的构建更为灵活和强大。
  • 并发模型的改进:SystemVerilog提供了fork-join语法,支持更加精细的并发控制,这对于复杂的验证环境尤其重要。
  • 数据类型的丰富:除了基本的wire和reg类型,SystemVerilog还新增了如logic、enum、struct等多种数据类型,支持更广泛的设计需求。
  • 验证能力的提升
    约束随机生成:SystemVerilog支持带约束的随机生成技术,这可以自动产生更多样化的测试场景,极大地提高验证的覆盖率和效率。
  • 功能覆盖率分析:内置的功能覆盖率分析工具帮助验证工程师精确地量化验证进度,确保设计满足所有功能要求。
  • 断言的支持:通过SVA(SystemVerilog Assertions),SystemVerilog允许设计者在代码中直接嵌入断言,以监测设计行为的特定属性,这对排查问题和确保设计的正确性至关重要。

2.设计流程的优化

  • 接口的概念:SystemVerilog中的接口是一种强大的结构,它允许设计者将相关的信号组合在一起,简化模块间的连接,提高设计的清晰度和可维护性。
  • 时间精度的控制:SystemVerilog提供了更为精确的时间控制机制,支持从秒到飞秒的多种时间单位,这有助于处理高速设计中的时间精度问题。

3.工具社区的支持

  • 更多的工具支持:由于其强大的功能和广泛的应用,多数现代EDA工具都原生支持SystemVerilog,为用户提供了丰富的设计和验证工具链。
  • 活跃的开发社区:围绕SystemVerilog形成了一个活跃的开发社区,许多开源项目和论坛都在不断促进这一语言的发展和完善。

,支持更广泛的设计需求。

  • 验证能力的提升
    约束随机生成:SystemVerilog支持带约束的随机生成技术,这可以自动产生更多样化的测试场景,极大地提高验证的覆盖率和效率。
  • 功能覆盖率分析:内置的功能覆盖率分析工具帮助验证工程师精确地量化验证进度,确保设计满足所有功能要求。
  • 断言的支持:通过SVA(SystemVerilog Assertions),SystemVerilog允许设计者在代码中直接嵌入断言,以监测设计行为的特定属性,这对排查问题和确保设计的正确性至关重要。
相关推荐
仲南音1 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner2 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20202 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子3 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议