我正在尝试为1热编码的简单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
答案 0 :(得分: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 :(得分: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
答案 2 :(得分:1)
是的,您可以将多个始终块合并为一个。
您只需将同步(异步)和异步块分离为单独的始终块。
然而,一个好的风格是为每个输出都有一个始终块。这更容易阅读,更真实,就像每个总是块彼此同时一样。
答案 3 :(得分: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
答案 4 :(得分:0)
这已经过去很久了,但所提出的解决方案可能并不完全符合您的预期。从我可以推断出的解决方案,所有人都认为只要按下按钮(即它将按时钟的频率切换),LED就会保持切换状态,如果时钟频率很高,则会在视觉上察觉不到。但是,我认为你会想要每次按下按钮时只切换LED一次,在此期间保持LED状态。
以下示例根据3个按钮的活动切换3个LED的状态。
请注意, 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