VERILOG 一点感想

距上次发文章好像应该是很长时间之前了,那么今天就把暑假的一些学习成果汇总一下也算了解的一个心愿,因为我是初学者所以涉及的内容也都比较基础

那么下面我们就开始

既然是 verilog 语言总结那么这篇文章我也就用 verilog 的格式也算入乡随俗了。

module top_module(input 鼠标翻页,output 知识点);

目录  c1 (鼠标翻页,模块的概念);

目录  c2 (鼠标翻页,基本输入输出和数据类型);

目录  c3 (鼠标翻页,基本语法);

目录   c4  (鼠标翻页,几个例子);

endmodule

module 目录(input clk,input content);

always @(鼠标翻页)

begin

if(模块的概念)

那么从这里我们开始介绍我们 verilog 的模块的概念。普及一下概念模块是具有输入,输出功能,并按其预期设计运行。

verilog 模块的复杂性没有上限,它们甚至可以描述完整的处理器内核!如用在 FPGA 上 NIOS2 核心等是不是还有点小激动处理器都可以描述,事实上很多处理器的设计都是采用硬件描述语言来进行的,正是因为他的模块的可实例化,这和 C++ 或者 python 中的类很相似也使得处理器中亿级的门电路成为了可能,你可以用与或非门组成加法器等等进而组成一个完整的系统。

说白了,个人之见 Verilog 就是创建模块,互连模块和管理时钟交互时间。

下图可以看出模块的几个要素

else if(基本输入输出和数据类型)

首先我们使用 verilog 中的 hello world 的程序代入

module helloVerilog(A, B);
input wire A;
output wire B;
assign B = !A;
endmodule
模块的名称是“helloVerilog”,使用“module”关键字来声明模块。Verilog 中的关键字模块定义了我们的模块并为其分配了两个端口 A,B。进入此模块的所有内容都放在“module”和“endmodule”(每个模块必须有 endmodule)关键字之间。我们的模块有两个端口。

在下面的两行中,端口 A 和端口 B 分别声明为输入和输出。你可能问”wire" 是神马,在 Verilog 中有两种基本数据类型,即’wire’和’reg’。还有许多其他数据类型,如 int,real 等……但’wire’和’reg’在 Verilog 中是很基本且重要的存在。

’wire’就像我们用来电连接两个不同东西的物理线。如果在铜线的一端施加电位,只要继续施加电位,它就会出现在电线的另一端。一旦删除输入,电位就会消失。对于 Verilog 中的“wire”数据类型也是如此。只要线路由某个其他实体驱动,线路将具有特定的逻辑状态。如果没有驱动电线,它将处于未知状态。在 Verilog 中,’wire’可用于连接模块内或两个模块之间的内容。

那么’reg’可以存储逻辑状态并保持它直到有人去改变它(类比控制器中的寄存器)。这类似于触发器。如果你将触发器置于一个状态,它将保持该状态,直到有人改变它。

至于其他类型还有 integer 型、parameter 型,net 型

其中对于通常大多数的矢量类型(reg 或者 net)都被默认当做无符号数。integer(整数型) 和 real,它们被默认为当做有符号数。

其中 parameter 型可类比 C 语言里面的 define,我们用 parameter 来定义一个标志符代表一个常量,称作符号常量,可以提高程序的可读性和可维护性。parameter 是参数型数据的关键字,在每一个赋值语句的右边都必须是一个常数表达式。即该表达式只能包含数字或先前已经定义的参数。

对于 net 型由模块或门驱动的连线。驱动端信号的改变会立刻传递到输出的连线上

还有很多其他的数据类型作者在此就不一一阐述了。

关于上述代码的另一个重要事项是关键字“assign”。assign 关键字用于创建组合电路。无论在语句的右侧写入什么,都将被执行,结果将被分配给左侧的实体也就是我们的输出,这是异步发生的。一旦右侧发生任何变化,结果将反映在左侧。这也是 FPGA 优势之一程序并行执行而不像单片机顺序执行程序。

其他的还有 always@(敏感列表)

大家可能注意到我们 verilog 风格的文章里面有这一句在敏感列表我们把鼠标翻页作为敏感列表的值(一般是时钟信号或者上升沿下降沿最为敏感列表输入)当敏感列表内变化会执行下面的语句

else if(基本语法)

对于常用的 wire 和 reg 型做以下赋值方法

wire [n-1,0] 数据名 1,数据名 2…数据名 i;          // 表示共有 i 条总线,每台总线内有 n 条线路。或者 wire [n,1] 数据名 1,数据名 2…数据名 i;

[n-1,0] 和 [n,1] 表示该数据的位宽为 n。如:

wire      a;            // 定义了 1 个 1 位的 wire 数据

wire    [7,0] b;       // 定义了 1 个 8 位的 wire 数据

wire    [4,1] a,b;    // 定义了 2 个 4 位的 wire 数据

reg 常用来表示 always 模块内的指定信号,代表触发器。在 always 模块内被赋值的每一个信号都必须定义成 reg 型。格式与 wire 型类似:

reg [n-1,0] 数据名 1,数据名 2,…数据名 i;

reg [n,1]  数据名 1,数据名 2,…数据名 i;

reg 数据可以赋正值,也可以赋负值。但是当一个 reg 数据是一个表达式的操作式时,它的值被当做无符号值,即正值。如:4 位的 reg 被赋值为 -1,在表达式中为 +15.

reg 型只是表示被定义的信号将被用在 always 模块中,并不是说 reg 型数据就一定是存储器或触发器的输出。

something to 注意

1,防火防盗防 latch,一般来说锁存器有利有弊不过大部分都是弊除非你是需要锁存器在你的电路中的应为大部分锁存器的产生都是因为程序错误以下为我目前总结的急救方法

1)在组合逻辑进程中,if 语句一定要有 else!并且所有的信号都要在 if 的所有分支中被赋值。

2)case 语句的 default 一定不能少!

else if(几个例子)

module top_module(
input [2:0] vec,
output [2:0] outv,
output o2,
output o1,
output o0
);

assign outv = vec;
assign o0 = vec[0];
assign o1 = vec[1];
assign o2 = vec[2];

endmodule
此例就是输入一个三位的量通过 o1,o2,o0 分别输出和 outv 进行 3 位数据输出

下面的例子学过数电的同学应该不会陌生就是通过真值表进行设计电路这里我在这顺便怀念一下数电课

module top_module (
input x3,
input x2,
input x1,
output f
);
assign f = (~x3 & x2 & ~x1) |
(~x3 & x2 & x1) |
(x3 & ~x2 & x1) |
(x3 & x2 & x1) ;

endmodule
这里 f 就是所有为真逻辑的或用 assign 输出就可以了。

给定 100 位输入向量 [99:0],反转其排位顺序

module top_module (
input [99:0] in,
output reg [99:0] out
);

always @(*) begin
	for (int i=0;i<$bits(out);i++)		 
		out[i] = in[$bits(out)-i-1];	is 100 bits wide.
end

endmodule

哈哈久违的 for 循环有了 c 语言的感觉

else content=content;

end

end module