verilog - Verilog:条件分支
问题描述
我希望iState
(从底部开始的第二个条)在时钟的上升沿(最顶部的条)为 0,并且当它的当前值为 1110(假设iSkip
并且iRev
都是 0)或 1010(假设iSkip
是1 并且iRev
都是 0)。但是,它改为 1111。有谁知道为什么会发生这种情况以及我应该怎么做?谢谢。
module CounterSkipReverse(iClk, iRst, iSkip, iRev, oState);
input iClk, iRst, iSkip, iRev;
//declare oState:
output integer oState;
//declare internal wires and reg types here:
always @ (posedge iClk) begin
if (iRst == 1)
oState <= 0;
else
if (iSkip == 0 & iRev == 0) oState <= oState + 4'd1;
else if (iSkip == 1 & iRev == 0) oState <= oState + 4'd5;
else if (iSkip == 0 & iRev == 1) oState <= oState - 4'd1;
else if (iSkip == 1 & iRev == 1) oState <= oState + 4'd9;
if (oState < 0) oState <= oState + 4'd14;
if (oState > 14) oState <= oState - 4'd14;
end
endmodule
module StateToCountSequence(iState, oV);
//declare the input and output
input iState;
output reg [3:0]oV;
//declare any internal wire and reg types here.
always @ (iState) begin
case(iState)
4'd0: oV = 4'd3;
4'd1: oV = 4'd2;
4'd2: oV = 4'd4;
4'd3: oV = 4'd9;
4'd4: oV = 4'd9;
4'd5: oV = 4'd0;
4'd6: oV = 4'd7;
4'd7: oV = 4'd1;
4'd8: oV = 4'd1;
4'd9: oV = 4'd5;
4'd10: oV = 4'd1;
4'd11: oV = 4'd7;
4'd12: oV = 4'd0;
4'd13: oV = 4'd8;
4'd14: oV = 4'd9;
endcase
end
//Have you checked for inferred latches in this module?
endmodule
module CompleteCounter(iClk, iRst, iSkip, iRev, oV, oState);
input iClk, iRst, iSkip, iRev;
output [3:0] oV;
//declare oState next line
output [3:0]oState;
CounterSkipReverse cntr(.iClk(iClk), .iRst(iRst), .iSkip(iSkip), .iRev(iRev), .oState(oState));
StateToCountSequence statemap(.iState(oState), .oV(oV));
endmodule
`timescale 1ns / 1ps
module AssignmentTestBench;
//declare internal signals and instantiate module CompleteCounter.
reg iClk, iRst, iSkip, iRev;
wire [3:0]oState;
wire [3:0]oV;
initial begin
iClk = 1'b1;
iRst = 0;
iSkip = 0;
iRev = 0;
end
CompleteCounter counter(iClk, iRst, iSkip, iRev, oV, oState);
//generate test sequences for all state transitions
always begin
#5 iClk = ~iClk; //period 10 ns for clock
end
always begin // control w input and reset
#1;
// iSkip = 0, iRev = 0
#10 iRst = 1'b1;
#10 iRst = 1'b0;
#300; // 30 clock cycles
// iSkip = 1, iRev = 0
#10 iRst = 1'b1;
#10 iRst = 1'b0;
iSkip = 1'b1;
#80;
// iSkip = 1, iRev = 1
#10 iRst = 1'b1;
#10 iRst = 1'b0;
iRev = 1'b1;
#40;
// iSkip = 0, iRev = 1
#10 iRst = 1'b1;
#10 iRst = 1'b0;
iSkip = 1'b0;
#150;
$display("Finished test");
$finish; // remove for modelsim
$stop;
end
endmodule
解决方案
工作的方式是在块完成后将<=
值分配给oState 。因此,在接下来的oState计划为 15 时,if语句仍将其视为14
.
oState <= oState + 1;
...
if (oState > 14) ...
至少,您需要if(oState >= 14)
;
此外,在以下声明中
if (oState > 14) oState <= oState - 4'd14;
如果oState确实大于 14,即 15,则15 - 14 = 1
;
你可能需要
if (oState > 14) oState <= 0;
您还需要弄清楚表达式的另一面。问题是这if (oState <= 0)
会给你带来麻烦ostate <= 0
。您可能需要以下内容:if (iSkip == 0 && iRev == 1 && oState <= 0)
还有几个问题:
BT oState在CounterSkipReverseinteger
中,它是 32 位宽有符号的。另一方面,istate 是StateToCountSequence的输入。您需要使它们都具有相同的宽度。您的 case 语句不适用于 1 位 iState。one-bit wide
此外,不要&
在条件语句中使用singel。使用`&&。尽管在您的情况下并不重要,但在我上面提供的建议中确实很重要。
不使用always @(iState)
,使用always @*
。
推荐阅读
- sql - 如何比较 SQL Server 中的两个日期值?
- r - 编写一个函数来构建所有可能模型的列表,其中每个变量都有多种类型的回归
- mysql - 在创建具有多个输入的通配符 sql 代码时遇到问题
- c - attiny13 pwm led 完成开关
- laravel - how can i change lang of errors message using laravel6?
- asp.net-core - EF Core 3.1 属性值返回默认字段值
- firebase - Firebase signInWithEmailAndPassword 在 vue.js 中不起作用
- c# - 创建自动更新 Windows 服务
- c# - 将代理凭据注入所有 HttpClient 请求
- google-apps-script - 发送带有内嵌图像和正文的电子邮件