1、inout用法浅析
FPGA不会像51单片机一样,自己分配inout的in和out功能。在指明同等驱动能力下,两个驱动源驱动的wire和tri型变量的真值表如下:
0 | 1 | X | Z | |
0 | 0 | X | X | 0 |
1 | X | 1 | X | 1 |
X | X | X | X | X |
Z | 0 | 1 | X | Z |
如果某时刻inout端口有输入,此时恰好要拿这个inout端口当做输出口时,那么冲突是在所难免的,其出现的结果参照上述真值表。一种典型的inout端口的使用方法是:
inout io_data;//inout 端口
reg out_data;//需要输出的端口
reg io_link;//inout端口方向
assign io_data=io_data?out_data:1'bz;
2、复位与亚稳态:(参考特权同学)
不管是同步复位还是异步复位都存在亚稳态的隐患。如下异步复位代码:
module reset_asyn(
input rst_n,
input clk,
input a,
output reg b,
output reg c
);
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
b<=1'b0;
else
b<=a;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
c<=1'b0;
else
c<=b;
end
endmodule
其RTL视图如下:
正常情况下,一旦进入复位,b、c都将清零。但是不能确定复位信号什么时候结束。如果结束于b_reg0 和 c_reg0 {latch edge-setup time, latch edge+hold time}之外,那么一切正常;但是不是,复位信号的撤销(由低电平变到高电平)出现在clk锁存数据的建立时间或者保持时间内,此时clk检测到rst_n的状态就是一个亚稳态(不确定是0还是1)。如果b_reg0 和 c_reg0 认为rst_n为1,那么跳出复位,执行相应的操作。
对于解决异步复位与同步复位的不靠谱,采用一种更为靠谱的异步复位、同步释放的双缓冲电路。该电路由同一时钟触发的层叠寄存器组成,该时钟必须和目标寄存器是同一时钟域。代码如下:
module reset_no_competition(
input clk,
input rst_n,
output reg rst_nr2
);
reg rst_nr1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rst_nr1<=1'b0;
else
rst_nr1<=1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rst_nr2<=1'b0;
else
rst_nr2<=rst_nr1;
end
endmodule
其RTL视图如下:
如此一来,既解决了同步复位的资源消耗问题,又解决了异步复位的亚稳态问题,根本思想,也是将rst_nr2是跳转时刻相对原来的处于亚稳态的rst_n向后延时了。
此时,完整的靠谱稳定复位信号的产生代码如下:
module reset_no_competition(
input clk,
input rst_n,
input a,
output reg b,
output reg c
);
reg rst_nr1;
reg rst_nr2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rst_nr1<=1'b0;
else
rst_nr1<=1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rst_nr2<=1'b0;
else
rst_nr2<=rst_nr1;
end
always@(posedge clk or negedge rst_nr2)
begin
if(!rst_nr2)
b<=1'b0;
else
b<=a;
end
always@(posedge clk or negedge rst_nr2)
begin
if(!rst_nr2)
c<=1'b0;
else
c<=b;
end
endmodule
其RTL视图如下:
更新中......