2013-05-30 56 views
2

我正在尝试为1热编码的简单LED开关按钮构建一个StateMachine。LED开关的简单Verilog示例?

特别是我试图了解阻塞和nonblocking作业与我的例子。

你会不会做得更好,或者在任何区块都完全错误?

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 @* begin 
    t_on_off = on & (push); 
    t_off_on = off & (push); 
end 

回答

3

如果它并不需要成为一个热点,然后将其简化为:

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 

它是功能上等同于你所拥有的,更具可读性。

1

特别是我想知道:我可以结合过渡的分配到一个单独的块,像...

是的,你可以做到这一点完全按照你描述。

您还可以结合顺序块,以及如果你想:

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 
1

是的,你可以在多个总是块合二为一。

你只需要将你的同步(clocked的)和异步块分离成单独的总是块。

但是,一个好的风格是每个单独的输出都有一个总是块。这是更容易阅读和更现实世界,就像每个总是块是彼此并行。

1

重构建议:

output reg led_on; 

always @* begin 
    led_on = on; 
end 

到:

output led_on; //wire by default (not declared reg) 

assign led_on = on; 

你也可以用做同样的t_on_offt_off_on

wire t_on_off; 
wire t_off_on; 

assign t_on_off = on & (push); 
assign t_off_on = off & (push); 

或者如果你喜欢滚动申报与分配在一行中。

wire t_on_off = on & (push); 
wire t_off_on = off & (push); 

但如果你是滚动两个时钟总是块到一个没有必要分开的逻辑,结合@添的回答与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 
0

这已经远远的已经过去了,但提出的解决方案可能并不完全符合您的期望。从我所能推断出的解决方案中,所有人都认为,只要按下按钮,LED就会保持切换(即它将按照时钟频率切换),如果时钟频率很高,就会使其在视觉上难以察觉。但是,我认为每次按下按钮时都需要一次切换LED的功能,并在此期间保持LED状态。

下面的示例根据3个按钮的活动切换3个LED的状态。无论何时按下pbutton0

  1. LED0被激活。
  2. LED1保持周期性地切换(基于CLK_DIV的尺寸),并且是每当pbutton1按下复位。
  3. led2无论何时pbutton2被按下。

请注意,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