我一般都是fpgas的新手。我想在每次SCK看到上升沿时进行迭代。我的代码问题是,它似乎算了两次。每次有一个上升沿过渡时,两个LED点亮 - 而不是只有一个LED。知道这可能来自何处?
module spi_slave(pcEn, LED, clk, SCK);
input clk, SCK;
output reg pcEn;
output reg [7:0] LED = 8'h00;
reg r1 = 0;
reg r2 = 0;
reg r3 = 0;
reg [3:0] cnt = 4'b0000;
always @(posedge clk)
begin
r1 <= SCK;
r2 <= r1;
pcEn <= r1 && !r3;
if (pcEn == 1) begin
cnt = cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] = 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] = 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] = 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] = 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] = 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] = 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] = 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] = 1'b1;
end
else
LED = 8'h00;
end
else
#100;
r3 <= r2;
end
endmodule
答案 0 :(得分:1)
计数器正在计数两次,因为您正在比较r1 & !r3
。
r1-> r2-> r3。在r1等于1之后,r3需要2个时钟。这意味着r1&!r3
条件将在2个时钟内保持有效。 pcEn将生成2个时钟,因此计数器将计数两次。
r1 && !r2
或者如果您想延迟r2 && !r3
应该可以正常工作。
您应该能够在波形中看到此行为进行调试。在模拟中使用$dumpvars;
来查看波形。
还有一些改进来改进代码。
不需要#100延迟。
module spi_slave(pcEn, LED, clk, SCK,rst_n);
input clk, SCK,rst_n;
output reg pcEn;
output reg [7:0] LED ;
reg r1 ;
reg r2 ;
reg r3 ;
reg [3:0] cnt ;
always @(posedge clk or negedge rst_n)
begin
if ( rst_n == 0 )
begin
r1 <=0 ;
r2 <= 0 ;
r3 <= 0 ;
cnt <= 0 ;
LED <=0 ;
pcEn <=0 ;
end
else
begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
if (pcEn == 1) begin
cnt <= cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] <= 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] <= 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] <= 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] <= 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] <= 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] <= 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] <= 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] <= 1'b1;
end
else
LED <= 8'h00;
end
end
end
endmodule
答案 1 :(得分:1)
#
延迟中的第一个不可合成,它们只是模拟的延迟。
通常,将块和非阻塞逻辑分成不同的始终块通常被认为是最佳实践。 always @*
用于组合(阻止分配),always @(posedge clk)
用于顺序(非阻塞分配)。仅供参考:Verilog支持案例陈述,这使得编码值比较容易,然后嵌套else-if。
我想你可能想要使用r2 && !r3
代替r1 && !r3
,因为Rahul也指出了
always @* begin
if (pcEn == 1'b0) begin
next_cnt = cnt;
next_LED = LED;
else begin
next_cnt = cnt + 4'b0001;
next_LED = 8'h00; // Rest all to 0s
if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles
case(cnt)
4'b0000 : next_LED[0] = 1'b1;
4'b0001 : next_LED[1] = 1'b1;
// ...
4'b0111 : next_LED[7] = 1'b1;
endcase
end
end
always @(posedge clk) begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
cnt <= next_cnt;
LED <= next_LED;
end