lcytms
发表于 2016-11-14 17:05:11
加上数据控制模块data_controller和数码管模块seg7后,架构图如下。
其中,数据控制模块data_controller循环输出0~999999(对应十六进制的0~F423F),b2bcd模块将其转化为BCD数据000000~999999,提交给数码管模块seg7进行显示。
lcytms
发表于 2016-11-14 17:07:11
建模主体框架
首先建立工程文件夹b2bcd,编写顶层模块b2bcd.v文件。
module b2bcd (din, dout);
input din;
output dout;
wire data ;
assign data = {24'b0, din}; //第一步:准备阶段。将输入二进制数在高位补齐全0的BCD位,生成二进制全序列的初始状态。
shift s01 (.datain(data), .dataout(data)); //第二步:移位阶段。依次进行20个小步操作。具体动作在shift子模块中描述。
shift s02 (.datain(data), .dataout(data));
shift s03 (.datain(data), .dataout(data));
shift s04 (.datain(data), .dataout(data));
shift s05 (.datain(data), .dataout(data));
shift s06 (.datain(data), .dataout(data));
shift s07 (.datain(data), .dataout(data));
shift s08 (.datain(data), .dataout(data));
shift s09 (.datain(data), .dataout(data));
shift s10 (.datain(data), .dataout(data));
shift s11 (.datain(data), .dataout(data));
shift s12 (.datain(data), .dataout(data));
shift s13 (.datain(data), .dataout(data));
shift s14 (.datain(data), .dataout(data));
shift s15 (.datain(data), .dataout(data));
shift s16 (.datain(data), .dataout(data));
shift s17 (.datain(data), .dataout(data));
shift s18 (.datain(data), .dataout(data));
shift s19 (.datain(data), .dataout(data));
shift s20 (.datain(data), .dataout(data));
assign dout = data; //第三步:输出阶段。取出BCD部分,作为输出。
endmodule
lcytms
发表于 2016-11-14 17:08:21
本帖最后由 lcytms 于 2016-11-14 22:13 编辑
建模shift移位子模块
shift移位子模块shift.v文件如下:
module shift (datain, dataout);
input datain;
output dataout;
wire data;
assign data = datain;
pre_shift p0 (.d4in(datain), .d4out(data)); //对应第二步各小步下的a操作,此处为6个BCD位的大四加三操作。具体动作见pre_shift移位预操作子模块。
pre_shift p1 (.d4in(datain), .d4out(data));
pre_shift p2 (.d4in(datain), .d4out(data));
pre_shift p3 (.d4in(datain), .d4out(data));
pre_shift p4 (.d4in(datain), .d4out(data));
pre_shift p5 (.d4in(datain), .d4out(data));
assign dataout = {data, 1'b0}; //对应第二步各小步下的b操作,此处为全序列的左移移位操作。
endmodule
lcytms
发表于 2016-11-14 22:23:06
建模pre_shift预移位操作子模块
pre_shift预移位操作子模块pre_shift.v文件如下:
module pre_shift (d4in, d4out);
input d4in;
output reg d4out;
always @ (*)
begin
if (d4in > 4)
begin
d4out = d4in + 3; //如果大于四,则加三
end
else
begin
d4out = d4in; //如果不大于四,则不变
end
end
endmodule
lcytms
发表于 2016-11-14 22:29:30
本帖最后由 lcytms 于 2016-11-14 22:30 编辑
pre_shift预移位操作子模块,也可以这样写
module pre_shift (d4in, d4out);
input d4in;
output d4out;
assign d4out = (d4in > 4) ? d4in + 4'd3 : d4in; //如果大于四,则加三,否则不变。
// always @ (*)
// begin
// if (d4in > 4)
// begin
// d4out = d4in + 3;
// end
// else
// begin
// d4out = d4in;
// end
// end
endmodule
lcytms
发表于 2016-11-14 22:32:05
编写Testbench模块
Testbench模块b2bcd_tb.v文件如下:
`timescale 1ns/1ps
module b2bcd_tb;
reg din;
wire dout;
integer i;
b2bcd dut (.din(din), .dout(dout));
initial
begin
din = 0;
for (i=0; i<=999999; i=i+1) #10 din = i; //六位数码管循环显示000000~999999
#100 $stop;
end
endmodule
lcytms
发表于 2016-11-14 22:33:06
仿真运行结果
设置好仿真之后,可以看到仿真结果。
此时将din的数据格式设置为无符号数Unsigned,将dout的数据格式设置为十六进制数Hexadecimal。
可以看到两种不同码制的数据保持了完全一致。
从一个方面验证了大四加三算法的正确性。
lcytms
发表于 2016-11-14 22:36:12
用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;
// pre_shift p0 (.d4in(datain), .d4out(data));
// pre_shift p1 (.d4in(datain), .d4out(data));
// pre_shift p2 (.d4in(datain), .d4out(data));
// pre_shift p3 (.d4in(datain), .d4out(data));
// pre_shift p4 (.d4in(datain), .d4out(data));
// pre_shift p5 (.d4in(datain), .d4out(data));
genvar i;
generate for (i=0; i<24; i=i+4)
begin : g4i
pre_shift p (.d4in(datain), .d4out(data)); //对应第二步各小步下的a操作,此处为6个BCD位的大四加三操作。具体动作见preshift移位预操作子模块。
end
endgenerate
assign dataout = {data, 1'b0}; //对应第二步各小步下的b操作,此处为全序列的左移移位操作。
endmodule
lcytms
发表于 2016-11-14 22:37:13
用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-11-14 22:38:53
第二步的小步次数优化
前面表格中我们提到,第二步的最初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