lcytms
发表于 2016-10-21 10:31:55
本帖最后由 lcytms 于 2016-10-21 10:33 编辑
仿真运行结果
设置好仿真之后,可以看到仿真结果。
此时将din的数据格式设置为无符号数Unsigned,将dout的数据格式设置为十六进制数Hexadecimal。
可以看到两种不同码制的数据保持了完全一致。
从一个方面验证了大四加三算法的正确性。
lcytms
发表于 2016-10-21 10:43:46
本帖最后由 lcytms 于 2016-10-21 10:48 编辑
用generate for语句改写shift移位子模块shift.v文件
我们注意到由于存在重复性操作,相同的语句往往写好多次。当然参数会稍微有所差异。
有个偷懒的办法,就是采用generate for语句。
用generate for语句改写的shift移位子模块shift.v文件如下所示:
module shift (datain, dataout);
input datain;
output dataout;
wire data;
assign data = datain;
// preshift p0 (.d4in(datain), .d4out(data));
// preshift p1 (.d4in(datain), .d4out(data));
// preshift p2 (.d4in(datain), .d4out(data));
// preshift p3 (.d4in(datain), .d4out(data));
// preshift p4 (.d4in(datain), .d4out(data));
// preshift p5 (.d4in(datain), .d4out(data));
genvar i;
generate for (i=0; i<24; i=i+4)
begin : g4i
preshift p (.d4in(datain), .d4out(data)); //对应第二步各小步下的a操作,此处为6个BCD位的大四加三操作。具体动作见preshift移位预操作子模块。
end
endgenerate
assign dataout = {data, 1'b0}; //对应第二步各小步下的b操作,此处为全序列的左移移位操作。
endmodule
lcytms
发表于 2016-10-21 10:53:32
本帖最后由 lcytms 于 2016-11-14 11:08 编辑
用generate for语句改写顶层模块b2bcd.v文件
同样的道理,我们对顶层模块b2bcd.v文件的重复性语句也进行了改写。
用generate for语句改写的顶层模块b2bcd.v文件如下所示:
module b2bcd (din, dout);
input din;
output dout;
wire data ;
assign data = {24'b0, din}; //第一步:准备阶段。将输入二进制数在高位补齐全0的BCD位,生成二进制全序列的初始状态。
genvar i;
generate for (i=0; i<20; i=i+1)
begin : g4i
shift s (.datain(data), .dataout(data)); //第二步:移位阶段。依次进行20个小步操作。具体动作在shift子模块中描述。
end
endgenerate
assign dout = data; //第三步:输出阶段。取出BCD部分,作为输出。
endmodule
lcytms
发表于 2016-10-21 11:10:15
本帖最后由 lcytms 于 2016-10-21 11:13 编辑
第二步的小步次数优化
前面表格中我们提到,第二步的最初3小步可以去除,因为最初3小步除了左移操作,在BCD位大四加三操作中并不发生变化。
因此可以在第一步直接将原初始状态左移三位,原第二步直接跳过前3小步执行即可。
优化结果体现在顶层模块b2bcd.v文件中,如下所示:
module b2bcd (din, dout);
input din;
output dout;
wire data ;
// assign data = {24'b0, din};
assign data = {21'b0, din, 3'b0}; //第一步:准备阶段。将输入二进制数在高位补齐全0的BCD位,直接左移三位,生成二进制全序列的初始状态。
genvar i;
// generate for (i=0; i<20; i=i+1)
generate for (i=3; i<20; i=i+1)
begin : g4i
shift s (.datain(data), .dataout(data)); //第二步:移位阶段。依次进行17个(20-3)小步操作。具体动作在shift子模块中描述。
end
endgenerate
assign dout = data; //第三步:输出阶段。取出BCD部分,作为输出。
endmodule
lcytms
发表于 2016-10-21 11:42:28
查看RTL视图——顶层模块b2bcd.v
顶层模块b2bcd.v的视图如下所示。
其中最下面为全局视图,上面为左边、右边的局部视图,可以看到17个子步shift移位模块逐次递进的一个结果。
lcytms
发表于 2016-10-21 11:46:25
本帖最后由 lcytms 于 2016-10-21 11:49 编辑
查看RTL视图——shift移位子模块shift.v
shift移位子模块shift.v的RTL视图如下。
lcytms
发表于 2016-10-21 11:49:28
查看RTL视图——preshift移位预操作子模块preshift.v
preshift移位预操作子模块preshift.v的RTL视图如下。
lcytms
发表于 2016-10-21 13:58:23
本帖最后由 lcytms 于 2016-11-14 22:47 编辑
加入数码管驱动模块seg7.v文件
为了更直观地看到数码管显示效果,在已经做好的工程文件中加入编写好的数码管驱动模块seg7.v文件。
数码管驱动模块seg7.v文件如下所示。
module seg7 (clk, rst_n, data, sel, seg);
input clk, rst_n;
input data;
output reg sel;
output reg seg;
reg count;
reg clk_1ms;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
clk_1ms <= 1;
end
else
begin
if (count < 24999)
begin
count <= count + 20'd1;
end
else
begin
count <= 0;
clk_1ms <= ~clk_1ms;
end
end
end
reg state;
reg data_temp;
always @ (posedge clk_1ms or negedge rst_n)
begin
if (!rst_n)
begin
sel <= 0;
data_temp <= 0;
state <= 0;
end
else
begin
case (state)
0 : begin
sel <= 0;
data_temp <= data;
state <= 1;
end
1 : begin
sel <= 1;
data_temp <= data;
state <= 2;
end
2 : begin
sel <= 2;
data_temp <= data;
state <= 3;
end
3 : begin
sel <= 3;
data_temp <= data;
state <= 4;
end
4 : begin
sel <= 4;
data_temp <= data;
state <= 5;
end
5 : begin
sel <= 5;
data_temp <= data;
state <= 0;
end
default : state <= 0;
endcase
end
end
always @ (*)
begin
if (!rst_n)
begin
seg = 8'b1111_1111;
end
else
begin
case (data_temp)
0 : seg = 8'b1100_0000; //d0
1 : seg = 8'b1111_1001; //d1
2 : seg = 8'b1010_0100; //d2
3 : seg = 8'b1011_0000; //d3
4 : seg = 8'b1001_1001; //d4
5 : seg = 8'b1001_0010; //d5
6 : seg = 8'b1000_0010; //d6
7 : seg = 8'b1111_1000; //d7
8 : seg = 8'b1000_0000; //d8
9 : seg = 8'b1001_0000; //d9
10 : seg = 8'b1000_1000; //dA
11 : seg = 8'b1000_0011; //db
12 : seg = 8'b1100_0110; //dC
13 : seg = 8'b1010_0001; //dd
14 : seg = 8'b1000_0110; //dE
15 : seg = 8'b1000_1110; //dF
default : seg = 8'b1000_1110; //dF
endcase
end
end
endmodule
lcytms
发表于 2016-10-21 14:48:25
本帖最后由 lcytms 于 2016-10-21 14:53 编辑
创建新的顶层模块top.v
创建新的顶层模块top.v,循环生成要显示的数字000000~999999,显示数字每100ms更新一次,通过b2bcd模块转换成BCD码,然后输出给数码管驱动模块。
新的顶层模块top.v文件如下所示。
module top (clk, rst_n, sel, seg);
input clk, rst_n;
output sel;
output seg;
reg count;
reg din;
wire dout;
parameter T100ms = 5_000_000;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count <= 0;
din <= 0;
end
else
begin
if (count < T100ms - 1) //显示数字每100ms更新一次
begin
count <= count + 1;
end
else
begin
count <= 0;
if (din < 999999) //循环生成要显示的数字000000~999999
begin
din <= din + 20'd1;
end
else
begin
din <= 0;
end
end
end
end
b2bcd b2bcd
(
.din(din),
.dout(dout)
);
seg7 seg7
(
.clk(clk),
.rst_n(rst_n),
.data(dout),
.sel(sel),
.seg(seg)
);
endmodule
lcytms
发表于 2016-10-21 15:02:12
参照.tcl文件设置好FPGA管脚
参照EP4CE10F17C8Nzx_1.tcl文件内容,对FPGA芯片管脚进行设置。
EP4CE10F17C8Nzx_1.tcl文件相关内容如下所示。FPGA芯片配置结果如图所示。
#set_global_assignment -name FAMILY "Cyclone IV"
#set_global_assignment -name DEVICE ep4ce10f17c8n
set_location_assignment PIN_E1 -to clk
# KEY 轻触按键
set_location_assignment PIN_L3 -to key
# SEG7 x 8 七段数码管
set_location_assignment PIN_L6 -to sel
set_location_assignment PIN_N6 -to sel
set_location_assignment PIN_M7 -to sel
set_location_assignment PIN_T11 -to seg
set_location_assignment PIN_T10 -to seg
set_location_assignment PIN_T9 -to seg
set_location_assignment PIN_T8 -to seg
set_location_assignment PIN_T7 -to seg
set_location_assignment PIN_T6 -to seg
set_location_assignment PIN_T5 -to seg
set_location_assignment PIN_T4 -to seg