LED开关的简单Verilog示例?

LED开关的简单Verilog示例?,verilog,hdl,Verilog,Hdl,我正在尝试为1热编码的简单LED开关按钮构建一个状态机 特别是我试图通过我的例子来理解阻塞和非阻塞赋值 你会认为下面的事情可以做得更好,还是在任何一个街区都是完全错误的 module example ( input clk, input rst, input push, output reg led_on ); reg on; reg off; reg t_on_off; reg t_off_on; always @* begin t_on_off = on &a

我正在尝试为1热编码的简单LED开关按钮构建一个状态机

特别是我试图通过我的例子来理解阻塞和非阻塞赋值

你会认为下面的事情可以做得更好,还是在任何一个街区都是完全错误的

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);


reg on;
reg off;

reg t_on_off;
reg t_off_on;


always @* begin
  t_on_off = on & (push);
end

always @* begin
  t_off_on = off & (push);
end


always @(posedge clk or posedge rst) begin
  if (rst)              on <= 1'b0;
  else if (t_off_on)    on <= 1'b1;
  else if (t_on_off)    on <= 1'b0;
end

always @(posedge clk or posedge rst) begin
  if (rst)              off <= 1'b1;
  else if (t_off_on)    off <= 1'b0;
  else if (t_on_off)    off <= 1'b1;
end


always @* begin
  led_on = on;
end


endmodule
?

特别是我想知道:我能把过渡的赋值合并成一个块吗,比如

是的,你可以完全按照你描述的那样做

如果需要,还可以组合顺序块:

always @(posedge clk or posedge rst) begin
  if (rst) begin
     on  <= 1'b0;
     off <= 1'b1;
  end else if (t_off_on) begin
     on  <= 1'b1;
     off <= 1'b0;
  end 
  (etc....)
end
始终@(posedge clk或posedge rst)开始
如果(rst)开始

在是时,可以将多个always块组合成一个块

您只需要将同步块(时钟块)和异步块分离为单独的always块


但是,一个好的样式是为每个单独的输出都有一个always块。这更易于阅读,更像真实世界,因为每个“始终”块彼此并发。

如果它不需要是一个热块,则将其简化为:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

always @(posedge clk or posedge rst) begin
  if (rst)        led_on  <= 1'b0;
  else if (push)  led_on  <= !led_on;
end

endmodule
模块示例(
输入时钟,
输入rst,
输入推送,
输出reg led_开启
);
始终@(posedge clk或posedge rst)开始

如果(rst)引导了重构建议:

output reg led_on;

always @* begin
  led_on = on;
end
致:

您也可以对
t\u on\u off
t\u off\u on

wire t_on_off;
wire t_off_on;

assign t_on_off = on  & (push);
assign t_off_on = off & (push);
或者,如果您更喜欢将declare和assign放在一行中

wire t_on_off = on  & (push);
wire t_off_on = off & (push);
但是,如果您将两个时钟始终块滚动到一个块中,则不需要单独的逻辑,将@Tim的答案与t_on_off检查相结合:

module example (
  input clk,
  input rst,
  input push,

  output reg led_on
);

reg on;
reg off;

assign  led_on = on;

always @(posedge clk or posedge rst) begin
  if (rst) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
  else if (off & push) begin
    on  <= 1'b1;
    off <= 1'b0;
  end
  else if (on  & push) begin
    on  <= 1'b0;
    off <= 1'b1;
  end
end

endmodule
模块示例(
输入时钟,
输入rst,
输入推送,
输出reg led_开启
);
注册;
登记关闭;
分配led_开=开;
始终@(posedge clk或posedge rst)开始
如果(rst)开始

在上,这已经是很久以前的事了,但给出的解决方案可能并不完全是您所期望的。从我可以推断出的解决方案都认为,LED将继续切换只要按钮被按下(即,它将切换时钟的频率),使它在视觉上察觉不到,如果时钟频率高。但是,我假设您希望在每次按下按钮时只切换一次LED,并在此期间保持LED状态

