
1.在使用case或casex结构进行同步状态机构建时,最后一定要有default状态,在这个状态中主要设计的是纠错程序,这个非常重要,通过这个状态可以把状态机因状态位错误而进入无效或错误的状态中拉回来,或跳出这次操作强制进入下一次操作的初始状态。
2.在使用else-else if ……-else结构时,各个条件之间必须完全是明确地互斥,任何两条件在任何时候都必须不能同时满足。这个很重要,此重要性,虽在仿真阶段没什么大问题,但当综合成门电路以后在现实的硬件上进行运行时,就会暴露出很多缺陷,影响稳定性问题以及兼容性问题。
3.① 在进行同步时序逻辑设计时,对由其他非主时钟信号沿触发的事件,采用信号沿跟 踪寄存器,来及时判断沿的发生,当然这样会产生误差,最大会有一个主时钟周期;
② 判断沿发生的另一种方法是,使用主时钟发生两个一个周期相同的时钟信号,第二个时钟要落后于第一个时钟一个周期,当第一个时钟为高而第一个时钟为低时,说明在此之前第一个时钟有一个上升沿,第二种方法依然会有一个主时钟周期的误差。
4.在把测试模块包括在内的顶层模块的编写中,需要使用“include”来把各个子模块包含进来(被包含的文件名要写完全路径),不需要有输入输出端口列表,也不需要在模块中使用input和output进行声明,但在模块中,必须对需要引用的下层模块的输入输出变量进行声明,不管输入还是输出变量都声明成wire类型,如果不声明则均默认成位宽为1位的变量;在不包括测试模块的顶层模块中,要有输入输出列表,把所有子模块的对外输入输出在列表中体现,并且使用input和output进行声明,其中output也必须默认成wire类型的,而子模块间的输入输出变量使用wire进行一下声明就可以了,但必须要有。
5.在同步状态机设计中,要在前一状态为下一状态的关键变量进行赋值,以使在进入下一状态时,获得稳定的条件。
6.在同步状态机设计中,一定要在必要的状态中设计一个判断条件,以便当发生异常时,能及时跳出这个状态,重新开始,防止发生状态机死机现象。
7.在状态机中调用task时,使用一个标志寄存器在主状态机中和task状态机中来回推拉,以使二者工作时衔接紧密。
8.切记千万不可在主状态机和从状态机中同时对某一变量赋值,否则综合出来的电路会有问题。
9.不能对同一个变量同时地进行输入和输出操作,否则此数据会不准确,影响整个系统的性能;
10.为功能模块编写测试模块时,在模块头不需要使用include引用原模块,直接进行实例化就可以了。否则,在ISE中新建一个项目的时候,不能够直接把测试文件加在原功能模块的下面,且后仿真不会正确,因为ISE会认为这种层次关系是错的,它默认的是,被include引用的是底层模块,而此模块本身为顶层模块;
11.除法运算不可综合;
12.必须确保声明的每一个寄存器变量位都能用到,不能有空闲位,否则在综合时会有Warning,例如,声明了temp[8:0]的寄存器变量,但在所有用到temp的地方最多也就用了8位,这时在综合时就会产生Warning,称最高位没有相连或此变量没有初始化而为常量;
13.在使用assign语句进行连续赋值时,类似“assign c=a=b=1;”的语句是错误的,正确的应该是:“assign c=1,b=1,a=1;” ;
14.在进行后仿真时,若逻辑与预期的设计不一致,有两种办法来进行调试,一是,降低时钟频率;二是,修改状态机,再增加一个时钟周期产生数据使能信号,这就有可能消除由于时钟过快引起的触发器输入端由延迟和冒险竞争造成的不稳定,从而使逻辑正确;
15.冒险和竞争一般都是由组合逻辑和路径延迟引起的,为了很好地避免冒险竞争,在设计中采用同步时序逻辑设计。同步逻辑设计的主旨就是,利用上一个时钟沿为下一个时钟沿的触发创造稳定可靠的条件,所有的输入输出信号至少有一个时钟周期的时间来稳定,具体一点说,所有被赋的值在上一时钟沿前就已经保存在寄存器中,这些信号有足够的时间传送到被赋值的寄存器的数据端口,当时钟沿到来时它们都已经稳定,所以存入的寄存器的数值是可靠的,但这需要一个前提,即下一个状态所使用的组合逻辑电路信号的延迟与时钟到各触发器的时间的差值必须小于一个时钟周期的宽度;
16.在使用case(x,z)……endcase结构语句时,若两个或两个以上的可选择状态值,可以是相同的处理,这样就可以将其简写成:
Casex (state)
2’b00,
2’b01,
2’b10:
begin
-------------------------------
--------------------------------
end
2’b11: -------------------------------
Default: --------------------------------
重点是在2’b00和 2’b01之间必须使用逗号;
17.状态的转移不是由唯一的时钟来触发的状态机,为异步状态机,其不可综合;
18.在使用case或casex写状态机时,一定要有default状态,若状态编码中没有多余状态时,默认状态要写成“default: state<=’bx”,然后通过复位信号来设置状态机的初始状态,这样以便与综合后的硬件状况一致,因为硬件系统一上电后的各个状态值都是不确定的,切不可把它设为某一已知有效状态,若在状态编码中,有多余状态,在默认状态中可使用综合指令或在源代码中直接设置,把状态值设置为某一个有效状态,避免死锁;
19.使用Verilog做一个信号一个时钟的延时的最简单方法是,在触发时钟的某个沿,将此信号赋给另外一个寄存器,则这个寄存器的值落后源信号状态一个触发时钟周期,例如,
Always @ (posedge clk)
B<=a;
则,B的值落后于a的值一个clk的周期;
20.在可综合语言书写的模块中,尽量少用函数,推荐多用task来代替,因为用函数书写的逻辑在很多情况下是不可控的;
21.在使用task时,在语法上,可以有输入参数也可以有输出参数,即可以在task内部定义input和output变量,但一般只通过task的调用来传递输入参数,而对于输出变量,则可以在task程序内部直接对输出变量进行赋值,因为如果通过调用来传递输出参数的话,它进行的是阻塞赋值,尽管task内部所有的语句都是非阻塞赋值,这样的话如果在全部是非阻塞赋值的always块内进行调用这个task的话,就出现了既有阻塞赋值又有非阻塞赋值,而造成非可综合的结果。
22.在有异步复位的模块里,复位触发与主时钟触发关系的处理:
以下为一段资料里的描述,
The compiler only extracts standard flip-flops that are clocked by a single clock edge. Any attempt to create a register that does not represent a standard flip-flop results in the error.
In the following test case, the process is executed whenever there are multiple edges (on clock or on reset), but the flip-flop is to be loaded with the current data on both edges. This behavior does not match the normal operation of the flip-flop.
module counter2 (out, data, rst, clk);
output [7:0] out;
input [7:0] data;
input rst,clk;
reg [7:0] out;
reg cout;
// create the 8-bit register
always @(posedge clk or negedge rst)
begin
out <= data;
end
endmodule
User Action:
To avoid this error, recode the process to match a flip-flop in hardware. To eliminate this error in the above test case, add a condition to reset the flip-flop as shown in the corrected test case below.
module counter2 (out, data, rst, clk);
output [7:0] out;
input [7:0] data;
input rst,clk;
reg [7:0] out;
reg cout;
// create the 8-bit register
always @(posedge clk or negedge rst)
begin
if (!rst)
out <= 8'b0;
else
out <= data;
end
endmodule
也就是说,在有复位触发的模块里,复位信号触发的就是复位触发的,主时钟触发的就是主时钟触发的,不允许掺入其他逻辑,必须是感觉的触发信号。例如以下程序,
always @ (posedge CLK_S or posedge RESET)
if (RESET)
begin
if (flag1==0)
begin
flag1<=1;
bd_timer<=87;
clk_counter_t<=0;
clk_transmit1<=0;
clk_transmit2<=0;
end
end
else
――――――――
――――――――
――――――――
对于,flag1的处理,只能这样写,若是写成,
always @ (posedge CLK_S or posedge RESET)
if (RESET&& flag1==0)
begin
flag1<=1;
bd_timer<=87;
clk_counter_t<=0;
clk_transmit1<=0;
clk_transmit2<=0;
end
else
――――――――
――――――――
――――――――
这样的是不可综合的,当是同步复位的就可以这样写了,即
always @ (posedge CLK_S)
if (RESET&& flag1==0)
begin
flag1<=1;
bd_timer<=87;
clk_counter_t<=0;
clk_transmit1<=0;
clk_transmit2<=0;
end
else
――――――――
――――――――
――――――――
总之,在进行设计时,一定要以最坏的情况考虑现实环境,而且编写风格一定要严谨,严格按照标准的语法来,这样才能综合出来正确的逻辑电路,否则生成的电路会存在缺陷,从而影响系统的稳定性和可移植性。
