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

页: 1 [2] 3 4 5
查看完整版本: 把二进制变成BCD码需要几步?——漫谈大四加三算法的Verilog实现