Verilog全称是Verilog HDL,HDL即硬件描述语言(hardware description language),换言之,Verilog的所有代码,与硬件电路的器件框图是等价的,本文以跑马灯为例,结合其verilog程序,来阅读其电路图。

代码示例

跑马灯的实现非常简单,只需对时钟进行计数,到达一定的数目后,对LED灯的亮暗进行移位即可。下面只考虑两个led灯,代码如下

module flow_led(
    input               sys_clk,
    input               sys_rst,

    output  reg  [1:0]  led
);

reg  [24:0]  cnt ;                  //计数器

//计数器计时0.5s
always @(posedge sys_clk or negedge sys_rst) begin
    if(!sys_rst)
        cnt <= 25'd0;
    else if(cnt < (25'd2500_0000 - 25'd1))
        cnt <= cnt + 25'd1;
    else
        cnt <= 25'd0;
end

//对LED灯进行移位控制,以输出2位LED的状态
always @(posedge sys_clk or negedge sys_rst) begin
    if(!sys_rst)
        led <= 2'b01;
    else if(cnt == (25'd2500_0000 - 25'd1))
        led <= {led[0],led[1]};
    else
        led <= led;
end

endmodule

其功能很简单,两段触发电路,一个是让计时器递增,增长到25’d2499_9999时归零;另一个是在计时器达到25’d2499_9999时,对led进行高低位调转。

电路图

上述代码对应的电路图如下

在这里插入图片描述

上图左右两侧共有三个信号,分别对应verilog代码中的输入输出,即sys_clk,sys_rst以及led。

电路图中共涉及到五种逻辑器件,分别是加法器、比较器、多路选择器、寄存器、ROM。由于所有器件的名字都以RTL开头,故下面介绍各器件时略去这个前缀。

【ADD】加法器。对应代码中cnt <= cnt + 25'd1,其输入有二,一个是常量I1,另一个【I0[24:0]】与cnt_reg相连接,此cnt_reg即表示代码中的cnt。

【LT】比较器,对应代码中的cnt < (25'd2500_0000 - 25'd1)。图中并未出现减法,说明常数减法在编译期就已经被替换为常数了,即下面的17D783F。

【MUX】多路选择器,其输入端有二,一个是从加法器输出的I0,另一个是常量I1,而决定其输出哪个的,则是来自于比较器的比较结果。该器件即可对应计数器计时代码中的两个赋值语句。

【ROM】是一个25位的只读寄存器,其输入为cnt,输出一个使能信号。

【REG_ASYNC】异步复位寄存器,引脚【C】表示时钟;【CE】为使能;【D】为数据输入;【Q】为输出;【CLR】即Clear,表示清除。

  • 【cnt_reg】一个25位的异步复位寄存器,用于存储计数值。sys_rst与【CLR】引脚相连,表示复位信号有效时,寄存器被清零。其输入端从多路选择器中引出,输出端递交给加法器核比较器。
  • 【led_reg】两位的异步复位寄存器,用于存储led的亮暗状态。这里需要注意的是,尽管图中将输出【Q】与输入【D】连接到了一起,但并没有体现出LED灯交替变化的状况。

led <= {led[0],led[1]}的功能是将led的低位与高位呼唤,如果将其变为led <= {led[1], led[0]},实际上就和led <= led没有区别了,此时代码的功能就是保持led的初始状态。

但是,如果将led设为三位,那么代码led <= {led[1], led[0], led[2]}和led <= {led[0], led[2], led[1]}在电路图中是看不出区别的。

修改

verilog代码中,需要比较cnt和2499_9999的大小进行判断,但两次比较时,一次用了等号,一次用了小于号,下面将其改为都用等号,则电路变为

在这里插入图片描述

代码如下

module flow_led(
    input               sys_clk,
    input               sys_rst,

    output  reg  [1:0]  led
);

reg  [24:0]  cnt ;                  //计数器

//计数器计时0.5s
always @(posedge sys_clk or negedge sys_rst) begin
    if(!sys_rst)
        cnt <= 25'd0;
    else 
        cnt <= cnt == 25'd2499_9999 ? cnt + 25'd1 : 25'd0;
end

//对LED灯进行移位控制,以输出2位LED的状态
always @(posedge sys_clk or negedge sys_rst) begin
    if(!sys_rst)
        led <= 2'b01;
    else
        led <= cnt == 25'd2499_9999 ? {led[0], led[1]} : led;    
end

endmodule
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