所有行为代码写在 module 和 endmodule 内。无论打算创建什么数字设计,都放在 module 块中。可定义端口允许信号作为 input 进入或作为 output 离开。 模块 下面空模块叫 testbench。命名随意,但须字母数字且可含下划线 _。 module testbench; endmodule 再看另一模块。有几个信号 (d, clk, rstb) 声明为输入,q 声明为输出。 module dff (input d, clk, rstb, output q); endmodule 数据类型 看过模块样子,再看模块内可放什么,以 testbench 模块为例。Ve
一组 Verilog 语句通常在仿真中顺序执行。这些语句放在 过程 块中。Verilog 中主要有两类 过程 块:initial 和 always。 语法 initial [single statement] initial begin [multiple statements] end initial 块用途 initial 块不可综合,无法转换为包含数字元件的硬件原理图。因此 initial 块除仿真外用途不大。主要用于初始化变量和驱动设计端口特定值。 initial 块何时开始和结束? initial 块在仿真开始时刻 0 启动。整个仿真期间仅执行一次。执行完块内所有语句后结束。 上图
前文展示了用 always 块实现组合逻辑的示例。always 块也主要用于实现时序逻辑,包含可保持值的触发器等存储元件。 JK 触发器 JK 触发器是存储值的多种触发器之一,有两个数据输入 j 和 k,以及复位 rstn 和时钟 clk。真值表如下,通常用与非门实现。 rstnjkq注释 0000复位有效时输出恒为 0 100保持值j=k=0 时输出保持不变 1011k=1 时输出变 1 1100k=0 时输出变 0 111翻转值j=k=1 时输出翻转当前值 JK 触发器行为 Verilog 代码如下: module jk_ff ( input j, // Input
Verilog always 块可用于时序和组合逻辑。前文用 assign 语句展示了几个设计示例。接下来用 always 块探索相同设计集。 示例 #1:简单组合逻辑 下面代码实现简单数字组合逻辑,输出信号 z 类型为 reg,在敏感列表中任一信号值变化时更新。敏感列表声明在 @ 运算符后的括号内。 module combo ( input a, b, c, d, e, output reg z ); always @ (a or b or c or d or e) begin z = ((a & b) | (c ^ d) & ~e); end endmodule 模
always 块是 Verilog 中的 过程 块之一。always 块内语句按顺序执行。 语法 always @ (event) [statement] always @ (event) begin [multiple statements] end always 块在特定事件执行。事件由敏感列表定义。 什么是敏感列表? 敏感 列表定义 always 块何时执行,指定在 @ 运算符后的括号 ( ) 内。列表可包含一个或一组信号,其值变化将触发 always 块执行。 下面代码中,always 块内所有语句在信号 a 或 b 值变化时执行。 // 当 a 或 b 值变化时执行 always 块
多位 Verilog 线网和变量可通过 拼接 运算符 { 和 } 用逗号分隔组合成更宽的多线网线网或变量。拼接操作数除线网和变量外,还允许表达式和带位宽常数。 必须知道每个操作数尺寸以计算完整拼接尺寸。 Verilog 拼接示例 wire a, b; // 1-bit wire wire [1:0] res; // 2-bit wire to store a and b // res[1] follows a, and res[0] follows b assign res = {a, b}; wire [2:0] c; wire [7:0] res1; // res[0] follows c
无法处理的数据毫无用处,数字电路和计算机系统总需要某种计算。看看 Verilog 中哪些运算符能让综合工具实例化合适的硬件元件。 Verilog 算术运算符 若除法或取模运算符的第二个操作数为零,结果为 X。若幂运算符任一操作数为实数,结果也为实数。幂运算符第二个操作数为 0 时结果为 1 (a0)。 运算符描述 a + ba 加 b a - ba 减 b a * ba 乘 b a / ba 除以 b a % ba 模 b a ** ba 的 b 次幂 算术运算符使用示例: module des; reg [7:0] data1; reg [7:0] data2; initial begi
Verilog assign 语句通常用于持续驱动 wire 数据类型信号,综合为组合逻辑。以下是更多使用 assign 语句的设计示例。 示例 #1:简单组合逻辑 下面代码实现简单数字组合逻辑,输出线网 z 通过 assign 语句持续驱动以实现数字方程。 module combo ( input a, b, c, d, e, output z ); assign z = ((a & b) | (c ^ d) & ~e); endmodule 模块 combo 经综合工具展开为以下硬件原理图,可见组合逻辑用数字门实现。 测试平台 测试平台用于仿真验证设计行为是否符合预期。使
wire 类型或类似线网数据类型的信号需要连续赋值。例如面包板上连接元件的电线,只要一端接 +5V 电池,另一端连接的元件即获得所需电压。 Verilog 中通过 assign 语句实现此概念:任何 wire 或类似线网数据类型可被表达式持续驱动。值可以是常量或由一组信号组成的表达式。 assign 语法 赋值语法以关键字 assign 开始,后跟信号名(可以是单个信号或不同信号线网的拼接)。驱动强度 和 延迟 可选,主要用于数据流建模而非综合成真实硬件。右侧表达式或信号求值后赋给左侧线网或线网表达式。 assign = [drive_strength] [delay] 延迟值用于指定门
如前文所述,复杂设计通过层次化集成多个模块构建。模块可在其他模块内实例化,这些实例的端口可与父模块内其他信号连接。 端口连接可通过有序列表或按名称进行。 按有序列表连接端口 模块实例化中端口表达式列表与父模块内信号连接的一种方法是有序列表。 mydesign 模块在另一模块 tb_top 中实例化为 d0。端口按特定顺序连接,顺序由模块声明中端口列表位置决定。例如 tb_top 中的 b 连接到设计的 y,仅因两者在端口列表中均处于第二位置。 o endmodule 必须知道设计模块端口顺序才能正确连接。 这非常不便,因为新增端口会改变顺序,且端口数量大时极易出错。 按名称连接端口 更好的方
端口是作为特定模块输入和输出的一组信号,是与模块通信的主要方式。将模块视为放置在 PCB 上的芯片,很明显与芯片通信只能通过其引脚。端口如同引脚,设计用于向外部发送和接收信号。 端口类型 端口描述 Input设计模块仅通过 input 端口从外部接收值 Output设计模块仅通过 output 端口向外部发送值 Inout设计模块可通过 inout 端口发送或接收值 端口默认视为 wire 类型线网。 语法 inout 声明的端口可同时作为输入和输出。 input [net_type] [range] list_of_names; // 输入端口 inout [net_type] [ra
module 是实现特定功能的 Verilog 代码块。模块可嵌套在其他模块内,高层模块通过输入输出端口与低层模块通信。 语法 module 必须包含在 module 和 endmodule 关键字之间。模块名紧跟 module 关键字后,可选端口列表。注意:端口列表中声明的端口不能在模块体内重复声明。 module ([port_list]); // Contents of the module endmodule // 模块可有空端口列表 module name; // Contents of the module endmodule 所有变量声明、数据流语句、函数/任务及下层模块实例(
数组 声明的线网或变量可以是标量或向量。通过在标识符名后指定地址范围可创建任意维度数组,称为多维数组。Verilog 允许 reg、wire、integer 和 real 数据类型形成数组。 reg y1 [11:0]; // y1 是标量 reg 数组,深度=12,每个 1 位宽 wire [0:7] y2 [3:0] // y2 是 8位向量线网,深度=4 reg [7:0] y3 [0:1][0:3]; // y3 是二维数组,行=2,列=4,每个 8位宽 访问数组特定元素需为每个维度指定索引,索引可以是其他变量的表达式。数组可用于 Verilog 支持的所有数据类型。 注意:n 个 1
Verilog 需表示单个位和位组。例如单个位时序元件是触发器,而 16 位时序元件是可存 16 位的寄存器。为此 Verilog 提供 标量 和 向量 线网和变量。 标量与向量 无范围声明的线网或 reg 视为 1 位宽,即 标量。若指定范围,则成为多位实体即 向量。 wire o_nor; // 单标量线网 wire [7:0] o_flop; // 8位向量线网 reg parity; // 单标量变量 reg [31:0] addr; // 32位向量变量存地址 范围赋予寻址向量中单个位的能力。向量最高有效位 (MSB) 作为范围左值,最低有效位 (LSB) 作为右值。 wire [
Verilog 数据类型的主要目的是表示数据存储元件(如触发器中的位)和传输元件(如连接逻辑门和时序结构的线网)。 变量可取值 除 real 和 event 外,几乎所有数据类型仅可取以下四种值: 0逻辑 0,或假条件 1逻辑 1,或真条件 x未知逻辑值(可能是 0 或 1) z高阻抗状态 下图展示这些值在时序图和仿真波形中的表示。大多数仿真器约定:红色 代表 X,中间 橙色 代表高阻抗 Z。 Verilog 值集的含义 Verilog 用于描述触发器、与非门、或非门等硬件元件,必须建模硬件中的值系统。逻辑 1 代表电源电压 Vdd,范围 0.8V 至 3V 以上,取决于工艺节点。逻辑
Verilog 词法约定类似 C 语言,包含 token 流。词法 token 可由一个或多个字符组成,包括注释、关键字、数字、字符串或空白。所有行应以分号 ; 结尾。 Verilog 区分大小写,var_a 和 var_A 是不同的。 注释 Verilog 有两种注释方式: 单行注释 以 // 开始,告诉编译器将该点到行尾视为注释。 多行注释 以 /* 开始,以 */ 结束,不能嵌套。 但单行注释可嵌套在多行注释中。 // This is a single line comment integer a; // Creates an int variable called a, and t
在深入 Verilog 语言细节前,了解芯片设计的不同抽象层级很有帮助。 顶层是系统级架构,定义各子块并按功能分组。例如处理器集群包含多个核、缓存块和缓存一致性逻辑,全部封装为具有输入输出信号的单个块。 下一层,每个子块用硬件描述语言编写,准确描述各块功能,忽略电路原理图、工艺库等低层实现细节。例如控制器块最终包含多个 Verilog 文件,每个描述其功能的较小组件。 HDL 综合为门级原理图,涉及表征触发器等数字元件的工艺库。例如 D 锁存器的数字电路包含特定排列的与非门,使所有 D 和 E 输入组合产生真值表给定的输出 Q。 真值表给出所有输入电平排列及结果输出电平,下表为带使能引脚
典型设计流程遵循以下结构,可分解为多个步骤,部分并行、部分顺序进行。我们来看看当今行业中典型的项目设计周期。 需求分析 半导体公司的客户通常是计划在其系统或终端产品中使用芯片的其他公司。因此,客户需求在决定芯片设计方式上起关键作用。第一步自然是收集需求、评估终端产品市场价值,并评估项目所需资源。 规格制定 下一步是收集“规格”,抽象描述芯片的功能、接口和整体架构。例如: 需要运行图像算法以支持虚拟现实的计算能力 需要两个 ARM A53 处理器,带一致性互联,运行频率 600 MHz 需要 USB 3.0、蓝牙和 PCIe 2.0 接口 需支持 1920x1080 像素显示及相应控制器
在集成电路早期,工程师必须在纸上手绘晶体管及其连接以设计可在硅上制造的电路。随着电路规模和复杂度增加,需要更多工程师、时间和资源,迫切需要更好的设计方法。 VHDL 应运而生,允许工程师描述硬件功能,让自动化工具将其转换为组合逻辑门和时序逻辑等实际硬件元件。Verilog 则进一步简化流程,使硬件描述语言 (HDL) 更健壮灵活。如今,Verilog 是半导体行业最流行的 HDL。 Verilog 的用处 Verilog 创建了一个抽象层,隐藏实现细节和技术细节。 例如,设计一个 D 触发器需要了解晶体管排列以实现正边沿触发,以及上升/下降时间和 clk-Q 时间等技术细节。功耗、时序和驱动能
Verilog是硬件描述语言(HDL),赋能工程师为FPGA与ASIC建模、仿真、综合数字逻辑。与孪生兄弟VHDL并列,Verilog是学术课程与商业产品开发的行业标准语言。 若您初涉可编程逻辑或硅设计,本指南带您走过Verilog基础,构建简单与门——每个数字系统基石元件。 不同于Java或C等高级软件语言,Verilog在门级描述硬件。结果代码可直接映射到硅,赋予设计师对时序、功耗、面积的精细控制。 下图为我们将用Verilog建模的经典双输入与门。 让我们深入Verilog实现。 Verilog中构建块是wire。本例将wire视为仅能为0或1的二进制信号。 wire and_tem
Verilog