System Verilog 要点概览

news2025/2/24 14:26:29

二进制

常量

格式:二进制位宽+'+进制符号(b:2;h:16;d:10)+数据

1'b1
1'b0
16'habcd
4'd10

变量

logic a;//一位二进制
logic [3:0]b;//4位二进制
logic [31:0][31:0]c;//32*32位二进制

组合/位绑定

{a, 1'b1}//高位是a,低位是常数二进制1的两位向量
{a, b}//五位二进制,最高位a,低四位b
{16{1'b1}}//16位全1
{a, 16{b}}//

运算符

基本运算符

在这里插入图片描述

缩位运算符

在这里插入图片描述
运算符不能视为向量,例如(a+b)[3:0]的写法是错误的

赋值语句

变量 = 表达式

  • 等号左边的变量,可以是单个变量,也可以是 {a,b], 但不能有常量或运算符
  • 等号右边的表达式,可以是单个变量或常量,也可以是 {a + b,1’b1],要注意位数

电路语句1——assign

现有电路图再有电路语句,电路代码包括以下几个部分:

  • 二进制信号声明
  • 数字元件
  • 电路连接

assign语句是一种电路语句,可以描述一部分电路,这些电路的的作用是运算符的功能
assign语句的基本形式为: assign 赋值语句;

logic [31:0]a,b,c;
assign c = a&b;

适用于简单组合电路;已有电路图 (仅包含基本元件)或逻辑表达式的组合电路

电路语句2——元件例化语句

需求:

  • 层次化设计、功能区分
  • 代码复用
  • 黑盒

1.模块声明

module adder(
	//输入和输出声明
	input logic  [3:0]a,b,
	output logic [3:0]c
);
	//电路代码
	assign c = a +b;
endmodule

2.元件例化

  • 输入:可以接变量、常量、表达式、未绑定
  • 输出:只能接变量,
logic [3:0] b,c;
//模块名 元件名(接口对应:.+端口名(信号名))
adder adder_inst0(.a(4'b0010), .b, .*);//assign c = 4'b0010 + b
//等效于adder adder_inst(.a(4'b0010), .b(b), .*);
//.b与.b(b)等效的条件:信号名和端口名一致
//也等效于adder adder_inst(.a(4'b0010), .*);
//.*即未用的其他同位宽变量,如果位宽不同将报错
adder adder_inst1(.a[0](1'b0));//错误写法,端口名是一个整体,必须要整个对应

电路语句3——always_comb

always_comb用于描述复杂电路

always_comb begin
	a = 1'b1;
	b = a;
	a = 1'b0;
	c = a;
end

always_comb内部每条语句都是赋值语句。不能出现电路语句
always_comb内部描述电路行为。
always_comb有以下性质:

  • 内部覆盖性:后面的赋值覆盖前面的赋值
  • 对外原子性:
assign a = b;
always_comb begin
	b = 1'b1;
	c = a;// c = b;
	b = 1'b0;
end
//结果:a=b=c=0(c=a时)
//结果:a=b=0,c=1(c=b时)
  • 阻塞赋值
    always_comb内部还支持if、case等控制语句:

always_comb内部的控制语句:case

case语句常用于描述选择器和译码器

unique case

有unique,表明其中有一项符合要求,允许并行比较

always_comb begin
	unique case (a[3:0])
		4'd1:begin 
		end
		4'd0:begin
		end
		default:begin
		end
	endcase
end

如果没有default,遇到不匹配时将什么都不做

priority case

always_comb begin
	priority case (1'b1)
		a[3]:begin 
		end
		a[2]:begin
		end
		default:begin
		end
	endcase
end
always_comb begin
	if(a[3]) begin
	end else if(a[2]) begin
	end else if()//.....
end

always_comb内部的控制语句:if和for

if和for是always_comb 中的常用语法。

if

if和else用于条件判断

always_comb begin
	if(a[3])begin
		b = 1'b1;
	end else if(a[2])begin
		b = 1'b0;
	end else begin
	end
end

和case要有default类似,在always_comb 中,if也应有else。

for

for在always_comb中,会被解释为循环展开。
for相关的语句:break,continue

logic [15:0]a;
logic [3:0]b;

always_comb begin
	b = '0;
	for (int i = 15; i >= 0; i--)begin
		if(a[i]) begin
			b = i[3:0];
			break;			
		end
	end
end

循环变量的上下界都应为常数。

always_comb begin 
	for(int i = 0; i < 16; i++) begin
		if(i > n) break;
	end
end

for和if即可表示行为,也可生成电路

always_comb begin
	for(int i = 0; i < 16; i++) begin
		a[i] = b[i] & (c[i] == d[i] | e[i]);//编译器不认为i是常数,a[i,i+3]非法
	end
end

for(genvar i = 0; i < 16; i++) begin
	assign a[i] = b[i] & (c[i] == d[i] | e[i]);//编译器认为i是常数,a[i,i+3]合法
	always_comb begin

	end
end

电路语句4——always_ff

always_ff 用于描述触发器

  • always_ff全部使用<=的非阻塞赋值(并行)
  • always_comb全部使用=的阻塞赋值
always_ff @(posedge clk, negedge resetn) begin
	if(~resetn)begin
		q <= 0';
	end else if(en) begin
		q <= d;
	end
end

always_ff 里可以描述很复杂的逻辑,但那样写不直观。写代码时,也应该参考状态方程

logic [3:0] a,a_nxt;
always_ff @(posedge clk) begin
	if(~resetn)begin
		a < '0;
	end else if(en) begin
		/*
		unique case(a)
			4'd3: a <= 4'd2;
			default: a <= 4'd3;
		endcase
		*/ 
		a <= a_nxt;
		{b,c} <= {b_nxt,c_nxt};
		// b <= a;//b赋的是上升沿时刻a的值,可能与a_nxt不同
	end
end 

always_comb begin
	a_nxt = a;
	b = a_nxt;//b=a
	unique case(a)
		4'd3: begin
			a_nxt = 4'd2;
		end
		default: begin
		end
	endcase
end 

高级语法1——typedef

1. typedef

数字电路中,万物皆为二进制。
类型同一为logic,符合这一规律。但这对程序员,可能不太友好。

  • 需要管理变量的位数
  • 同一位数的信号,可能意义完全不同
    对此,引入自定义类型语法 typedef
    基本格式为: typedef 已有类型 新类型;
typedef logic[31:0] word_t;
typedef logic[5:0] entry_t;
typedef entry_t[31:0] table_t;

声明与使用变量的语法:

word_t a,b;
assign b = {a[15:0], a[31:16]};

table_t table1; //logic [31:0][5:0]
assign table1[1] = '0;//logic [5:0] = entry_t
assign table1[0][1] = '0;

用途举例

typedef logic[3:0] code_t;
typedef logic[15:0] info_t;

typedef logic[31:0] paddr_t; // 物理地址
typedef logic[31:0] vaddr_t; // 虚拟地址

2. struct

结构体struct可以描述一组相关的数据。
以译码器为例,按以前的写法,可能需要这样写:

logic [3:0] alufunc;
logic mem_read;
logic mem_write;
logic reg_write;

logic [6:0] control;
assign control[3:0] = {alufunc, mem_read, mem_write, reg_write};

结构体类型相关的语法如下:

// type definition
typedef struct packed{
 	logic [3:0] alufunc;
 	logic mem_read;
	logic mem_write;
	logic reg_write;
}control_t;//使用typedef定义的结构体,视作一个结构体类型,需要进一步定义才有结构体变量实体

// variable declaration
control_t control;

logic reg_write;
assign reg_write = control[0];//用control.reg_write更直观
// using struct without typedef
struct packed{
	logic [3:0] alufunc;
 	logic mem_read;
	logic mem_write;
	logic reg_write;
}control_without_typedef;//不使用typedef定义的结构体,视作一个结构体变量实体,与上面的control是同一个类型

struct语法有很多好处,用途也很广,例如可以使用struct结构来优化流水线寄存器的编写

typedef struct packed{
	//...
}pipeline_decode_t;

pipeline_decode_t p,p_nxt;
always_ff @(posedge clk)begin
	p <= p_nxt;
end

3. enum

枚举的语法形式为:

typedef enum <datatype>{
	IDEN_1, IDEN_2//0,1,...
} typename;

举个instance

typedef enum logic [3:0]{
	ALU_ADD, ALU_AND, ALU_SUB
}alufunc_t;

alufunc_t alufunc;

enum logic [3:0]{
	ALU_ADD, ALU_AND, ALU_SUB
}alufunc_without_typedef;

enum语法常用于编码 (包括状态机的编码)
enum类型的变量,在Vivado仿真里会显示枚举项。
枚举项被视为常量,各枚举类型的枚举项名字不能冲突
enum类型的变量,赋值时只能用枚举项

typedef enum logic[1:0]{
	STATE_0,STATE_1,STATE_2
}state_t;

state_t state,state_nxt;

always_ff @(posedge clk)begin
	if(~resetn)begin
		//state <= '0//state是变量时候可以这么写
		state <= state_t'(0);
	end else begin
		state = state_nxt;
	end
end

Union

联合类型的语法:

typedef union packed{
	struct packed{
		logic zero;
		logic [31:0]aluout;
	} alu;
	struct packed{
		logic zero;
		logic [31:0] pcbranch;
	}branch;
	struct packed {
		logic [31:0] addr;
		logic mem_read;
	}memory;
} result_t;

result_t res;

logic [31:0]addr, aluout;
assign addr = res.memory.addr; //assign addr = res[32:1]
assign aluout = res.alu.aluout;//assign aluout = res[31:0]

对union类型的变量进行赋值时,要注意多驱动
‘0是位全0,'1是位全1

高级语法2——parameter

引入元件例化的语法,有很多好处。
然而,已有的模块设计语法,缺乏flexibility。
适用同一int和long l ong 的加法器,需要写两个。
为了使模块代码具有更高的复用性,引入参数 parameter。

module adder # (
	parameter int N = 16,
	parameter logic [31:0] W = 32'd100000,
	parameter type element_t = logic[31:0]
)(
	input logic[N-1:0] a,b,
	output logic[N-1:0] c
);
assign c = a + b;
endmodule

	logic [31:0] a,b,c;
	
	adder #(.N(32), .element_t(logic[63:0])) adder_inst1(.a, .b, .c);
	logic [15:0] d,e,f;
	adder adder_inst2(.a(d), .b(e), .c(f));
end module 
module top #(
	parameter logic SIM = 1'b0;
)(input logic clk,resetn);

module sim();
	top #(.SIM(1'b1)) top_inst(.clk,.resetn);
	// -DDEBUG
endmodule

parameter也可用于全局常量声明。作为一句语句,它以分号结尾。

parameter logic[5:0] OP_ADDI = 6'b101010;

always_comb begin
	unique case(op)
		OP_ADDI: begin//6'b101010: begin
		end
	endcase
end

高级语法3——预编译命令

C语言中的部分预编译命令:

#include <stdio.h>
#ifndef __SHARE_H
#define __SHARE_H
#endif

#define N 1000000 + 3

// int a[N];

有了预编译命令,就可以用利用头文件,提升代码易读性
sv中的预编译命令,和c语言基本一致,用 `(反引号) 开头:

`include "mips.svh"// sv头文件后缀为svh
// vivado把同一project的所有文件视为同一目录下,故include时无需加目录
`ifndef __SHARE_SVH
`define _SHARE_SVH

`endif

`define LINES 0x10

logic a[`LINES-1:0]; // 使用宏时,也需要以`开头

预编译命令可以达到以下效果:
veri

  • 配置一些参数。类似于 parameter语句。
  • 根据不同的参数,生成不同的电路。不同于mux。
    • generate if语句的粒度为电路语句。而 `ifdef 之类的预编译命令可以是任意粒度的。
assign a = b + c
	#ifdef D_INSIDE
	+ d
	#endif
;

generate if (D_INSIDE) begin
	assign a = b + c + d;
end else begin
	assign a = b + c;
end
  • 使用头文件。类似于package 语句。
  • 使用宏来封装一些功能。部分情况下可用function语句代替

高级语法4——interface

电路图清晰地标明了元件的每位输入是从哪个元件的输出得到的,而元件例化语句无法做到这一点:

  • 元件例化语句不标出信号是作为输入还是输出
  • 信号相关模块的例化代码可能隔了很远
    同时,模块接口部分的代码,在语法上也有可改进的地方:
  • 不同模块可能复用一部分接口
  • 添加一个接口,需要修改多处代码

interface语法可以解决这一些问题,其语法形式与模块类似,具体为:

interface interface_name(input logic d, output logic e);/*inputs and outputs*/
	// signa1s
	logic c;
	
	// modports
	modport modport_namel(input c,d, output e);
	modport modport_name2(output c,f);
endinterface

// module
module module_name(
	interface_name.modport_namel variable_name// input logic c,d
);
	// use `variable_name` like a struct
	logic d;
	assign d = variable_name.c;
	assign variable_name.e = d;
endmodule

module top();
	// instantiate an interface involves declaring the singals inside it
	interface_name intf_inst(.d(), .e());
	module_name instance_name(.variable_name(intf_inst.modport_namel)):
endmoduTe

把interface的声明放到头文件里,可以大幅减少源代码量
modport就是一组数据,包括输入和输出
Verilator暂不支持interface语法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1474830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

go test用法(获取单元测试覆盖率)

go test用法&#xff08;获取ut覆盖率&#xff09; 为了提升系统的稳定性&#xff0c;一般公司都会对代码的单元测试覆盖率有一定要求。下面针对golang自带的测试命令go test做讲解。 1 命令 1.1 go test ./… &#xff08;运行当前目录及所有子目录下的测试用例&#xff09; …

读《Shape-Guided: Shape-Guided Dual-Memory Learning for 3D Anomaly Detection》

Chu Y M, Chieh L, Hsieh T I, et al. Shape-Guided Dual-Memory Learning for 3D Anomaly Detection[J]. 2023.&#xff08;为毛paperwithcode上面曾经的榜一引用却只有1&#xff09; 摘要 专家学习 无监督 第一个专家&#xff1a;局部几何&#xff0c;距离建模 第二个专家&…

【React源码 - 调度任务循环EventLoop】

我们知道在React中有4个核心包、2个关键循环。而React正是在这4个核心包中运行&#xff0c;从输入到输出渲染到web端&#xff0c;主要流程可简单分为一下4步&#xff1a;如下图&#xff0c;本文主要是介绍两大循环中的任务调度循环。 4个核心包&#xff1a; react&#xff1a;…

数据结构 队列

一定义 1.1概述&#xff1a; 队列只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表 特点&#xff1a;队列是先进先出的线性表 允许插入的一端称为队尾&#xff0c;允许删除的一端是队头 这里我们就介绍链式的 1.2 建立队列 这里说一句 其实不管是栈还…

php基础学习之错误处理(其一)

一&#xff0c;错误处理的概念 错误处理指的是系统(或者用户)在执行某些代码的时候&#xff0c;发现有错误&#xff0c;就会通过错误处理的形式告知程序员&#xff0c;俗称报错 二&#xff0c;错误分类 语法错误&#xff1a;书写的代码不符合 PHP 的语法规范&#xff0c;语法错…

【医学影像】LIDC-IDRI数据集的无痛制作

LIDC-IDRI数据集制作 0.下载0.0 链接汇总0.1 步骤 1.合成CT图reference 0.下载 0.0 链接汇总 LIDC-IDRI官方网址&#xff1a;https://www.cancerimagingarchive.net/nbia-search/?CollectionCriteriaLIDC-IDRINBIA Data Retriever 下载链接&#xff1a;https://wiki.canceri…

基于springboot+vue的编程训练系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

斯元Z-ONE-China Cybersecurity Tech Landscape·中国网络安全全景图-百度网盘下载

面向全球&#xff0c;斯元Z-ONE正式发布首版「China Cybersecurity Tech Landscape中国网络安全全景图」。 为了提升海外市场对中国网络安全行业的全局认识&#xff0c;方便国际客户及合作伙伴了解中国网络安全科技的赛道分布和国内外厂商对标&#xff0c;助力中国网安厂商出海…

Qt中tableView控件的使用

tableView使用注意事项 tableView在使用时&#xff0c;从工具栏拖动到底层页面后&#xff0c;右键进行选择如下图所示&#xff1a; 此处需要注意的是&#xff0c;需要去修改属性&#xff0c;从UI上修改属性如下所示&#xff1a; 也可以通过代码修改属性&#xff1a; //将其设…

个人玩航拍,如何申请无人机空域?

我们在《年会不能停》一文中&#xff0c;有分享我们在西岭雪山用无人机拍摄的照片和视频&#xff0c;有兴趣可以去回顾。 春节的时候&#xff0c;趁着回老家一趟&#xff0c;又将无人机带了回去&#xff0c;计划拍一下老家的风景。 原本以为穷乡僻壤的地方可以随便飞&#xf…

【c语言】内存函数

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 memcpy函数的使用和模拟实现 memcpy函数的使用 memcpy函数的模拟实现 memmove的使用和模拟实现 memmove的使用 memmove的模拟实现 memset函数的使用 memcmp函数…

【Docker】安装及相关的命令

目录 一 Docker简介 1.1 是什么 1.2 优缺点 1.3 应用场景 1.4 安装 二 命令 2.1 Docker基本命令 2.2 Docker镜像命令 2.3 Docker容器命令 一 Docker简介 1.1 是什么 Docker是一个开源的应用容器引擎&#xff0c;它基于Go语言实现&#xff0c;并利用操作系统本身已有的…

Kafka安全模式之身份认证

一、简介 Kafka作为一个分布式的发布-订阅消息系统&#xff0c;在日常项目中被频繁使用&#xff0c;通常情况下无论是生产者还是消费者只要订阅Topic后&#xff0c;即可进行消息的发送和接收。而kafka在0.9.0.0版本后添加了身份认证和权限控制两种安全服务&#xff0c;本文主要…

六、防御保护---防火墙内容安全篇

六、防御保护---防火墙内容安全篇 一、IAE&#xff08;Intelligent Awareness Engine&#xff09;引擎二、深度检测技术(DFI和DPI&#xff09;2.1 DPI -- 深度包检测技术2.1.1 基于“特征字”的检测技术2.1.2 基于应用网关的检测技术2.1.3 基于行为模式的检测技术 2.2 DFI -- 深…

CGI程序与ShellShock漏洞

CGI是什么&#xff1f; CGI&#xff08;通用网关接口&#xff0c;Common Gateway Interface&#xff09;程序是一种用于在Web服务器上执行动态内容的技术。与服务器上普通的后端代码相比&#xff0c;CGI程序有几个区别&#xff1a; 执行环境&#xff1a; CGI程序在服务器上作为…

k8s部署java微服务程序时,关于配置conusl acl token的方法总结

一、背景 java微服务程序使用consul作为服务注册中心&#xff0c;而consul集群本身的访问是需要acl token的&#xff0c;以增强服务调用的安全性。 本文试着总结下&#xff0c;有哪些方法可以配置consul acl token&#xff0c;便于你根据具体的情况选择。 个人认为&#xff…

BL0942 内置时钟免校准计量芯片 用于智能家居领域 低成本

BL0939是上海贝岭股份有限公司开发的一款用于智能家居领域进行电能测量的专用芯片&#xff0c;支持两路测量&#xff0c;可同时进行计量和漏电故障检测&#xff0c;漏电检测电流可设&#xff0c;响应时间快&#xff0c;具有体积小&#xff0c;外围电路简单&#xff0c;成本低廉…

C++ 前缀和

目录 1、DP34 【模板】前缀和 2、DP35 【模板】二维前缀和​编辑 3、724. 寻找数组的中心下标 4、238. 除自身以外数组的乘积 5、560. 和为 K 的子数组 6、974. 和可被 K 整除的子数组 7、525. 连续数组 8、1314. 矩阵区域和 1、DP34 【模板】前缀和 思路&#xff1a;…

Project_Euler-11 题解

Project_Euler-11 题解 题目 题目中给出的数据如下&#xff1a; 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 52 70 95 23 04 …

ESP32语音转文字齐护百度在线语音识别

一、导入(10分钟&#xff09; 学习目的 二、新授(70分钟) 1.预展示结果(5分钟) 2.本节课所用的软硬件(5分钟) 4.图形化块介绍(10分钟) 5.单个模块的简单使用(10分钟) 6.在线语音转换工具逻辑分析(10分钟) 7.在线语音转换工具分步实现(30分钟) 三、巩固练习(5分钟) 四、课堂小结…