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
页: 1 [2] 3 4 5
查看完整版本: FPGA初级课程第十二讲 二进制转BCD