最近学了verilog语言,看到有位大佬设计的电子密码锁们就想自己试一试,但是照抄代码出现报错,自己尝试修复了一些小问题,但是还是有报错,自己实在搞不明白,所以来请教一下各位大佬,感谢。平台用的是wmware虚拟机支持win7的ISE。原博主链接:https://www.cnblogs.com/vv123/p/17436195.html#5333441
1.密码锁共有12个键, 0-9的数字键, 为取消键, #为确定键
2.开锁时,需要输入4位正确密码后,按#号键确定,密码锁可以打开,注意这里只要最后按#键前4位正确即可,密码门打开后30秒回到初始态。
3.如果连续3次输错密码,密码门自动死锁3分钟。
4.密码门有一个六位超级密码230419,输入后可以用户重置并且设置四位开锁密码, 用于设置新的开锁密码时,需要连续输入两次并按#确认,两次必须相同。否则设置失败。
5.无论是开锁还是设置密码可以按号来取消。
定义
`timescale 1ns / 1ps
module lock(
input wire clk,
input wire clr,
input wire [3:0] din, //数字键0-9,需要4bit
input wire confirm, //确定键'#'
input wire cancel, //取消键'*'
output reg unlock_ok, //成功开锁状态时,输出1
output reg reset_ok, //重设密码成功时,输出1
output reg locking //输错密码3次进入锁定状态时,输出1
);
//初始密码1234
reg [3:0] passwd0 = 1;
reg [3:0] passwd1 = 2;
reg [3:0] passwd2 = 3;
reg [3:0] passwd3 = 4;
//超级密码230419
reg [3:0] superwd0 = 2;
reg [3:0] superwd1 = 3;
reg [3:0] superwd2 = 0;
reg [3:0] superwd3 = 4;
reg [3:0] superwd4 = 1;
reg [3:0] superwd5 = 9;
//新密码
reg [3:0] newpasswd0 = 0, newpasswd1 = 0, newpasswd2 = 0, newpasswd3 = 0;
//开启状态保持时间
reg [5:0] open_time = 0;
//连续输错密码次数
reg [5:0] wrong_count = 0;
//锁定状态保持时间
reg [5:0] lock_time = 0;
//状态定义
reg[3:0] present_state_s, next_state_s;//当前状态,下一状态
parameter S0 = 3'b0, S1 = 3'b1, S2 = 3'b10, S3 = 3'b11;
parameter S4 = 3'b100; //等待键入确定键'#'
parameter Open = 3'b101; //开启状态
parameter Lock = 3'b110; //输错3次密码,锁定状态
//状态机S
always @(*) begin
case (present_state_s)
S0:
begin
if (din == passwd0) next_state_s <= S1;
else next_state_s <= S0;
if (confirm == 1)
begin
wrong_count <= wrong_count + 1;
if (wrong_count >= 3)
begin
next_state_s <= Lock;
end
else
next_state_s <= S0;
end
if (cancel == 1) next_state_s <= S0;
end
S1:
begin
if (din == passwd1) next_state_s <= S2;
else next_state_s <= S0;
if (confirm == 1)
begin
wrong_count <= wrong_count + 1;
if (wrong_count >= 3)
begin
next_state_s <= Lock;
end
else
next_state_s <= S0;
end
if (cancel == 1) next_state_s <= S0;
end
S2:
begin
if (din == passwd2) next_state_s <= S3;
else next_state_s <= S0;
if (confirm == 1)
begin
wrong_count <= wrong_count + 1;
if (wrong_count >= 3)
begin
next_state_s <= Lock;
end
else
next_state_s <= S0;
end
if (cancel == 1) next_state_s <= S0;
end
S3:
begin
if (din == passwd3) next_state_s <= S4;
else next_state_s <= S0;
if (confirm == 1)
begin
wrong_count <= wrong_count + 1;
if (wrong_count >= 3)
begin
next_state_s <= Lock;
end
else
next_state_s <= S0;
end
if (cancel == 1) next_state_s <= S0;
end
S4:
begin
if (confirm == 1) begin
next_state_s <= Open;
wrong_count <= 0;
end
else
next_state_s <= S0;
end
Open:
begin
if (open_time > 0)
next_state_s <= Open;
else
next_state_s <= S0;
end
Lock:
begin
if (lock_time > 0)
begin
next_state_s <= Lock;
end
else next_state_s <= S0;
end
endcase
end
//状态切换与输出
always @(posedge clk or posedge clr) begin
if (open_time > 0) begin
if (open_time == 1) unlock_ok <= 0;
open_time <= open_time - 1;
end
if (lock_time > 0) begin
if (lock_time == 1) begin
locking <= 0;
wrong_count <= 0;
end
lock_time <= lock_time - 1;
end
if (clr == 1) begin
present_state_s <= S0;
unlock_ok <= 0;
locking <= 0;
end
else
begin
if (present_state_s != Open && next_state_s == Open) begin
unlock_ok <= 1;
open_time <= 3;
end
if (present_state_s != Lock && next_state_s == Lock) begin
locking <= 1;
lock_time <= 3;
end
present_state_s <= next_state_s;
end
end
reg[5:0] present_state_t, next_state_t;
parameter T0 = 5'b0, T1 = 5'b1, T2 = 5'b10, T3 = 5'b11, T4 = 5'b100, T5 = 5'b101,
T6 = 5'b110, T7 = 5'b111, T8 = 5'b1000, T9 = 5'b1001, T10 = 5'b1010, T11 = 5'b1011,
T12 = 5'b1100, T13 = 5'b1101, T14 = 5'b1110, T15 = 5'b1111,
T16 = 5'b10000, T17 = 5'b10001, T18 = 5'b10010, T19 = 5'b10011,
T20 = 5'b10100, //等待键入确定键'#'
OK = 5'b10101;
always @(posedge clk or posedge clr) begin
if (clr == 1)
present_state_t <= T0;
else
present_state_t <= next_state_t;
end
//状态机T
always @(*) begin
case (present_state_t)
T0: if (din == superwd0) next_state_t <= T1;
else next_state_t <= T0;
T1: if (din == superwd1) next_state_t <= T2;
else next_state_t <= T0;
T2: if (din == superwd2) next_state_t <= T3;
else next_state_t <= T0;
T3: if (din == superwd3) next_state_t <= T4;
else next_state_t <= T0;
T4: if (din == superwd4) next_state_t <= T5;
else next_state_t <= T0;
T5: if (din == superwd5) next_state_t <= T6;
else next_state_t <= T0;
T6: if (din == superwd0) next_state_t <= T7;
else next_state_t <= T0;
T7: if (din == superwd1) next_state_t <= T8;
else next_state_t <= T0;
T8: if (din == superwd2) next_state_t <= T9;
else next_state_t <= T0;
T9: if (din == superwd3) next_state_t <= T10;
else next_state_t <= T0;
T10: if (din == superwd4) next_state_t <= T11;
else next_state_t <= T0;
T11: if (din == superwd5) next_state_t <= T12;
else next_state_t <= T0;
T12:
begin
newpasswd0 <= din; next_state_t <= T13;
end
T13:
begin
newpasswd1 <= din; next_state_t <= T14;
end
T14:
begin
newpasswd2 <= din; next_state_t <= T15;
end
T15:
begin
newpasswd3 <= din; next_state_t <= T16;
end
T16:
if (din == newpasswd0) next_state_t <= T17;
else next_state_t <= T0;
T17:
if (din == newpasswd1) next_state_t <= T18;
else next_state_t <= T0;
T18:
if (din == newpasswd2) next_state_t <= T19;
else next_state_t <= T0;
T19:
if (din == newpasswd3) next_state_t <= T20;
else next_state_t <= T0;
T20:
if (confirm == 1) begin
next_state_t <= OK;
end
else next_state_t <= T0;
OK:
begin
passwd0 <= newpasswd0;
passwd1 <= newpasswd1;
passwd2 <= newpasswd2;
passwd3 <= newpasswd3;
next_state_t <= T0;
wrong_count <= 0;//重设密码后,重新计算连续输错的次数
end
default: next_state_t <= T0;
endcase
if (cancel == 1) next_state_t <= T0;
end
always @(posedge clk or posedge clr) begin
if (clr == 1) reset_ok <= 0;
else
if (present_state_t == OK)
reset_ok <= 1;
else
reset_ok <= 0;
end
endmodule
报错的话是:ERROR:Xst:899 - "lock.v" line 172: The logic for <wrong_count> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
报错中的第172行是状态切换与输出部分的:wrong_count <= 0;也就是下面if判断中的这句。
if (lock_time > 0) begin
if (lock_time == 1) begin
locking <= 0;
wrong_count <= 0;
end
lock_time <= lock_time - 1;
end
在你的 Verilog 代码中,出现的错误信息表明 wrong_count
的赋值方式与预期的触发器(FF)或锁存器(Latch)模板不匹配。这通常是因为在组合逻辑中对寄存器(register)进行了赋值,而未在时钟边沿触发的块中进行处理。
在 Verilog 中,寄存器(如 wrong_count
)的赋值应该在时钟边沿触发的 always
块中进行,而不能在组合逻辑的 always @(*)
块中进行。这是因为组合逻辑块的赋值没有明确的时钟信号触发,可能导致综合工具无法确定寄存器的行为。
将 wrong_count
的赋值移动到时钟触发的 always
块中:
你需要确保所有对 wrong_count
的赋值都在时钟边沿触发的块中进行,而不是在组合逻辑块中。
修改状态机的逻辑:
在状态机中处理 wrong_count
的逻辑时,确保在时钟触发的 always
块中进行更新。
以下是修改后的代码片段,确保 wrong_count
的赋值在时钟触发的 always
块中进行:
//状态切换与输出
always @(posedge clk or posedge clr) begin
if (clr == 1) begin
present_state_s <= S0;
unlock_ok <= 0;
locking <= 0;
wrong_count <= 0; // 在清零时重置 wrong_count
end else begin
// 处理锁定状态逻辑
if (lock_time > 0) begin
if (lock_time == 1) begin
locking <= 0;
wrong_count <= 0; // 锁定结束后重置 wrong_count
end
lock_time <= lock_time - 1;
end
// 状态切换逻辑
if (present_state_s != Open && next_state_s == Open) begin
unlock_ok <= 1;
open_time <= 3; // 设定开启时间
end
if (present_state_s != Lock && next_state_s == Lock) begin
locking <= 1;
lock_time <= 3; // 设定锁定时间
end
present_state_s <= next_state_s; // 状态切换
end
end
// 状态机S
always @(*) begin
next_state_s = present_state_s; // 默认保持当前状态
case (present_state_s)
S0: begin
if (din == passwd0) begin
next_state_s <= S1;
end else if (confirm == 1) begin
wrong_count <= wrong_count + 1; // 在这里不应赋值
if (wrong_count >= 3) begin
next_state_s <= Lock;
end
end
if (cancel == 1) next_state_s <= S0;
end
// 其他状态的逻辑...
S4: begin
if (confirm == 1) begin
next_state_s <= Open;
wrong_count <= 0; // 在这里不应赋值
end else begin
next_state_s <= S0;
end
end
// 其他状态...
endcase
end
wrong_count
的更新移到时钟触发的 always
块中:在状态机的组合逻辑中不再直接对 wrong_count
进行赋值,而是在状态切换的时钟边沿更新中进行处理。wrong_count
:在清零条件下(clr
为 1)重置 wrong_count
。wrong_count
时,确保逻辑清晰,避免在组合逻辑中对寄存器进行赋值。通过以上修改,你的代码应该能够正常编译并运行。如果还有其他问题,请随时告诉我!