SystemVerilog学习笔记(一)
Verilog-1995有两种基本数据类型:变量(variables) 和 网络(nets),包含4个状态值:0,1,Z,X。
变量(variables)的几种类型
1.无符号单bit或多bit变量 — reg [7:0] sum
2.有符号32bit — integer i
3.无符号64bit — time t
4.浮点数 — real r
SystemVerilog向Verilog语言添加了bit和logic关键字,分别表示2状态和c。
SystemVerilog的 网络(nets) 类型(如wire)仅使用4状态值集,而 变量(variables) 类型中一部分使用4状态值集,另一部分使用2状态值集
bit和logic关键字也可以在不明确定义网络或变量的情况下使用,在这种情况下,网络或变量是从上下文推断出来的。关键字bit总是推断为变量。关键字logic在大多数中推断为变量,但如果与模块输入或inout端口声明一起使用,则推断为网络。以下声明说明了这些推理规则
module A;
...
endmodule
module M (
// module ports with inferred types
input i1, // infers a 4-state net,推断为4状态网络
input logic i2, // infers a 4-state net,推断为4状态网络
input bit i3, // infers a 2-state variable,推断为2状态变量
output o1, // infers a 4-state net,推断为4状态网络
output logic o2, // infers a 4-state variable,推断为4状态变量
output bit o3 // infers a 2-state variable,推断为2状态变量
);
// internal signals with inferred and explicit types
bit clock; // infers a 2-state variable
logic reset; // infers a 4-state variable
logic [7:0] data; // infers a 4-state variable
wire [7:0] n1; // explicitly declares a net, infers 4-state logic
wire logic [7:0] n2; // explicitly declares a 4-state net
var [7:0] v1; // explicitly declares a variable, infers logic
var logic [7:0] v2; // explicitly declares a 4-state variable
...
endmodule
- wire和tri —— 互连网络,允许并解决多个驱动因素
- supply0和supply1 —— 分别具有常数0或1的互连网络
- wand,triand, wor, trior —— 将AND和OR多个驱动器连接在一起的网络互连
- reg —— 用户定义向量大小的通用4状态变量
- integer —— 32位4状态变量
- logic —— 除模块输入/输入输出端口外,推断用户定义的向量大小的通用4状态变量
- bit —— -推断用户定义向量大小的通用2状态变量
- byte, shortint, int, longint —— 分别具有8位、16位、32位和64位向量大小的2状态变量
logic关键字并不是真正的变量类型,但在几乎所有上下文中,logic都会推断为reg变量。由于这种推理,可以使用logic关键字代替reg,让语言自己来推断变量
通过在方括号中指定一系列位,后跟向量名称来声明向量。在SystemVerilog中将向量定义为packed arrays,即压缩数组。例如:
wire [31:0] a; // 32-bit向量 ,LSB
logic [1:32] b; // 32-bit向量,MSB
SystemVerilog添加压缩数组的一个显著增强是,通过使用多个范围将向量声明划分为子字段的能力。例如:
logic [3:0][7:0] bytes; //32-bit向量,被分为4个8-bit子向量
bytes = 32'hCAFE_DADA;
bytes[2] = 8'hFF; //分配给向量的第2个子向量值
bytes[1][0] = 1'b1; //选择向量的第1个子向量的第0个bit
对于某些数据类型,您可能既要访问整个值,也要将其划分为较小的元素。例如,您可能有一个32位寄存器,有时需要将其视为四个8位值,有时需要将其视为单个无符号值。
SystemVerilog压缩数组被视为数组和单个值。与 未压缩数组(unpacked arrays) 不同,它存储为一组连续的位,没有未使用的空间。
可以看到向量在存储时是连续存储的,与后文要介绍的未压缩数组不同
packed arrays的维数定义在变量标识符之前
unpacked arrays的维数的定义在变量标识符之后
SystemVerilog允许声明网络、变量和用户定义类型的一维和多维数组。数组维度在数组名称之后声明。例如:
logic [7:0] LUT [0:255]; //一维数组,数组单个元素是8-bit
logic [7:0] RGB [0:15][0:15][0:15]; //三维数组,数组单个元素是8-bit
可能有些人会混淆数组和向量,数组的维数定义是在标识名称之后,而向量的维数定义是在标识名称之前
数组定义:
1. bit a [7:0][15:0] // 二维数组,数组元素为bit
2. int b [7:0][15:0] // 二维数组,数组元素是32位
3. bit [7:0] c [7:0][15:0] // 二维数组,数组元素是8-bit
向量定义:
1.wire [31:0] a; // 32-bit向量 ,LSB
2.logic [1:32] b; // 32-bit向量,MSB
如何调用数组的元素:
logic Arrays [7:0][7:0] ;
Arrays [2][3] = 1'b1;
数组(unpacked arrays)将值存储在字(word,32-bit)的较低部分,而较高的位未使用。如下图所示,字节数组b_unpack存储在三个字中:

