EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
无处不在的Always 9 b* z5 b! m& ~: \; ^
今天在论坛上看到了ltbytyn 网友的一个程序时,忽然想起always语句是HDL语言的特色,C里面没有,如果硬说有的话应该是while(1)之类无限循环吧:)。二者的中文含义是“永远”或者“直到….”。 那段语句是下面这样的:
% m Y d5 V1 Q. V 我不详细解释逻辑的功能了,只想针对always@说2句,always的含义是“总是”,@的含义是“当”,()里面就是传说中的“敏感变量列表”了。之所以叫敏感变量列表是因为下面要写的语句中发生的变化都是由“敏感变量”门引起的。如果再“敏感变量”们前面加上posedge 或者 negedge 就表示为上升沿或者下降沿。下面说几个常用的例子,错误的就不一一解释了。 第一种情况:always@(posedge clk or negedge rst) begin if(!rst) a = 0; else a = a + 1; end 上述语句的解释就是: 1、“总是”在“敏感变量clk”的上沿到来时,a = a + 1; 2、“总是”在“敏感变量rst”的下沿到来时,a = 0; 请注意,这两者之间的关系是or,也就是单独运作的,但是rst的优先级较高;所以二者同时到来时rst起了作用。也就是俗称“异步复位”。 事实上这里只是这样理解而已,因为在FPGA内部这个结构对应到触发器上的时钟和复位两个端子。因此优先是触发器结构所决定的而不是语言决定的。 第二种情况:always@(posedge clk) begin if(!rst) a = 0; else a = a + 1; end 这也很好理解,rst不在变量列表中出现,因此rst“受制于”敏感变量clk,所以这里复位是同步的,也就是rst要在时钟上沿到来时起效。 第三种情况:always@(clk or rst) begin if(!rst) a = 0; else a = a + 1; end 请注意此处没有posedge,因此没有时钟了,实际上这段语句已经是一段组合逻辑了。 推荐新手们记住这三种情况,多运用前两种,少用第三种写法。 新手常犯的错之一:值得注意的是,always的写法是语法和综合器们约定俗成的,如果我写成了下面这样: always@(posedge rst or negedge clk) begin if(!clk) a = 0; else a = a + 1; end 那么综合器绝不会认为clk还是时钟,这段语句里rst变成了时钟。 因为综合器是认钱不认人的,只会根据行为判断变量的作用不会识别变量名,注意到了吗?时钟总是润物细无声的,执行语句当中只有她们是从不现身的。一个真的时钟总是低调而无处不在的。而复位信号rst没有这般高端大气,他们出现在if语句的判断中。所以这就是判断时钟和复位的依据而不管他们叫张三还是李四。 新手常犯的错之二:上升沿和下降沿一定要和if语句中条件相匹配: always@(posedge clk or negedge rst) begin if(rst) a = 0; else a = a + 1; end 上述是错误的语句,注意必须是negedge 对应 if(!rst),posedge对应 if(rst)。 最后新手应注意:真的时钟是不能赋值给线网或寄存器的。由于FPGA里时钟属于单独的时钟树,CLK是无法直接赋值给一个寄存器变量的,因为他们只能从时钟树分配到寄存器的CLK端。因为时钟树总是和寄存器的clk端相连,他们和触发器的D端实际是不连接的,需要通过特殊处理,开始时你注意这点别犯错误就行。 特殊情况下你可以把他们从时钟树上请下来再请上去,这是影响性能的行为之一。不详细展开解释了,新手注意不犯错就行,老手自行飘过。 # d% {' ~1 p$ f# a5 z4 E
|