verilog 介绍(附状态机实例)


author: hjjdebug

date: 2024年 10月 12日 星期六 15:02:56 CST
description: verilog 介绍(附状态机实例)

初学者可以把菜鸟教程中的verilog 当参考手册.

但那里介绍的太多了,精简入门(或者入门后的概括)看看本博就够了.

1. 什么是HDL ?

HDL, hardware description language, 硬件描述语言

其分为两部分:

a. 逻辑功能设计.

用HDL 语言在不同层次描述对数字电路的功能、结构和行为进行描述.

b. 电路实现

通过综合工具将逻辑设计转化为门级电路网表,再将其与某种工艺的

基本元件逐一对应起来,再通过布局,布线工艺转换为电路的布局,布线

美国,中国,日本多使用verilog, 欧洲多使用vhdl

2. verilog 是什么?

verilog 是一种类C 语言, 它的词法和语法借鉴了C, 减小了它的入门门槛.

但verilog 是硬件描述语言,数字电路是它的基础,运算是并行的,这是与C不同之处.


1. 基础知识:(词法)


1.1: 逻辑值, 0,1,X,Z(低,高,不定,高阻)

1.2: 数据的表示方式:

表示方式是<位宽'类型数值>

常见类型: b,d,h (二进制,十进制,16进制)

例如:

4'b0101

4'd9

4'hb

16'b0101_1010_0101_1010 = 16'h5a5a

1.3: 标识符

标识符用来表示模块名,端口名,信号名

1.4: 数据类型(3种), 寄存器类型,线网类型,参数类型(非线路类型)

1.4.1: reg 关键字说明寄存器类型.

该类型代表一个抽象的数据存储单元.

通过赋值语句可以改变寄存器中储存的值.

它可以在 always 语句和 initial 语句中被赋值.

如果该过程语句描述的是时序逻辑,即 always 语句带有时钟信号,则该寄存器变量对应为寄存器;

如果该过程语句描述的是组合逻辑,即 always 语句不带有时钟信号,则该寄存器变量对应为硬件连线;

寄存器类型的缺省值是 x(未知状态)

reg [31:0] delay_cnt; //位宽32位的寄存器

1.4.2: wire 关键字说明线网类型

它代表元件间的物理连线。它的值由驱动元件的值决定

如果没有驱动元件连接到线网,线网的缺省值为 z(高阻态)

wire[7:0] data; // 8bits 数据

1.4.3: 由parameter 关键字说明的变量是参数类型

参数类型实际上是定义一个常数.

例:

parameter DATA_WITH = 8; //跟c语言中的宏类似

外部调用模块时,还可以传递参数.

类型后边跟一个标识符,说明这个变量时什么类型.

1.5: 注释

与c 一样, //注释单行, /* */注释多行

1.6: 运算符

与c 一致.

算术运算符: ±*/%

关系运算符: >,=,<,>=,<=,==,!=

逻辑运算符: &&,||,!

条件运算符: ?:

位运算符: ~,^,&,|

移位运算符: <<,>>

新增一条强势组合操作符,拼接运算符

例如: c={a,b} 把a,b 拼成c信号

1.7: 关键字.

关键字用来表示特定的意义,指导编译程序完成特定功能. 掌握常用关键字即可.


2. 常用关键字介绍


if - else 语句

if - else if -else 语句

for 语句

while 语句

以上与c 一致

case 语句

c 中是switch ... case 形如: switch(var) case val1: do1;break...;default: do_defaut;

v 中是case ... endcase 形如: case(var) val1: do1; val2:do2; default: do_default; endcase;

与c不同的地方

c 用{} 表示语句块, v用begin, end 表示语句块

c 用 = 直接给变量赋值,v 叠加了assign 或者 always 关键字给变量赋值

assign 用于简单的组合逻辑赋值语句

always 即可用于组合逻辑,此时功能与assign 一样, 也可用于时序逻辑.

always 语句常常带有敏感信号列表,带begin,end 语句块,看起来像一个c中的无名函数

= 是阻塞赋值, 用在组合电路中

<=是非阻塞赋值, 用在时序带路中

always 语句块, 其内部可以认为是顺序执行的,而always 块与块之间是并行执行的.

注: 硬件语句一定要注意语法的完整性,有if一定要跟else, 有case 一定要有default,不能有不周全的地方.

否则可能会有glitch 毛刺的产生.


3. 模块化设计


一个模块对应一种功能,上层模块调用下层模块.

每调用一次模块,需要先对模块实例化.

模块相当于c++中的类, 模块的参数相当于带参对象的构造函数


4.实战: 4位密码锁设计

当然,改成8位也是很简单的.


状态机的编写

典型的状态机例子就是一个密码锁. 它有10个按键输入

