前言

FPAG虽说是嵌入式的,但和一般的嵌入式单片机差别很大,FPGA定义“一种可通过编程来修改其逻辑功能的数字集成电路”,
说简单点就是他的程序是用来修改电路的,而大多数单片机编程改变不了他的电路内部连接,大多是用来程序设计。
Verilog 是FPGA的一种编程方式,他跟单片机C语言语法有些类似的地方,但是框架不同,单片机是串行,FPGA是并行,
简单点说就是一个是单线程,一个是多线程

Verilog学习

因为我之前一直是学习STM32,STC15,ESP32这些,他们的编程方式基本一样,互通的,但是FPGA就另类了,没办法,得听
导师的学这个,不然就得学PLC那些了,哈哈哈所以,我将用Verilog和单片机C语言对比的方式学习,这样更容易理解和记忆。

Verilog-逻辑值

Verilog的逻辑值是0,1,x,z 四个值,分别代表 低电平 高电平 未知电压(高/低) 高阻悬空 ,而C语言只有0和1,也就
是高电平和低电平两个状态。 在单片机C语言中,数字信号是以二进制0和1组成的,比如 IO口控制LED 我用0和1控制
亮和灭;在信号传输中根据高低电平输出的 0xff(1111 1111)信号 都是0和1组成的,但Verilog就不一样了,他的引脚
输出还可以是x,z ,也就是说 在Verilog中 我的值 不再是单纯的数字了,我还有其它状态,我觉得这个就是Verilog
和C最本质的区别,C是面对软件的,就像计算机是二进制的,他们都属于软件类,而Verilog是面对硬件的,就要有实际
硬件的状态,就多了未知电压和高阻悬空这两个状态。 举个例子:在c语言中 假设变量a; if(!a)的条件是 a=0的时候执
行if里的函数,而在Verilog中 if(!a)表示的是 a为0/x/z的时候都可以执行if里的程序

Verilog-进制

二进制:4’b0101 表示4位二进制数字0101
十进制:4’d2 表示4位十进制数字2 0010
十六进制:4’ha 表示4位十六进制数字a 1010

‘前面的数字是表示数据是转为二进制几位的存储单元 不加默认32位
‘后面的b o d h 就跟c语言表示进制是一致的
数字 ‘ 字母 都不加的 默认32位十进制

Verilog-引脚定义

在单片机C语言中,在添加完对应单片机型号的头文件 就可以直接定义一个变量指代单片机的引脚
例如 STC51 STC15 等系列单片机 直接 sbit led = P1^0 就可将P1^0引脚用led 标识符来代替 进而控制控制或者读取
在stm32系列中,又比51系列的多些步骤,就是每个引脚多需要配置他的频率、强推挽…51的话有默认状态可以省去,
15系列也可以去设置推挽状态
但在Verilog中,他不存在头文件,自然就没有程序控制引脚,只是定义一个变量然后在软件中按引导选择配置他的引脚,
这样感觉要比前者更好的多,在移植程序中会更加方便在C中就很麻烦了,还得在一个一个的.c .h中找哪儿定义了什么引脚,
而且定义引脚的方式也很多,有用寄存器版本的额,有库函数版本的,HAL库版本的,所以说在这块,FPGA做得确实很好。
pC96i28.jpg

在配置系统时钟频率方面,FPGA更加方便,直接填写具体频率参数即可,而C还得配置很多寄存器,什么分频电路,相当麻烦。

Verilog-数据类型

三大数据类型:寄存器数据类型 线网数据类型 参数数据类型
寄存器和线网相当于C中引脚定义的数据类型,可以直接和硬件引脚连接
参数就类似C中的普通变量了

寄存器类型

寄存器表示一个抽象的数据存储单元,通过赋值语句可以改变寄存器储存的值
寄存器数据类型的关键字是reg,reg类型数据的默认初始值位不定值x

reg [31:0] deelay_cnt;  //定义一个32位的数据 延时计数  **不可赋初值!**
reg key_reg; //默认位宽位1

用[x:0]来定义变量的位宽 位宽值位0-x的位数 即位数=x+1

如果 该数据类型带有时钟信号,则该寄存器变量对应位触发器,对应于C中的晶振输出频率,如pwm
如果不带时钟信号,则该寄存器对应位硬件连线 即C中的引脚定义标识符

线网类型

线网数据类型表示结构实体(例如逻辑门)之间的物理连线
线网类型的变量不能储存值,它的值是由驱动他的元件所决定的

wire     key_flag;    // 若无驱动原件接到该变量上 **则其值位Z** 高阻

参数类型

参数其实就是个变量,这跟C中的变量一样

parameter H_SYNC = 11'd41;  //行同步

Verilog-运算符

pC9RW7Q.png
pC9Ropq.md.png
将两个数据前后连接起来 两个数据得是相同位宽

Verilog-关键字

pC9RT10.png

Verilog-模块的结构

Verilog的设计基本单元是“模块”block
一个模块由两部分组成,一部分描述接口,另一部分描述逻辑功能

module block(a,b,c,d);
input a,b;
output c,d;

assign c = a | b; //assign 用于赋值
assign d = a & b;

endmodule

这里的模块 就跟C中的main函数差不多 不过c只有一个main 串行的 而Verilog可以有多个always部分 相当于是C中的多个while 并行
就跟单线程和多线程差不多

描述接口可直接添加在括号内定义  
每个Verilog包括四个主要部分:端口定义 IO说明 内部信号声明 功能定义

assign 语句用来描述组合逻辑,always 语句 描述组合/时序逻辑 例化实例元件 三个逻辑功能是并行的

Verilog-结构语句

initial 和 always
initial 语句在模块中只执行一次 这个跟arduino中的 void setup() 函数意思一样
always 不断重复活动 就类似arduino中的 void loop() 函数

逻辑功能分为 组合逻辑电路和时序逻辑电路
组合:任意时刻的输出取决于该时刻的输入,与原电路状态无关、 类似开环
时序:取决于该时刻输入和原电路状态 具有记忆功能 类似前置反馈

Verilog-赋值语句

阻塞赋值 就跟C语言一致 如:

always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
a=1;
b=2;
c=3;
end
else begin
a=0;
b=a;
c=b;
end
end

是 先a=0后再执行b=a; 正常串行执行

非阻塞赋值 = 变成 <=

always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
a<=1;
b<=2;
c<=3;
end
else begin
a<=0;
b<=a;
c<=b;
end
end

程序中 a=0;b=a;是同时执行
= 和<=不可同时存在 要不乱套了

Verilog-条件语句

pC9RvN9.png
pC9RjAJ.png