您可以混合数组和向量。您可能希望创建一个数组,该数组表示可以以位、字节或长字形式访问的内存。如下图显示了barray数组,他是一个由五个packed arrays组成的unpacked arrays,每个元素宽四个字节,存储在内存中

SystemVerilog允许通过指定数组大小来声明数组,方法与C语言中的方法相同。例如:
logic [7:0] LUT [256]; // one-dimensional array of 256 bytes
logic [7:0] RGB [16][16][16]; // three-dimensional array of bytes
使用此语法时,数组寻址始终以地址0开始,以数组大小减1结束。
Verilog一次只允许访问阵列的单个元素。要将数据从一个数组复制到另一个数组,需要编写通过每个数组的每个元素建立索引的循环。SystemVerilog允许将数组复制为单个赋值语句。可以复制整个阵列或阵列的一部分。例如:
logic [31:0] big_array [0:255]; // array with 256 32-bit elements
logic [31:0] small_array [0:15]; // array with 16 32-bit elements
assign small_array = big_array[16:31]; // copy 16 elements of big_array
数组复制要求指定两侧的维度数和每个维度中的元素数相同。每个元素的位数也必须具有相同的大小和兼容的数据类型
可以使用 '{} 中包含的值列表来指定数组的所有或多个元素。该列表可以包含单个数组元素的值,也可以包含整个数组的默认值。例如:
logic [7:0] a, b, c;
logic [7:0] d_array [0:3]; // array with 4 8-bit elements
always_ff @(posedge clock or negedge rstN) begin
if (!rstN) begin
d_array <= '{default:0}; // reset all elements of the array
end
else begin
d_array <= '{8'h00, c, b, a}; // load the array
end
end
操作数组最常用的方法是使用for或foreach循环。SystemVerilog函数$size返回数组的大小。在foreach循环中,指定数组名和方括号中的索引,SystemVerilog会自动遍历数组的所有元素。索引变量会自动为您声明,并且是循环的局部变量
initial begin
bit [31:0] src[5],dst[5] ;
for (int i=0; i<$size(src) ; i++)
src [i]=i; // Initialize src array
foreach (dst [j] )
dst[j] = src[j] * 2; // Set dst array to 2 * src
end
请注意,多维数组的foreach循环语法可能与您预期的不同。它们不是用单独的方括号[ i ] [ j ]列出每个下标,而是用逗号[i,j]组合。
int md[2][3] = '{'{0,1,2}, '{3,4,5}};
initial begin
$display ("Initial value:") ;
foreach (md[i,j]) // Yes, this is the right syntax
$display ("md[%0d] [%0d] = %0d", i, j, md[i] [j]) ;
$display ("New value:") ; // Replicate last 3 values of 5
md = '{'{9, 8, 7},'{3{5}}};
foreach (md[i,j]) // Yes,this is the right syntax
$display ("md[&0d] [%0d] = %0d",i, j, md[i] [j]) ;
end
输出结果如下:
Initial value :
md[0] [0] = 0
md[0] [1] = 1
md[0] [2] = 2
md[1] [0] = 3
md[1] [1] = 4
md[1] [2] = 5
New value :
md[0] [0] = 9
md[0] [1] = 8
md[0] [2] = 7
md[1] [0] = 5
md[1] [1] = 5
md[1] [2] = 5
如果不需要逐级遍历所有维度,可以在foreach循环中省略一些维度:
initial begin
byte twoD[4] [6] ;
foreach (twoD [i,j] )
twoD[i] [j] = i*10+j;
foreach (twoD[i]) begin // Step through first dim.
$write ("%2d:",i) ;
foreach (twoD[,j] ) // Step through second
$write ("%3d", twoD [i] [j] ) ;
$display;
end
end
输出结果如下:
0: 0 1 2 3 4 5
1: 10 11 12 13 14 15
2: 20 21 22 23 24 25
3: 30 31 32 33 34 35
最后加深理解:
1.数组 f [ 5 ] 等价于 f [ 0 : 4 ]
2.foreach ( f [ 5 ] ) 等价于 for ( int i = 0 ; i <= 4 ; i++ )
3.对于数组 rev [ 6 : 2 ]
foreach( rev [ i ] ) 等价于 for ( int i = 6 ; i >= 2 ; i-- )
分配给一个数组的多个元素的功能还可以将数组用作模块端口或任务/函数参数。以下示例定义了一个用户定义的类型,该类型表示一个由32位元素组成的8x256二维数组,然后将该数组传递给函数和从函数传递出去,并通过模块端口传递出去。
typedef logic [31:0] d_array_t [0:7][0:255];
module block_data (
input d_array_t d_in, // input is an array
output d_array_t q_out, // output is an array
input logic clock, rstN
);
function d_array_t transform (input d_array_t d); // input is an array
// ... perform operations on all elements of d
return d; // return is an array
endfunction
always_ff @(posedge clock or negedge rstN)
if (!rstN) q_out <= ’{default:0}; // reset entire q_out array
else q_out <= transform(d_in); // transform and store entire array
endmodule
SystemVerilog提供了许多特殊的系统功能,使操作数组更容易,而无需对数组大小进行硬编码。可综合的数组查询功能包括:
$left()
$right()
$low()
$high()
$increment()
$size()
$dimensions()
$unpacked_dimensions()
SystemVerilog允许设计和验证工程师创建新的、用户定义的数据类型。变量和网络都可以声明为用户定义的类型。如果未指定var或net type关键字,则假定用户定义的类型为变量。
可综合的用户定义类型有:
1.enum-具有法定值枚举列表的变量或网络-参见第12.1节
2.struct-包含多个网络或变量的结构-参见第12.2节
3.union-可以在不同时间表示不同类型的变量-参见第12.3节
4.typedef-类型定义-参见第12.4节
枚举类型允许使用一组特定的命名值定义变量和网络。声明枚举类型的基本语法为:
// 一个具有3个合法值的变量
enum {WAITE, LOAD, DONE} State;
枚举类型有一个基本数据类型,默认情况下是int(一种2状态32位类型)。在上面的示例中,State是int类型,WAITE、LOAD和DONE将具有32位int值。
枚举列表中的标签是具有关联逻辑值的常量。默认情况下,列表中的第一个标签的逻辑值为0,随后的每个标签都会递增一。因此,在上面的示例中,WAITE是0,LOAD是1,DONE是2。
你也可以显式的指定每个标签的基类型:
// 两个3位、4状态枚举变量,带有一个热值枚举逻辑
enum logic [2:0] { WAITE = 3’b001,
LOAD = 3’b010,
DONE = 3’b100} State, NextState;
// State,NextState是3-bit的4状态变量,其值只能是WAITE/LOAD/DONE中的一个
// 枚举类型内每个标签的值都是唯一的,不可以和别的标签相同
枚举类型定义的变量,其值只能是枚举标签其中之一(有特殊情况下也会取到标签之外的值,后文会说)
枚举类型在状态机中使用有很大的便利,使用枚举类型可以将逻辑错误转换成语法错误,这样可以在编译阶段就能排查出错误,而不必在功能验证阶段才发现,从而大大节省时间。下面两段代码分别展示了使用reg类型和enum类型编写状态机的代码,其中有一些bug,在第一段代码里可能是可以编译通过的,但状态机功能错误,而在第二段代码里是语法错误,编译无法通过。
// Names for state machine states (one-hot encoding)
parameter [2:0] WAITE=3'b001, LOAD=3'b010, DONE=3'b001; // FUNCTIONAL BUG
// Names for mode_control output values
parameter [1:0] READY=3'b101, SET=3'b010, GO=3'b110; // FUNCTIONAL BUG
// State and next state variables
reg [2:0] state, next_state, mode_control;
// State Sequencer
always @(posedge clock or negedge resetN)
if (!resetN) state <= 0; // FUNCTIONAL BUG
else state <= next_state;
// Next State Decoder (sequentially cycle through the three states)
always @(state)
case (state)
WAITE: next_state = state + 1; // DANGEROUS CODE
LOAD : next_state = state + 1; // FUNCTIONAL BUG
DONE : next_state = state + 1; // FUNCTIONAL BUG
endcase
// Output Decoder
always @(state)
case (state)
WAITE: mode_control = READY;
LOAD : mode_control = SET;
DONE : mode_control = DONE; // FUNCTIONAL BUG
endcase
endmodule
module bad_fsm_systemverilog_style (...); // only relevant code shown
enum logic [2:0] {WAITE=3'b001, LOAD=3'b010, DONE=3'b001} // SYNTAX ERROR
state, next_state;
enum logic [1:0] {READY=3'b101, SET=3'b010, GO=3'b110} // SYNTAX ERROR
mode_control;
// State Sequencer
always_ff @(posedge clock or negedge resetN)
if (!resetN) state <= 0; // SYNTAX ERROR
else state <= next_state;
// Next State Decoder (sequentially cycle through the three states)
always_comb
case (state)
WAITE: next_state = state + 1; // SYNTAX ERROR
LOAD : next_state = state + 1; // SYNTAX ERROR
DONE : next_state = state + 1; // SYNTAX ERROR
endcase
// Output Decoder
always_comb
case (state)
WAITE: mode_control = READY;
LOAD : mode_control = SET;
DONE : mode_control = DONE; // SYNTAX ERROR
endcase
endmodule
SystemVerilog提供了一些枚举类型的方法:
enum logic [3:0] { IDLE = 4'b0001 , sta0 = 4'b0010 , sta1 = 4'b0100} state , nextState;
state = IDLE;
则:
nextState = state.first();
nextState = state.last();
nextState = state.next();
nextState = state.prev();
nextState = state.num();
nextState = state.name();

SystemVerilog结构提供了一种机制,可以在一个公共名称下收集多个变量:
struct {
logic [7:0] source_address;
logic [7:0] destination_address;
logic [7:0] data;
logic [3:0] ecc;
} packet;
可以使用点运算符(.)访问结构的各个成员
packet.source_address = 8’h01;
也可以使用'{}对结构体赋值
packet <= '{8'h01 , 8'h03 , 8'haa , 4'hf};
packet <= '{default:0}; // reset all members of packet
结构体数据的存储可以通过声明packed使其连续存储
struct packed { // members will be stored contiguously
logic [ 1:0] parity;
logic [63:0] data;
} data_word;

联合体使各成员共用一个存储空间,使用单个存储空间表示多种存储格式。以下示例将无符号位向量b和整数i存储在同一位置:
union {
bit [31:0] b;
int i;
} un ;
un.i = -1;
// 此时i的存储空间为h80000001,有于i和b共用一个存储空间,所以b为h80000001
可以使用typedef定义新的用户自定义类型,新的数据类型是使用typedef从内置类型和其他用户定义的类型构造而成的,类似于C。一些简单的示例如下:
typedef logic [31:0] bus64_t; // 64-bit bus
typedef struct { // typed structure
logic [ 1:0] parity;
logic [63:0] data;
} data_t;
typedef enum logic {FALSE=1’b0, TRUE=1’b1} bool_t;
module D (input data_t a, b,
output bus64_t result,
output bool_t aok );
...
endmodule
原始Verilog语言没有共享的声明空间。每个模块都包含该模块中使用的所有声明。这是一个主要的语言限制。如果在多个模块中需要相同的参数、任务或函数定义,设计者必须纵容笨拙的工作循环,通常使用ifdef和include编译器指令的组合。
SystemVerilog用户定义类型、面向对象类定义和随机化约束的添加使得缺少共享声明空间成为一个严重的问题。
SystemVerilog通过添加用户定义的包解决了Verilog的缺点。包提供了一个声明空间,可以从任何设计模块以及验证代码中引用该空间。
package alu_types;
localparam DELAY = 1;
typedef logic [31:0] bus32_t;
typedef logic [63:0] bus64_t;
typedef enum logic [3:0] {ADD, SUB, ...} opcode_t;
typedef struct {
bus32_t i0, i1;
opcode_t opcode;
} instr_t;
function automatic logic parity_gen(input d);
return ^d;
endfunction
endpackage
声明空间中的用户自定义类型可以在引用了该声明空间的module中任意使用
模块引用package有三种方式:
1.显示包引用
2.显示导入语句
3 通配符导入语句
1.显示包引用:
module alu (
input alu_types::instr_t instruction, // use package item in port list
output alu_types::bus64_t result
);
alu_types::bus64_t temp; // use package item within module
...
endmodule
对包项的显式引用不会使该项在模块中的其他位置可见。每次在模块中使用该定义时,都必须使用显式引用。
2.显示导入语句:
module alu
import alu_types::bus64_t;
(
input alu_types::instr_t instruction, // explicit package reference
output bus64_t result
); // bus64_t has been imported
bus64_t temp; // bus64_t has been imported
...
endmodule
导入后,该项可以在模块中被任意引用
3.通配符导入语句
module alu
import alu_types::*;
(
input instr_t instruction, // instr_t has been imported
output bus64_t result
); // bus64_t has been imported
bus64_t temp; // bus64_t has been imported
...
endmodule
通配符导入使用*表示包中的所有定义。通配符导入使包的所有项在模块内可见。
包可以消除重复代码、设计的不同块中不匹配的风险以及维护重复代码的困难。
推荐使用软件包!包提供了一种干净、简单的方法,可以在整个设计和验证项目中重用任务、函数和用户定义类型的定义。
模块中包导入的位置很重要,如果希望在端口列表中就使用包中的自定义类型,则包的导入就要在端口列表之前
一个包可以引用另一个包的定义,也可以从另一个包导入定义
SystemVerilog比传统的Verilog增加了许多重要的编程功能。这些增强的目的有三个:
1.能够用更少的代码行建模更多的功能
2.降低设计中出现功能错误的风险
3.帮助确保仿真和综合以相同的方式解释设计功能。
未完待续…
20220528
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
如何学习ruby的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/
我想使用部分字符串搜索数组,然后获取找到该字符串的索引。例如:a=["Thisisline1","Wehaveline2here","andfinallyline3","potato"]a.index("potato")#thisreturns3a.index("Wehave")#thisreturnsnil使用a.grep将返回完整的字符串,使用a.any?将返回正确的true/false语句,但都不会返回匹配的索引找到了,或者至少我不知道该怎么做。我正在编写一段代码,该代码读取文件、查找特定header,然后返回该header的索引,以便它可以将其用作future搜索的偏移量。如果
深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG
文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk=Var(yt)Cov(yt,yt−k)其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞
写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是