FPGA开发之Verilog语言介绍

Verilog语法基础

  • Verilog HDL 定义
  • 相关术语
  • 基本模型结构
    • 端口
    • 数据类型
    • 行为建模
  • Verilog HDL函数和任务

Verilog HDL 定义

  • 并不是软件编程语言;
  • 是一种硬件描述语言,可综合和可仿真的代码,使用目标器件的硬件单元来实现功能。

相关术语

  • 行为建模——由其输入输出关系描述的组件;
    只指定电路功能,不指定电路实际结构。
  • 结构化建模——由底层组件和原语描述上层组件;
    不仅指定电路功能,还规定了电路结构,常用于综合。
  • 综合——将HDL译成电路,然后对表征电路进行优化;
    FPGA开发之Verilog语言介绍_第1张图片

基本模型结构

一个Verilog模块主五个基本部分组成:

  • 端口列表
  • 端口的定义
  • 寄存器和网络节点
  • 定义电路功能的代码
  • 为仿真环境提供的时序规范
    FPGA开发之Verilog语言介绍_第2张图片

端口

  • 端口列表
    端口名称列表
    eg:
module mult_acc(out,ina,inb,clk,clr);
  • 端口类型
    input ——输入端口
    output ——输出端口
    inout ——双向端口

  • 端口声明

    eg:

input[7:0] ina,inb;
input clk,clr;
output[15:0] out;	

数据类型

  • 网数据类型(NET)
    表示进程之间的物理互联(活动流程)
类型 定义
wire 表示一个节点或连接
tri 表示一个三态节点
supply0 逻辑0
supply1 逻辑1

eg

wire[7:0] out;
tri enable;
  • 寄存器数据类型
    暂时存储数据的变量,不仅仅包括物理寄存器寄存器可以是以下任意之一:寄存器、整数、实数、时间、实时
    只能在进程声明、任务或者功能中赋值reg类型变量
    不能是逻辑门输出,或者assign语句的输出
    eg
reg[7:0] out;
integer count;
  • 模块端口输入输出规则
数据类型 输入 输出 双向
网数据类型 YES YES YES
寄存器数据类型 NO YES NO
  • 赋值-数字
    sized或者unsized:
    < size >’< base formal >< number >
    sized例子:3’b010——3位宽二进制数字
    unsized例子:123——默认的32位宽十进制数字
    基本格式:
    十进制('d/'D)16’d255=16位宽十进制数字
    十六进制('h/'H)8’h9a=8位宽十六进制数字
    二进制('b/'B)'b1010=32位宽二进制数字
    八进制('o/'O)'o21=32位宽八进制数字

行为建模

  • 连续赋值声明
    左手侧必须是net数据类型;
    右手侧可以是net、寄存器或者是函数调用。
    eg:
wire adder_out=mult_out+out

等价于

wire adder_out;
assign adder=mult_out+out
  • 进程赋值模块
    initial模块:
    用于初始化仿真的行为说明(被综合器忽略);
    用于初始化仿真,监视波形和其他进程,在仿真中只能执行一次。
    always模块:
    使用行为声明,用于描述电路功能;
    对数字电路中不断重复地进程进行建模,以循环地方式连续执行行为声明。
    注意:
    每个always和initial模块代表不同的进程;
    各个进程并行运行,在仿真时间0开始;
    进程中的声明顺序执行;
    always和initial模块不能嵌套。
    eg:
module clock_gen(clk);
output clk;
reg clk;

initial
	clk=1'b0;
always
	#25 clk=-clk;
initial
	#100 $finish;
endmodule
时间 执行的声明
0 clk=1‘b0
25 clk=1‘b1
50 clk=1‘b0
75 clk=1‘b1
100 $finish
  • 两类进程赋值
    阻塞赋值(=):按顺序模块中指定的次序执行。
    非阻塞赋值(<=):不对顺序模块后的声明进行阻塞赋值,支持对赋值的调度。
    eg:
initial
	begin
		#5 a=b;
		#10 c=d;
	end

阻塞时间表

initial
	begin
		#5 a<=b;
		#10 c<=d;
	end

非阻塞时间表

  • 使用进程模块的电路类型
    组合电路:对组合逻辑中使用的所有输入敏感。
    eg:
