FC2カウンター FPGAの部屋 2進数からBCDへの変換回路(まとめ)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

2進数からBCDへの変換回路(まとめ)

2進数からBCDへの変換回路1”の続き。この前、お恥ずかしい自分の回路を公開してから、いろんなかたに変換回路を紹介していただいた。やはり、アルゴリズムが大事だな、ということを実感した。

すべての回路のFPGAはSpartan-3E-500(xc3s5000e-4pq208)を使用して、ISE12.3でインプリメントし、使用ロジックを調べた。(動作周波数は調べていない)それから、ISimでシミュレーションしてみた。

・武内さんの回路
まずは、武内さんの回路からやってみることにした。2進数10ビット、BCD4桁の設定でのインプリメント結果を下に示す。
Takeuchi_1_101030.png

Number of Slice Flip Flopsが42、Number of 4 input LUTsが83、Number of occupied Slicesが49だった。
次に、付属のテストベンチでシミュレーションしてみた。
Takeuchi_2_101030.png

レイテンシは、25クロックだった。

・Sさんの回路
次にコメントで教えていただいたSさんの回路を検証してみる。2進数10ビット、BCD3桁だ。
下にVerilogコードを表示させていただきます。

module bin2bcd (clk, bin, bcd); 
    input clk; 
    input [ 9:0] bin; 
    output [15:0] bcd; 

    wire [13:0] k3; 
    reg [13:0] k3b; 
    reg [ 3:0] d32; 
    reg [ 3:0] d31; 
    reg [ 3:0] d30; 
    wire [13:0] k2; 
    reg [13:0] k2b; 
    reg [ 3:0] d21; 
    reg [ 3:0] d20; 
    wire [13:0] k1; 
    reg [ 3:0] d10; 
    reg [ 3:0] d00; 

    assign k3 = bin + bin[9:6] + bin[9:7] + bin[9] + 1'b1; 
    always @(posedge clk) d32 <= k3[13:10]; 
    always @(posedge clk) k3b <= bin - (k3[13:10] * 1000); 

    assign k2 = k3b * 10 + k3b[13:2]; 
    always @(posedge clk) d21 <= k2[13:10]; 
    always @(posedge clk) k2b <= k3b - (k2[13:10] * 100); 
    always @(posedge clk) d31 <= d32; 

    assign k1 = k2b * 102 + k2b[13:1]; 
    always @(posedge clk) d00 <= k2b - (k1[13:10] * 10); 
    always @(posedge clk) d10 <= k1[13:10]; 
    always @(posedge clk) d20 <= d21; 
    always @(posedge clk) d30 <= d31; 

    assign bcd = {d30,d20,d10,d00}; 
endmodule 


2進数10ビット、BCD3桁でのインプリメント結果を下に示す。
S_1_101030.png

Number of Slice Flip Flopsが41、Number of 4 input LUTsが73、Number of occupied Slicesが51だった。
自分でテストベンチを書いてシミュレーションしてみた。下にテストベンチを示す。

