1. 高速设计时可把输出直接指定为状态的某几位
parameter IDLE=5'b0_000_0, START=5'b1_001_1; assign K2=state[4]; assign K1=state[0]; //K1,K2为输出,直接与每个状态高位和地位对应起来(在state增加两位,作为输出码)
2. 把状态的变化和输出开关的控制分开写,采用多个always,分别控制一个输出信号
always @ (state or A) //state为状态,A为输入 case(state) // // endcase
3. 自动包含所有电平敏感列表
always @ (*)
4. 接收外部时钟和数据时采用组合逻辑,提高实时性。
assign data_out=(flag==1'b0)?data_in:2'b0; //数据接收
assign fifo_wrclk=(flag==1'b0)? ~clk_in:1'b0; //时钟接收作为FIFO时钟
assign fifo_wr=(flag==1'b0)? 1'b1:1'b0; //门控接收
5. 把状态的变化和输出开关的控制分开写,采用多个always,分别控制一个输出信号。
6. 模块之间工作的协调方式:采用请求应答机制
a) 请求举例:(满872字节发送请求信号)
assignre q1=(fifo_rcv1_rdusedw>=16'd436)?1'b1:1'b0;
…
…
b)应答举例
(1)3小节中的循查模块的Check_over,循查完之后给数据写入模块发送check_over标志;
(2)接收的数据写入FIFO完毕之后给后续模块发送data_ready标志。
always @(posedge clkor negedge rst)
if(!rst)
data_ready<=1'b0;
else case (state)
WAIT: data_ready<=1'b1;
default:data_ready<=1'b0;
endcase
(3)数据发送完毕之后给循查模块发送t_over标志表示可以继续响应其他的请求信号了;
7. 分析清楚是采用电平触发还是边沿触发。比如之前的应答机制采用边沿触发较好,如果采用电平触发可能造成时序的混乱。
关于边沿检测的方法:
(1)声明check_over_old;
always @ (posedge clkor negedge rst)
if(!rst)
check_over_old<=1'b0;
else
check_over_old<=check_over;
(2)检测 见3小节中。
8.对于相对复杂的逻辑,状态与信号控制分离,即采用多个always结构,分别控制状态和每一个输出信号,便于分析程序和修改维护。
9.关于FIFO使用注意事项总结:
(1) 读写时钟一直给,通过读写使能来控制。在读写时钟的下降沿给读写使能信号赋值。
---主要体现在:调试时,读写时钟停止后rdusedw和wrusedw不更新了,原因是先使能读或者写有效,然后才给时钟,然后读写使能无效后也停止给时钟了,导致FIFO里面的存有的字节数不能及时更新,对读写造成影响,造成满872字节这个条件无法判断。
(2) rdempty为低时,rdusedw才更新
(3) 在rdempty为高时,从FIFO里面读出来的前两个数总是一样的。
-----解决办法:
a) 在rdempty为低时再使用读出的数据,这样第一次读出来的数会因为rdempty为高而当做无效数据跳过。
b) 采用1中的方法读写时钟一直给,只控制读写使能,这样rdempty会在写数据的时候就被更新,变成低电平,这样读出来的数就可以直接用。
建议:采用以上两种方法合用,因为数据更新要延后一个时钟周期,在使用读取的数据时候判断下rdempty能够有效防止这样的问题。
(4) 关于rdusedw和wrusedw更新的延后的理解,可以看做是先在每个读写的时钟上升沿到来时,先更新rdusedw和wrusedw再读写数据。