这里先讲讲狭义的组合逻辑和时序逻辑,时序逻辑一般指的是D触发器,组合逻辑指的是:与门 或门 非门,比较器,选择器,编码器,译码器,加法器,当然还有两类比较特殊的就是三态门和RAM,时序逻辑D触发器需要时钟来驱动的,也就是必须要有时钟才会 动作,而组合逻辑不需要时钟驱动,在时序图上的表现就是时序逻辑的输出比输入晚一个时钟周期,而组合逻辑输入和输出都是在同一个时钟周期,所有的数字电路 都是由组合逻辑和时序逻辑构成,大到CPU,小到电子表芯片,然后我们看看上面的组合逻辑和时序逻辑怎么来用硬件描述语言来描述,
1:与门
assign c = a&b;
always@(*)
c=a&b
2:或门
assign c = a|b;
always@(*)
c=a|b
3:非门
assign c = ~a;
always@(*)
c=~a
4:比较器
assign c = (a>=b)?1'b1:1'b0;
always@(*)
if(a>=b)
c=1'b1;
else
c=1'b0;
5:选择器
assign c = (a>=b)?d:e;
always@(*)
if(a>=b)
c=d;
else
c=e;
6:译码器
always@(*)
case(a)
2'b0;c=4'b0001;
2'b1;c=4'b0010;
2'b2;c=4'b0010;
2'b3;c=4'b1000;
endcase
7:编码器
always@(*)
case(a)
4'b0001 :c=2‘d0;
4'b0010 :c=2’d1;
4'b0010 :c=2'd2;
4'b1000; c=2'd3;
endcase
8:加法器
assign c= a+b;
时序逻辑D触发器
alway@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)
q<=1'b0;
else
q <=d;
end
描述完成上面的这些,我基本上可以用上面这些标准的电路和语言描述出90%的数字电路了,先从最简单的计数器开始吧,计数器在常见不过,我们先写一个模10 的计数器,省去模块端口定义和信号定位,以下就是核心代码了,为了让LZ可以看清楚具体的电路,可能刚刚看着代码LZ可能会有些难懂,不过没有关系,要学 会硬件的思维这个是必经之路
我们可以看到一个简单的模10计数器实际上是由4部分组成,一个比较器,一个加法器,一个选择器,和4个D触发器,所以一个计数器实际上是由上面最初介绍的 那几个基本单元组成,我打开了FPGA神器quartus,综合一些,改正了若干的语法错误,然后最终的综合的RTL电路如下
电路和代码配合的实在是太好了 代码描述了4部分的电路,而电路也表现出来了4部分的电路,我们可以看到 ADDER 加法器,LESS_THAN 比较器,MUX21 选择器 最后一个D触发器,这就是硬件思维,硬件思维就是认为所有的数字电路都是由基本的组合逻辑和时序逻辑的组件组合而成,写出来的代码都有对应的最小的电路组 件来对应,既然代码都写出来代码,那我们就来看看时序图,来验证一下 时序逻辑的输入和输出总是延迟一个时钟周期,组合逻辑的输入和输出在同一个时钟周期,开始搭建testbench,此处省略一万字,熟悉的波形终于出来了
可能上面那个也周期内的图不一定看的清,就看第二幅图吧,我们可以看到在
这3行代码是同时执行的,是串行的,在cnt_cnr >='d9的那一个时钟周期就执行完成,和C语言的执行方式其实是一样的,但是cnt_cur 的赋值就可以看到虽然是把cnt_nxt 赋值给cnt_cur,但是由于是时序逻辑所以总是要延迟一个时钟周期,好一个最简单的模10计数器就介绍完了,但是是不是所有的计数器都要写的这么复杂 能,不是,还有两种基本的写法,一种写法就是如下,把所有的组合逻辑都写在了一起,
还有这种最最常见的写法就是不区分组合逻辑和时序逻辑,所有的都写在一个always块里面,就当成时序逻辑来写,这个只不上是上面两种电路的一种抽象一点的写法,但是基本的组合逻辑和时序逻辑都还是一样
不信看看rtl 和上面的一模一样
一个基本的电路都是由基本的组合逻辑电路和D触发器组成,如果不能用着两个来组成,那你可能是弄错了,比方说有新手经常写一个延时电路,能用# 10么,#10可以是由选择器,还是与或非或者是D触发器来组成么,综合器能理解么,明显不行,所以在自己写一个代码的时候一定要想想他最后的电路是什 么,谈完了计数器,这个最最常用的电路,谈完了这个我想在谈谈verilog,对于verilog我的建议是,遇到组合逻辑用阻塞赋值,遇到时序逻辑用非 阻塞赋值,基本的语法就那么几条,
always assign if else case ?: >= <= == & | ~ && || !这个几个搞定了,应该所有的电路都可以描述了,其他的什么就不用去理会了,你写RTL是用不着的,乱用反而会用错,什么while , initial ,这些都是仿真用的,写rtl根本用不到,
至于如何上手比较快些,FPGA开发的流程无非就是 ,方案,代码,仿真,后端约束,上板验证,找一个项目吧这个流程都走一我相信上手起来应该不难比如说开发一个简单的UART,这个最常见的模块,或者一个 dds,或者sdram控制器,首先把方案做出来,就是把基本的电路和实现方法画到草稿上面或者电脑上面,考虑多方面,可靠性,可实现性,资源,能不能跑 到要的时钟频率,等等,接口的信号有哪些,时序是什么样子的,内部怎么控制,用状态机还是计数器,状态机的状态转移图是什么样,有哪些状态,状态迁移的条件有哪些,会不会跑非,等等