`timescale 1ns / 1ps

module bin2bcd_tb;

    // Inputs
    reg clk;
    reg [9:0] bin;

    // Outputs
    wire [15:0] bcd;
    
    parameter CLK_PERIOD = 10;
    integer i, j;

    // Instantiate the Unit Under Test (UUT)
    bin2bcd uut (
        .clk(clk), 
        .bin(bin), 
        .bcd(bcd)
    );

    always begin // clk
       #(CLK_PERIOD/2)    clk = 1'b1 ;
       #(CLK_PERIOD/2)    clk = 1'b0 ;
    end

    initial begin
        // Initialize Inputs
        bin = 0;

        // Add stimulus here
        for (i=0; i<=1000; i=i+1) begin
            @(posedge clk);
            #1;
            bin = i;
            for (j=0; j<=3; j=j+1) begin
                @(posedge clk);
                #1;
            end
        end
        #50;
        $stop;
    end
      
endmodule


ISimでのシミュレーション画面を下に示す。
S_2_101030.png

レイテンシは3クロックだった。

・ame_feb4さんに教えていただいた回路
次にツイッターでame_feb4さんに教えていただいたConverionsのページだ。
2進数10ビット、BCD3桁のbin2bcd.vhdを作成した。下に示す。

-- bin2bcd.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity bin2bcd is
    port(
        clk : in std_logic;
        reset : in std_logic;
        din : in std_logic_vector(9 downto 0);
        load : in std_logic;
        bcd_out : out std_logic_vector(11 downto 0);
        done : out std_logic
    );
end bin2bcd;

architecture RTL of bin2bcd is
component BcdDigit
    Port ( Clk :    in  STD_LOGIC;
           Init :   in  STD_LOGIC;
           DoneIn:  in  STD_LOGIC;
           ModIn :  in  STD_LOGIC;
           ModOut : out  STD_LOGIC;
           Q :      out  STD_LOGIC_VECTOR (3 downto 0));
end component;
signal shift_reg : std_logic_vector(9 downto 0);
signal count : std_logic_vector(3 downto 0);
signal done_node : std_logic;
signal modout0, modout1 : std_logic;
begin
    -- 3つのBcdDigit をインスタンス
    BcdDigit0 : BcdDigit port map(
        Clk => clk,
        Init => reset,
        DoneIn => done_node,
        ModIn => shift_reg(9),
        ModOut => modout0,
        Q => bcd_out(3 downto 0)
    );
    BcdDigit1 : BcdDigit port map(
        Clk => clk,
        Init => reset,
        DoneIn => done_node,
        ModIn => modout0,
        ModOut => modout1,
        Q => bcd_out(7 downto 4)
    );
    BcdDigit2 : BcdDigit port map(
        Clk => clk,
        Init => reset,
        DoneIn => done_node,
        ModIn => modout1,
        ModOut => open,
        Q => bcd_out(11 downto 8)
    );
    
    -- shift_reg
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                shift_reg <= (others => '0');
            else
                if load='1' then
                    shift_reg <= din;
                else
                    shift_reg <= shift_reg(8 downto 0) & '0';
                end if;
            end if;
        end if;
    end process;
    
    -- Doneを制御する
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                count <= (others =>'0');
            else
                if load='1' then
                    count <= (others => '0');
                elsif unsigned(count) <= 10 then
                    count <= count + 1;
                end if;
            end if;
        end if;
    end process;
    
    done_node <= '1' when count=10 else '0';
    done <= done_node;
end RTL;


これでインプリメントして、インプリメント結果を下に示す。
ame_feb4_1_101030.png

Number of Slice Flip Flopsが26、Number of 4 input LUTsが31、Number of occupied Slicesが17だった。
次に、テストベンチを作った。下に示す。

-- bin2bcd_tb.vhd

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
 
ENTITY bin2bcd_tb IS
END bin2bcd_tb;
 
ARCHITECTURE behavior OF bin2bcd_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT bin2bcd
    PORT(
            clk : in std_logic;
            reset : in std_logic;
            din : in std_logic_vector(9 downto 0);
            load : in std_logic;
            bcd_out : out std_logic_vector(11 downto 0);
            done : out std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
   signal din : std_logic_vector(9 downto 0) := (others => '0');
   signal load : std_logic := '0';

     --Outputs
   signal bcd_out : std_logic_vector(11 downto 0) := (others => '0');
   signal done : std_logic := '0';

   -- Clock period definitions
   constant clk_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: bin2bcd PORT MAP (
          clk => clk,
          reset => reset,
          din => din,
          load => load,
          bcd_out => bcd_out,
          done => done
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin        
        -- hold reset state for 100 ns.
        reset <= '1';
        wait for 100 ns;    
        reset <= '0'; 
        wait for clk_period*10;

        -- insert stimulus here 
        STIMULUS_LOOP : for i in 0 to 1000 loop
            wait until clk'event and clk='1';
            wait for 1 ns;
            din <= CONV_STD_LOGIC_VECTOR(i, 10);
            reset<='1';
            wait until clk'event and clk='1';
            wait for 1 ns;
            load <= '1'; reset<='0';
            wait until clk'event and clk='1';
            wait for 1 ns;
            load <= '0';
            TRANS_WAIT_LOOP : for j in 0 to 9 loop -- 11クロックwait
                wait until clk'event and clk='1';
                wait for 1 ns;
            end loop TRANS_WAIT_LOOP;
        end loop STIMULUS_LOOP;    
        
        wait for clk_period*10;
        assert (false) report "Simulation End!" severity failure;
   end process;

END;


ISimでのシミュレーション結果を下に示す。
ame_feb4_2_101030.png

レイテンシは11クロックだった。

・Sさんに教えていただいた回路
Sさんにブログのコメントで教えていただいた回路をやってみた。
インプリメント結果を下に示す。
fpgaz_1_101030.png

Number of 4 input LUTsが138、Number of occupied Slicesが76だった。
自分でテストベンチを書いた。テストベンチを下に示す。

module bin2bcd_m16_tb;

    // Inputs
    reg [15:0] bin_in;

    // Outputs
    wire [15:0] bcd_out;

    parameter CLK_PERIOD = 10;
    integer i;
    reg clk;

    // Instantiate the Unit Under Test (UUT)
    bin2bcd_m16 uut (
        .bin_in(bin_in), 
        .bcd_out(bcd_out)
    );
    
    always begin // clk
       #(CLK_PERIOD/2)    clk = 1'b1 ;
       #(CLK_PERIOD/2)    clk = 1'b0 ;
    end

    initial begin
        // Initialize Inputs
        bin_in = 0;

        // Wait 100 ns for global reset to finish
        #100;
        
        // Add stimulus here
        for (i=0; i<=1000; i=i+1) begin
            @(posedge clk);
            #1;
            bin_in = i;
        end
        #50;
        $stop;

    end
      
endmodule


シミュレーション結果を下に示す。
fpgaz_2_101030.png

レイテンシは0クロックだ。つまり組み合わせ回路だ。
  1. 2010年10月30日 17:06 |
  2. IP
  3. | トラックバック:0
  4. | コメント:6

コメント

「ame_feb4さんに教えていただいた回路」素晴らしいですね。
ビット数が増えても高クロック周波数で動作しそうですし、
レイテンシーも小さく、サイズも非常にコンパクトで驚きました。

「Sさんの回路」は Spartan3A DSP でインプリメントすると
DSP 回路がうまくはまるため、「使用スライス数」は非常に
小さくなるようでした。が、この回路に DSP を4つ使って
いいかどうかは使用目的次第ですね。

「Sさんに教えていただいた回路」は Spartan3A DSP では
30 MHz 程度まで動作するようでした。かなり複雑そうに
見えるのですが結構いけるものですね。
  1. 2010/10/30(土) 17:44:32 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

武内さん、こんにちは。
いろいろなアルゴリズムがありますね。今回は本当に勉強になりました。皆さんありがとうございました。

# BCD回路は、基本的には人間とのインターフェースだと思うので、あまり高速に動作しなくて良いのではないか?と思います。うちの回路でも表示書き換えは30回/秒です。
  1. 2010/10/30(土) 19:20:46 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

> 人間とのインターフェースだと思うので、あまり高速に動作しなくて良い

その通りですね。
ですので、レイテンシーは大きくても、サイズが小さい方が好まれそうです。

ただ、メインの回路との接続を考えると、ベースクロックはそこそこ
速くないと、相手の回路によっては間にクロック変換回路が必要に
なりそうで、、、あと、できれば多ビットにも容易に対応できる方が?

優先順位は
 記述の単純さ≒汎用性≒回路サイズ≒ベースクロック >> レイテンシー
でしょうか?
  1. 2010/10/30(土) 21:19:30 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

確かにベースクロックはそれなりに動かないと不便ですね。うちでは、25MHzで割り算に25クロック、BCD変換に11クロック、計36クロックかけています。それでも、VGAサイズの画像の圧縮率をパーセントで表すためなので、十分すぎるくらいのレイテンシです。

>記述の単純さ≒汎用性≒回路サイズ≒ベースクロック >> レイテンシー
もう1つ、自分が後で見た時、他人が見た時の可読性を追加したいです。
  1. 2010/10/31(日) 04:27:43 |
  2. URL |
  3. marsee #PU3n2AWw
  4. [ 編集 ]

はい、「記述の単純さ」 は 「可読性」 と書くべきでしたね。

PC上でのソフト開発と違って、可読性だけに特化した書き方ができない
のが、HDL や組み込みソフトの難しいところと感じています。

今自分でやってる回路(初めてのFPGA回路です)ではベースクロックを
100MHz 程度に設定しているため、組み合わせ回路の遅延が(必要以上に?)
気になってしまいます。たとえばクロックが 25MHz 程度のときにどの
くらいの複雑さまで許されるかあたり、経験不足と感じてます。

自分で上記回路を書いたときは、
汎用性(任意ビット数対応) ≧ 回路サイズ≒ベースクロック
                     ≧ 可読性 >> レイテンシー
くらいのつもりだったかもしれません。
  1. 2010/10/31(日) 12:23:18 |
  2. URL |
  3. 武内 #-
  4. [ 編集 ]

了解しました。
>100MHz 程度に設定しているため、組み合わせ回路の遅延が(必要以上に?) 気になってしまいます。
ここが一番悩むところでして、レイテンシを最小にしようとしていると、失敗してもう1段FFを挟まないと、などといつも困っています。一番、悩むところですね。
Cで書いて動作合成してもらえば、パイプライン段数を設定できるのでしょうから、考えなくていいのかな?とか思ってしまいます。どのくらい遅延するのか、よくわからないところが一番のネックですね。

ついついロジックを入れすぎてしまうので、Spartan3シリーズで、100MHzは組み合わせ回路の遅延を考慮せずに作っていると、厳しいかもしれませんね。Virtexシリーズだとだいぶ楽になります。
  1. 2010/10/31(日) 12:35:13 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1630-39e2c7cd
この記事にトラックバックする(FC2ブログユーザー)