Menu Close

Verilog实现16进制到10进制(BCD)转换(2)减法计数法

在 Verilog实现16进制到10进制(BCD)转换(1)加减计数法 文章中,介绍了如果使用一个基本的算法实现16进制数据到bcd 码的转换。通过实验,我们发现这个算法比较简单,但是计算时间很长。 尤其是当输入的数据比较大的情况下, 计算需要很多个时钟周期。 本文针对上述的算法的不足, 做了一些改进,可以在比较短的时间内,快速实现16进制到bcd码的转换。

代码实体:

module hex2bcd
(
    input rst,
    input clk,

    input cal_req,
    input [ 19: 0 ] indata,
    
    output reg[ 3: 0 ] out0_BCD,
    output reg[ 3: 0 ] out1_BCD,
    output reg[ 3: 0 ] out2_BCD,
    output reg[ 3: 0 ] out3_BCD,
    output reg[ 3: 0 ] out4_BCD,
    output reg[ 3: 0 ] out5_BCD,

    output reg cal_done

);

reg [ 19: 0 ] tmpa;
reg [ 19: 0 ] tmpa_r;

reg cal_req_r;
reg cal_got;
reg cal_update;

reg [ 3: 0 ] tmp0_BCD;
reg [ 3: 0 ] tmp1_BCD;
reg [ 3: 0 ] tmp2_BCD;
reg [ 3: 0 ] tmp3_BCD;
reg [ 3: 0 ] tmp4_BCD;
reg [ 3: 0 ] tmp5_BCD;

reg [ 1: 0 ] cal_st;

// data capture, assume indata and cal_req are synchronized with clk,
// otherwise synchronization should be done first

always@( posedge clk or posedge rst )
if ( rst )
begin
    tmpa <= 0;
    cal_req_r <= 1'b0;
end
else
begin
    if ( cal_req )
    begin
        tmpa <= indata;
        cal_req_r <= 1'b1;
    end
    else if ( cal_got )
        cal_req_r <= 0;
end

//====================

always@( posedge clk or posedge rst )
if ( rst )
begin
    tmp0_BCD <= 0;
    tmp1_BCD <= 0;
    tmp2_BCD <= 0;
    tmp3_BCD <= 0;
    tmp4_BCD <= 0;
    tmp5_BCD <= 0;
    tmpa_r <= 0;
    cal_got <= 0;
    cal_update <= 0;
    cal_st <= 0;
end
else
begin
    case ( cal_st )
    0:
    begin
        tmp0_BCD <= 0;
        tmp1_BCD <= 0;
        tmp2_BCD <= 0;
        tmp3_BCD <= 0;
        tmp4_BCD <= 0;
        tmp5_BCD <= 0;
        cal_got <= 0;
        cal_update <= 0;
        tmpa_r <= 0;

        if ( cal_req_r )
            cal_st <= 1;
    end
    1:
    begin
        cal_got <= 1'b1;
        tmpa_r <= tmpa;
        cal_st <= 2;
    end
    2:
    begin
        cal_got <= 0;
        if ( tmpa_r == 0 )
            cal_st <= 3;
        else
        begin
            if(tmpa_r >= 10_0000)
            begin
                tmpa_r <= tmpa_r - 10_0000;
                tmp5_BCD <= tmp5_BCD + 1;
            end
            else if(tmpa_r >= 1_0000)
            begin
                tmpa_r <= tmpa_r - 1_0000;
                tmp4_BCD <= tmp4_BCD + 1;
            end
            else if(tmpa_r >= 1000)
            begin
                tmpa_r <= tmpa_r - 1000;
                tmp3_BCD <= tmp3_BCD + 1;
            end
            else if(tmpa_r >= 100)
            begin
                tmpa_r <= tmpa_r - 100;
                tmp2_BCD <= tmp2_BCD + 1;
            end
            else if(tmpa_r >= 10)
            begin
                tmpa_r <= tmpa_r - 10;
                tmp1_BCD <= tmp1_BCD + 1;
            end
            else if(tmpa_r >= 1)
            begin
                tmpa_r <= tmpa_r - 1;
                tmp0_BCD <= tmp0_BCD + 1;
            end
        end
    end

    3:
    begin
        cal_update <= 1'b1;
        cal_st <= 0;
    end
    default:
        cal_st <= 3;
    endcase
end

//=====================update

always@( posedge clk or posedge rst )
if ( rst )
begin
    out0_BCD <= 0;
    out1_BCD <= 0;
    out2_BCD <= 0;
    out3_BCD <= 0;
    out4_BCD <= 0;
    out5_BCD <= 0;
    cal_done <= 1'b0;
end
else
begin
    cal_done <= 1'b0;

    if ( cal_update )
    begin
        out0_BCD <= tmp0_BCD;
        out1_BCD <= tmp1_BCD;
        out2_BCD <= tmp2_BCD;
        out3_BCD <= tmp3_BCD;
        out4_BCD <= tmp4_BCD;
        out5_BCD <= tmp5_BCD;
        cal_done <= 1'b1;
    end
end

endmodule

通过对输入的数据的大小,比较输入数据是否 >  10_0000,  1_0000,  1000, 100,  10 ,  1 等, 根据数据的大小,可以直接减去 10_0000,  1_0000,  1000, 100,  10, 1  而不必每次减一,这样就加快了算法的速度。

仿真文件如下:

`timescale 1ns / 1ps
module test_sim(
);

reg   rst = 1;
reg   clk = 0;

always #5 clk = ~clk;

reg   cal_req = 0;
reg   [ 19: 0 ] indata = 0;

wire [ 3: 0 ] out0_BCD;
wire [ 3: 0 ] out1_BCD;
wire [ 3: 0 ] out2_BCD;
wire [ 3: 0 ] out3_BCD;
wire [ 3: 0 ] out4_BCD;
wire [ 3: 0 ] out5_BCD;

wire cal_done;

initial
begin
    rst = 1;
    #10;
    
    rst = 0;
    #20;
    @(posedge clk);
    
    indata = 0;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    indata = 23;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    indata = 999;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    indata = 2323;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    indata = 54689;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    indata = 999999;
    cal_req = 1;
    @(posedge clk);
    cal_req = 0;
    while (!cal_done) @(posedge clk);
    
    #200;
    $stop;
    
end


hex2bcd    hex2bcd_inst
(
    .rst        (rst),
    .clk        (clk),

    .cal_req    (cal_req),
    .indata     (indata),
    
    .out0_BCD   (out0_BCD),
    .out1_BCD   (out1_BCD),
    .out2_BCD   (out2_BCD),
    .out3_BCD   (out3_BCD),
    .out4_BCD   (out4_BCD),
    .out5_BCD   (out5_BCD),

    .cal_done   (cal_done)

);

    
endmodule

 

仿真波形如下:

 

这个算法必之前的算法提高了很多,但是还是有些问题值得注意, 比如 999 的计算实践 大于 2323的计算时间 等。 所以,我们还有改进的空间。

 

Posted in FPGA, FPGA 教材教案, Verilog, Verilog, 教材与教案, 文章

发表回复

相关链接