下面的示例根据3个按钮的活动切换3个LED的状态

  • 只要按下pbutton0,led0就会激活
  • led1定期保持切换(基于clk_div的大小),并在按下pbutton1时复位
  • 只要按下pbutton2,led2就会切换
  • 请注意,led0是组合的,而其他两个LED是顺序的。对于切换led2,必须存储pbutton2的先前状态;每当pbutton2(t-1)==0和pbutton2(t)==1时,这意味着按钮刚从低变高,因此led2的状态必须改变

    最后,请忽略时钟源,因为它仅用于演示Xilinx SP605开发工具包上的代码

    ////////////////////////////////////////////////////
    // This project uses 3 pushbuttons and 3 LEDs.
    //  pbutton0 activates led0
    //  pbutton1 serves as reset for led1 periodic toggling
    //  pbutton2 toggles led2
    //
    // The clock source (divider+buffer) was created using the clocking IP wizard.
    //
    
    module xilinx_sp605_board_leds
    (
        input CLK_IN1_P,
        input CLK_IN1_N,
    
        input pbutton0,
        input pbutton1,
        input pbutton2,
    
        output led0,
        output reg led1,
        output reg led2
    );
    
    // declarations
    wire clk;
    wire reset = pbutton1;
    reg [19:0] clk_div;
    reg pbutton2_reg;
    
    // led0 = state of pbutton0
    assign led0 = pbutton0;
    
    // differential clock divider+buffer
    clk_source CLK_SOURCE (
        .CLK_IN1_P(CLK_IN1_P),
        .CLK_IN1_N(CLK_IN1_N),
        .CLK_OUT1(clk),
        .RESET(reset));
    
    // led1, led2 toggling
    always @(posedge reset or posedge clk)
    begin
        if(reset)begin
            clk_div <= 0;
            led1 <= 0;
    
            pbutton2_reg <= 0;
            led2 <= 0;
        end else begin
            clk_div <= clk_div + 1;
            if(clk_div==0) 
                led1 <= ~led1;
    
            pbutton2_reg <= pbutton2;
            if(~pbutton2_reg && pbutton2)
                led2 <= ~led2;
        end
    end
    
    endmodule
    
    ////////////////////////////////////////////////////
    //此项目使用3个按钮和3个LED。
    //pbutton0激活led0
    //pbutton1用作led1定期切换的复位
    //pbutton2切换led2
    //
    //时钟源(除法器+缓冲区)是使用时钟IP向导创建的。
    //
    模块xilinx_sp605_板_LED
    (
    在1\u P中输入时钟,
    输入CLK_in 1_N,
    输入pbutton0,
    输入pbutton1,
    输入pbutton2,
    输出led0,
    输出寄存器led1,
    输出寄存器led2
    );
    //声明
    电线电缆;
    导线复位=pbutton1;
    注册[19:0]时钟分区;
    reg pbutton2_reg;
    //led0=pbutton0的状态
    分配led0=pbutton0;
    //差分时钟分频器+缓冲器
    时钟源时钟源(
    .CLK_IN1_P(CLK_IN1_P),
    .CLK_IN1_N(CLK_IN1_N),
    .CLK_OUT1(CLK),
    .重置(重置));
    //led1,led2切换
    始终@(posedge重置或posedge clk)
    开始
    如果(重置)开始
    九龙分区
    
    module example (
      input clk,
      input rst,
      input push,
    
      output reg led_on
    );
    
    reg on;
    reg off;
    
    assign  led_on = on;
    
    always @(posedge clk or posedge rst) begin
      if (rst) begin
        on  <= 1'b0;
        off <= 1'b1;
      end
      else if (off & push) begin
        on  <= 1'b1;
        off <= 1'b0;
      end
      else if (on  & push) begin
        on  <= 1'b0;
        off <= 1'b1;
      end
    end
    
    endmodule
    
    ////////////////////////////////////////////////////
    // This project uses 3 pushbuttons and 3 LEDs.
    //  pbutton0 activates led0
    //  pbutton1 serves as reset for led1 periodic toggling
    //  pbutton2 toggles led2
    //
    // The clock source (divider+buffer) was created using the clocking IP wizard.
    //
    
    module xilinx_sp605_board_leds
    (
        input CLK_IN1_P,
        input CLK_IN1_N,
    
        input pbutton0,
        input pbutton1,
        input pbutton2,
    
        output led0,
        output reg led1,
        output reg led2
    );
    
    // declarations
    wire clk;
    wire reset = pbutton1;
    reg [19:0] clk_div;
    reg pbutton2_reg;
    
    // led0 = state of pbutton0
    assign led0 = pbutton0;
    
    // differential clock divider+buffer
    clk_source CLK_SOURCE (
        .CLK_IN1_P(CLK_IN1_P),
        .CLK_IN1_N(CLK_IN1_N),
        .CLK_OUT1(clk),
        .RESET(reset));
    
    // led1, led2 toggling
    always @(posedge reset or posedge clk)
    begin
        if(reset)begin
            clk_div <= 0;
            led1 <= 0;
    
            pbutton2_reg <= 0;
            led2 <= 0;
        end else begin
            clk_div <= clk_div + 1;
            if(clk_div==0) 
                led1 <= ~led1;
    
            pbutton2_reg <= pbutton2;
            if(~pbutton2_reg && pbutton2)
                led2 <= ~led2;
        end
    end
    
    endmodule