假期总结篇之——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

 

 

 

 

 

 

没有更多推荐了,返回首页