最近在学习fpga,用的是小脚丫的 Altera STEP-MAX10 V2.0 (10M08SAM153C8G) 板子,利用提供的STP MAX10实验指导书,实验18,秒表计时器,共3个模块:主模块Couter60、子模块1(分频模块,产生秒钟信号)、子模块2(两位数码管显示模块)。先上主模块代码:
问题部分代码:
/*
* 本模块输入、输出接口
*
*/
module Counter60
(
input wire clk,rst, //时钟和复位信号输入
input wire key, //启动暂停按键
output wire [8:0] segment_led1, segment_led2 //数码管输出
);
/*
*中间变量,只在程序内部使用;
*/
wire clk1h; //1秒时钟
reg [7:0] cnt ; //计时计数器
reg flag; //暂停启动标志
initial begin
cnt <= 8'h33;
flag <= 1'b1; //启动时就可以是计数;
end
//调用另外一个模块:分频器;例化1个分频器,产生秒钟信号
divideFreq # //例化分频器产生1秒时钟信号
(
.WIDTH(24),
.N(12_000_000)
)u1
(
.clk(clk),
.rst_n(rst),
.clkout(clk1h)
);
// rst, key 平常为高
always @(posedge clk) begin //产生标志信号
if(!rst)
flag <= 1'b0; //复位
else
if(!key) // 保持或者继续计数
flag = ~flag; //键盘按下,翻转
else
flag = flag; //键盘不按,保持
end
always @(posedge clk1h)
begin //产生60进制计数器
if(!rst)
cnt <= 8'h00; //复位初值显示00
else
begin
if(flag) //标志位为1,计数
begin //完成60秒的计数
if(cnt[3:0] == 4'd9) //个位满九?
begin
cnt[3:0] <= 4'd0; //个位清零
if(cnt[7:4] == 4'd5) //十位满5
cnt[7:4] <= 4'd0; //十位清零
else
cnt[7:4] <= cnt[7:4] + 1'b1; //十位加一
end
else cnt[3:0] <= cnt[3:0] + 1'b1; //个位加一
end
else //标志位为0,保持
cnt <= cnt;
end
end
Segment u2
(
.seg_data_1(cnt[7:4]),
.seg_data_2(cnt[3:0]),
.segment_led_1(segment_led1),
.segment_led_2(segment_led2)
);
endmodule
分配管脚,编译,下载测试,当按复位键(rst)时,数码管式中处于保持状态,不能按照程序写的复位清零。
主模块的逻辑想不出问题,fpga 初级阶段的我认为:这个是不是很难通过仿真发现内部问题在哪里啊???内部某处逻辑的问题,导致执行结果(输出)是不对的,但是内部逻辑问题出在哪里,怎么找?不像单片机,我可以单步走走去发现!!!知道如何仿真发现内部逻辑问题的可以教教我。
只能根据经验判断问题出在rst处逻辑出问题了,突然想到,是不是rst与子模块1(分频模块,产生秒钟信号)共用,是不是按键复位,搞乱了很重要的秒钟信号,从而使得此处逻辑不对?
always @(posedge clk1h)
begin //产生60进制计数器
if(!rst)
cnt <= 8'h00; //复位初值显示00
else .....
于是想法验证,不共用复位逻辑:复位控制的rst,与子模块1(分频模块,产生秒钟信号)复位的控制分开,不共用进行测试:rst只管主模块的复位,clear_divideFreq管子模块1的复位:
想法验证代码:
/*
* 本模块输入、输出接口
*
*/
module Counter60
(
input wire clk,rst, clear_divideFreq, //时钟和复位信号输入
input wire key, //启动暂停按键
output wire [8:0] segment_led1, segment_led2 //数码管输出
);
/*
*中间变量,只在程序内部使用;
*/
wire clk1h; //1秒时钟
reg [7:0] cnt ; //计时计数器
reg flag; //暂停启动标志
initial begin
cnt <= 8'h33;
flag <= 1'b1; //启动时就可以是计数;
end
//调用另外一个模块:分频器;例化1个分频器,产生秒钟信号
divideFreq # //例化分频器产生1秒时钟信号
(
.WIDTH(24),
.N(12_000_000)
)u1
(
.clk(clk),
.rst_n(clear_divideFreq),
.clkout(clk1h)
);
// rst, key 平常为高
always @(posedge clk) begin //产生标志信号
if(!rst)
flag <= 1'b0; //复位
else
if(!key) // 保持或者继续计数
flag = ~flag; //键盘按下,翻转
else
flag = flag; //键盘不按,保持
end
always @(posedge clk1h)
begin //产生60进制计数器
if(!rst)
cnt <= 8'h00; //复位初值显示00
else
begin
if(flag) //标志位为1,计数
begin //完成60秒的计数
if(cnt[3:0] == 4'd9) //个位满九?
begin
cnt[3:0] <= 4'd0; //个位清零
if(cnt[7:4] == 4'd5) //十位满5
cnt[7:4] <= 4'd0; //十位清零
else
cnt[7:4] <= cnt[7:4] + 1'b1; //十位加一
end
else cnt[3:0] <= cnt[3:0] + 1'b1; //个位加一
end
else //标志位为0,保持
cnt <= cnt;
end
end
Segment u2
(
.seg_data_1(cnt[7:4]),
.seg_data_2(cnt[3:0]),
.segment_led_1(segment_led1),
.segment_led_2(segment_led2)
);
endmodule
完美的结果出现,bug排除。
疑问:
fpga如何像单片机一样,能够单步执行,知道每一步的结果,方便排除逻辑bug?