module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire [3:0] i_en;
// wire pm_temp;
//assign pm_temp = (hh == {4'd1, 4'd1} && mm == {4'd5,4'd9} && ss == {4'd5, 4'd9}) ? (~pm) : pm;
// assign pm = pm_temp;
assign i_en = {mm[7:4] == 8'd5 && mm[3:0] == 8'd9 && ss[7:4] == 8'd5 && ss[3:0] == 8'd9,//i_en[3]
mm[3:0] == 8'd9 && ss[7:4] == 8'd5 && ss[3:0] == 8'd9, //i_en[2]
ss[7:4] == 8'd5 && ss[3:0] == 8'd9, //i_en[1]
ss[3:0] == 8'd9}; //i_en[0]
bcd i0 (clk, reset, ena, 4'd0, 4'd9, ss[3:0]);
bcd i1 (clk, reset, i_en[0] & ena, 4'd0, 4'd5, ss[7:4]);
bcd i2 (clk, reset, i_en[1], 4'd0, 4'd9, mm[3:0]);
bcd i3 (clk, reset, i_en[2], 4'd0, 4'd5, mm[7:4]);
bcd_h1 i4 (clk, reset, i_en[3], hh[7:0]);
pm i5 (clk, reset, hh, mm, ss, pm);
endmodule
//可选择范围的计数器;start表示计数起点,end表示计数终点
module bcd(
input clk,
input reset,
input i_enable,
input [3:0] starting,
input [3:0] ending,
output [3:0] num);
always @(posedge clk)
begin
if(reset) begin
num <= starting;
end
else begin
if(i_enable) begin
if(num == ending) begin
num <= starting;
end
else begin
num <= num + 1'b1;
end
end
else begin
num <= num;
end
end
end
endmodule
//小时
module bcd_h1(
input clk,
input reset,
input i_enable,
output [7:0] num);
reg [3:0] hours;
always @(posedge clk)
begin
if(reset) begin
num = {4'd1,4'd2};
hours = 4'd12;
end
else begin
if(i_enable) begin //i_enable_h1 = 1:表示十位数为1
if(hours == 4'd12) begin
num = {4'd0,4'd1};
hours = 4'd1;
end
else begin
hours = hours + 1'b1;
num = num + 1'b1;
end
end
else begin
hours = hours;
num = num;
end
if(hours < 4'd10) begin
num = {4'd0, hours};
end
else begin
num = {4'd1, hours - 4'd10};
end
end
end
endmodule
module pm(
input clk,
input reset,
input [7:0] hh,
input [7:0] mm,
input [7:0] ss,
output pm);
always @(posedge clk)
begin
if(reset) begin
pm <= 'b0;
end
else begin
if(hh == {4'd1, 4'd1} && mm == {4'd5,4'd9} && ss == {4'd5, 4'd9}) begin
pm <= ~pm;
end
else begin
pm <= pm;
end
end
end
endmodule
题目描述
设计一个带有am/pm指示的12小时时钟。当reset时时钟指向12:00am。pm为0时表示AM,pm为1表示PM。hh, mm, ss都是用连个BCD码表示hh(1-12),mm(0-59),ss(0-59)。reset的优先级高于enable信号。
当时钟在11:59:59am时下一刻在12:00:00PM
遇见问题1
若代码中出现此下情况
assign pm = {hh == 8'd11 && mm == 8'd59 && ss == 8'd59} ? ~pm : pm;
调试过程中便会出现如下错误:调试过程超出了限制次数5000次,一般的这种错误会出现在组合逻辑电路中(回环)。在组合逻辑电路中对敏感变量进行赋值,而敏感变量一变化,组合逻辑块就会进行赋值,赋值又会让敏感变量变化,如此循环,并且组合电路动作几乎不花时间,这便成了一个死循环。
# ** Error (suppressible): (vsim-3601) Iteration limit 5000 reached at time 15 ps.
This usually means your code is broken and the simulator can't simulate it. It's often caused by having a combinational loop or a latch with race conditions that oscillates, causing the simulator to never settle to a fixed value at this particular point in the simulation. Combinational loops can occur if some combinational logic (including always@(*) blocks) consumes a signal that it modifies. It can sometimes be caused by thinking in C while writing Verilog. Look for Quartus Warning (10240 or 13012) or Info (10041) regarding inferred latches or unsafe latch behaviour.
解决:利用电平铭感描述组合的逻辑块
module pm(
input clk,
input reset,
input [7:0] hh,
input [7:0] mm,
input [7:0] ss,
output pm);
always @(posedge clk)
begin
if(reset) begin
pm <= 'b0;
end
else begin
if(hh == {4'd1, 4'd1} && mm == {4'd5,4'd9} && ss == {4'd5, 4'd9}) begin
pm <= ~pm;
end
else begin
pm <= pm;
end
end
end
endmodule
问题2
当我在小时hh的代码子模块中使用非阻塞赋值语句时出现了延迟现象
改图为延迟产生的时序仿真
该图未正确的仿真时序
阻塞:语句的“右式计算”和“左式更新”完全完成之后,才开始下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行;begin-end语句块中的各个赋值语句时同步执行的。
执行过程:1. 将非阻塞赋值放入调度队列中;
2. 仿真工具开始执行下一条语句而不等待当前语句执行完毕
(先计算等式右边结果,并保存在事件队列中,等到时间调度时,将其赋值给左边)
赋值类型的选择取决于建模的逻辑类型。一般的:
1. 时序逻辑电路中使用非阻塞赋值
非阻塞赋值在块结束后完成赋值操作,次赋值方式可以避免在仿真出现冒险与竞争
2. 组合逻辑电路中一般使用阻塞赋值
阻塞赋值方式可以使变量的值在赋值语句执行完之后立刻改变
3. assign语句中必须使用阻塞赋值语句