System Verilog实现流水灯

发布于:2024-06-10 ⋅ 阅读:(178) ⋅ 点赞:(0)

一 System Verilog

如果没有硬件描述语言(HDL hardware description language)?
kimi的回答 :需要手动绘制电路原理图、手动布线、要打出电路板后测试验证设计的正确性…
没有HDL,数字硬件电路的设计和设置将更加依赖于手动操作和物理原型,这将大大增加设计周期、成本和出错的风险。此外,设计过程将更加繁琐,且难以实现现代电子系统中常见的复杂性和灵活性。
硬件描述语言可以做什么?
数字电路和系统的设计、建模、仿真、验证和综合。以文本形式描述数字电路的行为和结构,从而创建电路的模型。模拟电路功能,完成仿真。完成电路的优化(综合)。自动化布局和布线。与EDA集成。
硬件验证语言(Hardware Verification Language, HVL):Open Vera ,e语言,PSL,SystemC,SystemVerilog等

1.1 Systemverilog简介

SystemVerilog既是硬件描述语言(rtl(Register Transfer Level)级),也是硬件验证语言(testbench)。用于为ASIC和FPGA/SoC算法和系统建模、设计、仿真、验证、测试和实现。SystemVerilog基于Verilog语言并进行了大量扩张,并在2009年与Verilog一样称为了同一IEEE标准的一部分。支持有约束随机验证、断言和功能覆盖率,并且支持面向对象的编程。

1.2 与verilog的区别

新增数据类型:

  • 两态(I/O)数据类型
  • 枚举类型和用户自定义类型
  • 动态数组、关联数组和队列
  • 联合体和结构体
  • 字符串

1.2.1 两态数据类型(1,0)

verilog中有两种基本数据类型,reg和wire,都是四态数据类型(0,1,Z,X)。存储组合逻辑和时序逻辑的数据类型可以是标量,向量(reg[7:0]),integer,time,real,可以定义一个固定大小的数组。存储都是静态的。

systemverilog中引入两态数据类型 bit(无符号的),short int , int, longint, byte
在这里插入图片描述
logic是system verilog引入的新的四态数据类型,system verilog对reg的数据类型做了改进,可以被连续赋值语句(assign)、门逻辑和模块直接驱动(可以同时用于时序和组合逻辑)。
kimi写的例子:

module top_module;
    // 定义一个reg类型的变量,它可以被连续赋值语句驱动
    reg my_signal;

    // 连续赋值语句,类似于Verilog-1995中的wire
    assign my_signal = some_condition ? 1'b1 : 1'b0; // some_condition是一个条件表达式

    // 时钟信号
    input clk;

    // 时序逻辑,my_signal也可以在这里被赋值
    always_ff @(posedge clk) begin
        my_signal <= another_condition ? 1'b1 : 1'b0; // another_condition是另一个条件表达式
    end

    // 其他逻辑...
endmodule

1.2.2 枚举类型和用户自定义类型

枚举:

// enum [data_type] {name1 = value1, name2 = value2...} var_name;
enum {red, yellow, green} light1, light2;
//使用
light1 = red;
//错误使用
light1 = 0;

在这里插入图片描述
用户自定义类型:

parameter OPSIZE=8;
//将reg[7:0] 定义为opreg_t
typedef reg[OPSIZE-1:0] opreg_t;
//使用
opreg_t op_a, op_b;
module test_typedef();
	typedef enum {red, green, blue, yellow, white, blach} colors;
	colors my_colors;
	initial
		begin
			$display("my_color's default value is %s", my_colors);
			my_colors = green;
			my_colors = colors'(2);
			$display("my_color's %s",my_colors.name);
		end
endmodule

1.2.3 数组与队列

在这里插入图片描述

  • 静态数组

静态数组扩展了原始数组的概念,允许编程者定义每一位是如何存储的。

bit [7:0] c1; //压缩数组(维数定义在变量标识符之前),可以被指定为任何网线或者标量类型。
real u [7:0]; //非压缩数组(维数定义在变量标识符之后),任何数据类型

//静态数组的通用定义方法
//element_data_type [PRange1]...[PRangeN] array_name [Urange1]...[UrangeM];
bit [3:0][7:0] reg_32;
bit [3:0][7:0] mix_array[3]

在这里插入图片描述

  • 动态数组
//data_type array_name [];
bit [3:0] nibble[]; //4bit向量的动态数组;

动态数组实例:

module test_dy_array();
	int dyn1[],dyn2[];
	initial begin
		dyn1 = new [100]; //分配100个
		foreach(dyn1[i])
			dyn2[i] = i;
			dyn2 = new [100](dyn1); //复制一个动态数组
			dyn2[0] = 5;
	end
endmodule

还有一些内置函数,size()、delete等。使用.语法调用。

  • 队列
    队列是一个大小可变,具有相同数据类型成员的有序集合。0代表第一个成员,$代表最后一个成员。
byte q1[$]; //字节队列
string names[$] = {"Bob"};//字符串格队列

1.2.4 字符串

string myName = "John Smith";

操作符:
== !={str1,str2}{n |str|} 复制n次strstr[index]str.method()
内置方法:
在这里插入图片描述

1.2.5 结构体和联合体

实例:

module struct_example();
	struct {
		bit[7:0] my_byte;
		int my_data;
		real pi;
	}my_struct;
	initial begin
		my_struct.my_byte = 8'hab;
		my_struct=`{0,99,3.14}`;
	end
endmodule

1.2.6 常量

parameterlocalparamspecparamconst

1.2.7 过程语句

在这里插入图片描述
赋值包括了阻塞、非阻塞、自加/减、过程连续赋值语句。
控制结构包括了条件选择语句if…else,case;循环语句 for ,while, do…while,repeat,forever;跳转语句break,continue,return

等等

二 流水灯代码

led_flow.sv

module led_flow (
    input logic clk,       // 时钟信号
    input logic rst_n,     // 复位信号(低有效)
    output logic [7:0] led // 8位LED输出
);

    logic [23:0] counter;  // 24位计数器,用于产生慢时钟信号

    // 计数器逻辑
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            counter <= 24'd0;
        else
            counter <= counter + 1;
    end

    // LED流水灯逻辑
    always_ff @(posedge counter[23] or negedge rst_n) begin
        if (!rst_n)
            led <= 8'b0000_0001;
        else
            led <= {led[6:0], led[7]};
    end
endmodule

testbench

module led_flow_tb;
    logic clk;
    logic rst_n;
    logic [7:0] led;

    // 实例化待测试的流水灯模块
    led_flow uut (
        .clk(clk),
        .rst_n(rst_n),
        .led(led)
    );

    // 时钟信号生成
    initial begin
        clk = 0;
        forever #10 clk = ~clk; // 50MHz时钟周期为20ns
    end

    // 测试逻辑
    initial begin
        // 初始化信号
        rst_n = 0;
        #100;
        rst_n = 1;

        // 仿真运行一段时间后结束
        #1000000;
        $stop;
    end
endmodule

三 实验效果

在这里插入图片描述
testbench效果
在这里插入图片描述

总结

参考资料

system verilog绿皮书