假如实现4位密码锁,其密码是1217,输入正确开锁,不正确不开锁.

c语言的状态机只需要一个switch-case 块.

v语言常用三段式状态机. 因为它有组合逻辑部分和时序逻辑部分,需要区别对待.

基本格式是:

第一个 always 语句实现同步状态跳转;(时序电路), 在时钟上升沿把下一状态付给当前状态

第二个 always 语句采用组合逻辑判断状态转移条件;//类似于c语言的switch-case块, 找到下一个状态

第三个 always 语句描述状态输出(可以用组合电路输出,也可以时序电路输出)。对应moore 和 mealy状态机

代码:

c 复制代码
module Cipher(
	input sys_clk,
	input reset,
	input key0,
	input key1,
	input key2,
	input key3,
	input key4,
	input key5,
	input key6,
	input key7,
	input key8,
	input key9,
	output reg result
);

//parameter define
parameter S0 = 3'b000 ;
parameter S1 = 3'b001 ;
parameter S2 = 3'b010 ;
parameter S3 = 3'b011 ;
parameter S4 = 3'b100 ;

//reg define, 当前状态和下一状态,3bits
reg [2:0] curr_st;
reg [2:0] next_st;

//main code

//状态机的第一段采用同步时序描述状态转移
always @(posedge sys_clk or negedge reset) 
begin
	if (!reset)
		curr_st <= S0;
	else
		curr_st <= next_st;
end

//状态机的第二段根据当前状态及输入采用组合逻辑判断状态转移条件
//按键低有效
always @(
	negedge key1,
	negedge key2,
	negedge key3,
	negedge key4,
	negedge key5,
	negedge key6,
	negedge key7,
	negedge key8,
	negedge key9
) 
begin
	case (curr_st)
		S0: 
		begin
			if(key1 == 1'b0) next_st = S1;
			else next_st = S0;
		end
		S1: 
		begin
			if(key2 == 1'b0) next_st = S2;
			else next_st = S0;
		end
		S2: 
		begin
			if(key1 == 1'b0) next_st = S3;
			else next_st = S0;
		end
		S3: 
		begin
			if(key7 == 1'b0) next_st = S4;
			else next_st = S0;
		end
		default: 
			next_st = S0;
	endcase
end

//状态机的第三段描述状态输出(这里采用时序电路输出)
always @(posedge sys_clk or negedge reset) 
begin
	if (!reset)
		result <= 1'b0;
	else if (curr_st == S4)
		result <= 1'b1;
	else
		result <= 1'b0;
end

endmodule

测试代码:(test_bench)

c 复制代码
//时间精度/显示精度
`timescale 1ns/1ns
module tb_basic();

//regeister and wire
reg sys_clk;
reg reset;
reg key0;
reg key1;
reg key2;
reg key3;
reg key4;
reg key5;
reg key6;
reg key7;
reg key8;
reg key9;
wire result;


//initial, 输入信号激励及仿真命令
initial
begin
	$dumpfile("basic.vcd");
	$dumpvars(0,u_Cipher);
	sys_clk = 1'b1;
	reset = 1'b0;
	key0=1'b1;
	key1=1'b1;
	key2=1'b1;
	key3=1'b1;
	key4=1'b1;
	key5=1'b1;
	key6=1'b1;
	key7=1'b1;
	key8=1'b1;
	key9=1'b1;
	#100;
	reset = 1'b1;
	key1=1'b0;  // 1 press
	#100;
	key1=1'b1;
	key2=1'b0; // 2 press
	#100;
	key2=1'b1;
	key1=1'b0; // 1 press
	#100;
	key1=1'b1; 
	key7=1'b0; // 7 press
	#100;
	//	$stop;
	$finish;
end

//时钟激励, 25M 时钟
always #20 sys_clk=~sys_clk;

Cipher u_Cipher(
	.sys_clk(sys_clk),
	.reset(reset),
	.key0(key0),
	.key1(key1),
	.key2(key2),
	.key3(key3),
	.key4(key4),
	.key5(key5),
	.key6(key6),
	.key7(key7),
	.key8(key8),
	.key9(key9),
	.result(result)
);
endmodule

仿真结果:

测试输入密码1217, 给出了结果result=1. 测试通过.

相关推荐
枯无穷肉2 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6772 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式大圣3 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室3 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费3 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
liyinuo20175 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
艺术家天选5 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件
Anin蓝天(北京太速科技-陈)6 小时前
252-8路SATAII 6U VPX高速存储模块
fpga开发
小猪写代码7 小时前
STM32 水质水位检测项目 (调试模块)和(延时模块)
stm32·单片机·嵌入式硬件
御风_217 小时前
STM32单片机使用CAN协议进行通信
stm32·单片机·嵌入式硬件