always @(a or b or sel)

组合逻辑
时钟电路:对时钟以及控制信号敏感。
eg:

always @(posedge clk or negedge clr)

时钟电路

  • 行为声明
    IF-ELSE声明:
    对条件按照从上到下的顺序进行评估;
    有优先级。
    eg:
always @(sela or selb or a or b or c)
	begin
		if(sela)
			q=a;
		else
		if(selb)
			q=b;
		else
			q=c;
	end

IF-ELSE
CASE声明:
立即对所有条件进行评估;
没有优先级。
eg:

always @(sel or a or b or c or d)
	begin
		case(sel)
			2'b00:
				q=a;
			2'b01:
				q=b;
			2'b10:
				q=c;
			default:
				q=d;
		endcase
	end

CASE
注意:
casez认为case条件下的所有z值不重要;
casex认为case条件下的所有x和z值都不重要。
循环声明:
用于重复运算。

  1. Forever循环——不断执行。
    eg:50个时间单位的时钟周期
initial
	begin
		clk=0;
		forever #25 clk=-clk;
	end
  1. Repeat循环——执行一定次数。
    eg:重复8次循环操作
if(rotate==1)
	repeat(8)
		begin
			tmp=data[15];
			data={data<<1,temp};
		end
  1. While循环——如果表达式为真,则执行。
    eg:从0到100计数,101时退出循环
initial
	begin
		count=0;
		while(count<101)
			begin
				$display("Count=%d",count);
				count=count+1;
			end
	end
  1. For循环——循环开始时立即执行一次,如果表达式为真,则继续执行。
    eg:4位向左移
integer i;//declare the index for the FOR LOOP
always @(inp or cnt)
	begin
		result[7:4]=0;
		result[3:0]=inp;
		if(cnt==1)
			begin
				for(i=4;i<=7;i=i+1)
					begin
						result[i]=result[i-4];
					end
				result[3:0]=0;
			end

注意:
必须用于always或者initial模块中;
这些行为声明也可以用在时钟进程中。

Verilog HDL函数和任务

  • 函数
    根据输入返回一个值;
    产生组合逻辑;
    用下面表达式中:
assign mult_out=mult(ina,inb);
  • 任务
    与其他编程语言中的进程相似;
    可以是组合或者寄存器形式;
    以声明的形式调用任务:
stm_out(nxt,first,sel,filter);

注意:
函数和任务都是子程序;
用于可重复代码;
增加模块可读性;
二者区别:

  1. 函数
    可以使能其他函数,但不能调用其他任务;
    函数是组合逻辑,因此不能包含其他任何延迟、事件或者时序控制声明;
    至少要有一个输入变量;
    总是返回一个数值;
    不能有output、inout变量。
  2. 任务
    可以使能其他任务和函数;
    可以包含延迟、事件或者时序控制声明;
    可以有0或者更多的输入;
    返回0或者更多的数值;
    可以有output或者inout变量。

eg:
函数定义——乘法器

function[15:0] mult;
	input[7:0] a,b;
	reg[15:0] r;
	integer i;
begin
	if(a[0]==1)
		r=b;
	else
		r=0;
	for(i=1;i<=7;i=i+1)
		begin
			if(a[i]==1)
				r=r+(b<<i);
		end
	mult=r;
end
endfunction

Verilog模块实例——乘加器

module mult_acc(out,ina,inb,clk,clr);
input[7:0] ina,inb;
input clk,clr;
output[15:0] out;

wire[15:0] mult_out,adder_out;
reg[15:0] out;

parameter set=10;//常量
parameter hld=20;

assign adder_out=mult_out+out;
always @(posedge clk or posedge clr)
	if(clr) out=16'h0000;
	else out=adder_out;
//函数调用
assign mult_out=mult(ina,inb);
endmodule

任务实例

module tasks;
//任务定义
task add;//与函数不同,不需要传递参数
	input a,b;
	output c;
begin
	c=a+b;
endtask
//任务调用
initial
begin:init1
	reg p;
	add(0,1,p);//按顺序进行传递
	$dispaly("p=%b",p);
end
endmodule

你可能感兴趣的:(概念,verilog,fpga)