3

我正在尝试为 1-hot-encoded 简单 LED 开关按钮构建 StateMachine。

特别是我试图用我的例子来理解阻塞和非阻塞分配。

您会认为以下可以做得更好,还是在任何区块中都是完全错误的?

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

?

4

5 回答 5

4

如果它不需要是 one-hot,则将其简化为:

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

它的功能等同于您所拥有的并且更具可读性。

于 2013-05-30T16:43:55.757 回答
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
于 2013-05-30T16:18:15.273 回答
1

是的,您可以将多个always块合并为一个。

您只需将同步(时钟)和异步块分离为单独的始终块。

然而,一个好的风格是为每个单独的输出设置一个always块。这更容易阅读和更真实的世界,因为每个always块彼此并发。

于 2013-05-30T16:18:25.093 回答
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_off和做同样的事情t_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);

但是,如果您将两个时钟始终块合并为一个,则不需要单独的逻辑,将@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
于 2013-05-31T07:26:24.473 回答
0

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

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

  1. 只要按下pbutton0,就会激活led0
  2. led1会定期切换(基于clk_div的大小),并在按下pbutton1时重置。
  3. 每当按下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
于 2015-11-06T07:16:43.907 回答