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

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

FPGAの部屋

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

2進数からBCDへの変換回路

必要があって10ビットの2進数から3桁のBCD(Binary-coded decimal)への変換回路を作りました。
私はビットごとに+6補正を入れながら、足していきました。変換するに11クロックです。
変換クロックに余裕があれば、BCDカウンタとバイナリカウンタ2つ作って、両方をカウントアップしていって、バイナリカウンタと10ビットの2進数が同じになったところの、BCDカウンタの値を使っても良いと思います。
武内さんから、10のn乗で割っていく方式を教えてくださいました。ありがとうございました。
自分のVHDLコードもブログに貼っておきます。

#使いものにならないよ。どうしてこんなコードを書いたの?とか、厳しい御指導があるかと思いますが、どうぞお手柔らかにお願いします。

-- Binary to Decimal Test

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity binary_decimal_test is
    port(
        clk : in std_logic;
        reset : in std_logic;
        complete : in std_logic;
        latched_quotient : in std_logic_vector(9 downto 0);
        persent : out std_logic_vector(11 downto 0)
    );
end binary_decimal_test;

architecture RTL of binary_decimal_test is
signal persent_node : std_logic_vector(11 downto 0);
type binary_decimal_state is (idle_bds, state_0, state_1, state_2, state_3, state_4, state_5, state_6, state_7, state_8, state_9, state_10, val_valid);
signal cs_bds : binary_decimal_state;
type complete_state is (idle_comp, divide_complete);
signal cs_div : complete_state;
begin
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_div <= idle_comp;
            else
                case cs_div is
                    when idle_comp =>
                        if complete='1' then
                            cs_div <= divide_complete;
                        end if;
                    when divide_complete =>
                        cs_div <= idle_comp;
                end case;
            end if;
        end if;
    end process;
    
    -- 2進化10進用ステートマシン
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_bds <= idle_bds;
            else
                case cs_bds is
                    when idle_bds =>
                        if cs_div = divide_complete then
                            if unsigned(latched_quotient)>999 then -- 999以上は999と表示する
                                cs_bds <= state_9;
                            else
                                cs_bds <= state_0;
                            end if;
                        end if;
                    when state_0 =>
                        cs_bds <= state_1;
                    when state_1 =>
                        cs_bds <= state_2;
                    when state_2 =>
                        cs_bds <= state_3;
                    when state_3 =>
                        cs_bds <= state_4;
                    when state_4 =>
                        cs_bds <= state_5;
                    when state_5 =>
                        cs_bds <= state_6;
                    when state_6 =>
                        cs_bds <= state_7;
                    when state_7 =>
                        cs_bds <= state_8;
                    when state_8 =>
                        cs_bds <= state_9;
                    when state_9 =>
                        cs_bds <= state_10;
                    when state_10 =>
                        cs_bds <= val_valid;
                    when val_valid => -- present_nodeの値が有効
                        cs_bds <= idle_bds;
                end case;
            end if;
        end if;
    end process;
    
    -- 10進数変換用のテーブル
    
    -- 割り算で導き出したパーセンテージを10進にする
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                persent_node <= (others => '0');
            else
                case cs_bds is
                    when state_0 =>
                        if latched_quotient(0)='1' then
                            persent_node <= "000000000001";
                        else
                            persent_node <= (others => '0');
                        end if;
                    when state_1 => 
                        if latched_quotient(1)='1' then
                            persent_node <= persent_node + 2;
                        else
                            persent_node <= persent_node;
                        end if;
                    when state_2 =>
                        if latched_quotient(2)='1' then
                            persent_node <= persent_node + 4;
                        else
                            persent_node <= persent_node;
                        end if;
                    when state_3 =>
                        if latched_quotient(3)='1' then
                            persent_node <= persent_node + 8;
                        else
                            persent_node <= persent_node;
                        end if;
                    when state_4 =>
                        if unsigned(persent_node(3 downto 0))>9 then -- 前までの総計15
                            if latched_quotient(4)='1' then
                                persent_node <= persent_node + x"01C"; -- +6+16
                            else
                                persent_node <= persent_node + x"006"; -- +6
                            end if;
                        else
                            if latched_quotient(4)='1' then 
                                persent_node <= persent_node + x"016";
                            else
                                persent_node <= persent_node;
                            end if;
                        end if;
                    when state_5 =>
                        if unsigned(persent_node(3 downto 0))>9 then -- 前までの総計は31
                            if latched_quotient(5)='1' then
                                persent_node <= persent_node + x"038"; -- +6+32
                            else
                                persent_node <= persent_node + x"006"; -- +6
                            end if;
                        else
                            if latched_quotient(5)='1' then 
                                persent_node <= persent_node + x"032";
                            else
                                persent_node <= persent_node;
                            end if;
                        end if;
                    when state_6 =>
                        if unsigned(persent_node(3 downto 0)) >9 then -- 前までの総計は63
                            if latched_quotient(6)='1' then
                                persent_node <= persent_node + x"06A"; -- +6+64
                            else
                                persent_node <= persent_node + x"006"; -- +6
                            end if;
                        else
                            if latched_quotient(6)='1' then 
                                persent_node <= persent_node + x"064";
                            else
                                persent_node <= persent_node;
                            end if;
                        end if;
                    when state_7 => -- 前までの総計は127
                        if unsigned(persent_node(3 downto 0)) >9 then
                            if unsigned(persent_node(7 downto 4)) >9 then
                                if latched_quotient(7)='1' then
                                    persent_node <= persent_node + x"18E"; -- +6+60+128=18E
                                else
                                    persent_node <= persent_node + x"066"; -- +6+60
                                end if;
                            else -- +6補正のみ
                                if latched_quotient(7)='1' then
                                    persent_node <= persent_node + x"12E"; -- +6+128
                                else
                                    persent_node <= persent_node + x"006"; -- +6
                                end if;
                            end if;
                        else
                            if unsigned(persent_node(7 downto 4)) >9 then
                                if latched_quotient(7)='1' then
                                    persent_node <= persent_node + x"188"; -- +60+128=18E
                                else
                                    persent_node <= persent_node + x"060"; -- +60
                                end if;
                            else
                                if latched_quotient(7)='1' then
                                    persent_node <= persent_node + x"128"; -- +128
                                else
                                    persent_node <= persent_node;
                                end if;
                            end if;
                        end if;
                    when state_8 => -- 前までの総計は255
                        if unsigned(persent_node(3 downto 0)) >9 then
                            if unsigned(persent_node(7 downto 4)) >9 then
                                if latched_quotient(8)='1' then
                                    persent_node <= persent_node + x"2BC"; -- +6+60+256=2BC
                                else
                                    persent_node <= persent_node + x"066"; -- +6+60
                                end if;
                            else -- +6補正のみ
                                if latched_quotient(8)='1' then
                                    persent_node <= persent_node + x"25C"; -- +6+256
                                else
                                    persent_node <= persent_node + x"006"; -- +6
                                end if;
                            end if;
                        else
                            if unsigned(persent_node(7 downto 4)) >9 then
                                if latched_quotient(8)='1' then
                                    persent_node <= persent_node + x"2B6"; -- +60+256=2B6
                                else
                                    persent_node <= persent_node + x"060"; -- +60
                                end if;
                            else
                                if latched_quotient(8)='1' then
                                    persent_node <= persent_node + x"256"; -- +256
                                else
                                    persent_node <= persent_node;
                                end if;
                            end if;
                        end if;
                    when state_9 => -- 前までの総計は511
                        if unsigned(latched_quotient)>999 then -- 999よりも大きい
                            persent_node <= "100110011001"; -- 999
                        else
                            if unsigned(persent_node(3 downto 0)) >9 then
                                if unsigned(persent_node(7 downto 4)) >9 then
                                    if latched_quotient(9)='1' then
                                        persent_node <= persent_node + x"578"; -- +6+60+512=578
                                    else
                                        persent_node <= persent_node + x"066"; -- +6+60
                                    end if;
                                else -- +6補正のみ
                                    if latched_quotient(9)='1' then
                                        persent_node <= persent_node + x"518"; -- +6+512
                                    else
                                        persent_node <= persent_node + x"006"; -- +6
                                    end if;
                                end if;
                            else
                                if unsigned(persent_node(7 downto 4)) >9 then
                                    if latched_quotient(9)='1' then
                                        persent_node <= persent_node + x"572"; -- +60+512=572
                                    else
                                        persent_node <= persent_node + x"060"; -- +60
                                    end if;
                                else
                                    if latched_quotient(9)='1' then
                                        persent_node <= persent_node + x"512"; -- +512
                                    else
                                        persent_node <= persent_node;
                                    end if;
                                end if;
                            end if;
                        end if;
                    when state_10 => -- 10進補正のみ
                            if unsigned(persent_node(3 downto 0)) >9 then
                                if unsigned(persent_node(7 downto 4)) >9 or (unsigned(persent_node(3 downto 0)) >9 and unsigned(persent_node(7 downto 4))=9) then -- 桁が上がって2桁目がAになる時も+66補正をする
                                    persent_node <= persent_node + x"066"; -- +6+60
                                else -- +6補正のみ
                                    persent_node <= persent_node + x"006"; -- +6
                                end if;
                            else
                                if unsigned(persent_node(7 downto 4)) >9 then
                                    persent_node <= persent_node + x"060"; -- +60
                                else
                                    persent_node <= persent_node;
                                end if;
                            end if;
                    when others =>
                        persent_node <= persent_node;
                end case;
            end if;
        end if;
    end process;
   
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                persent <= (others => '0');
            else
                if cs_bds=val_valid then
                    persent <= persent_node;
                end if;
            end if;
        end if;
    end process;
            
end RTL;



テストベンチのVHDLコードも下に貼っておきます。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
 
ENTITY binary_decimal_test_tb IS
END binary_decimal_test_tb;
 
ARCHITECTURE behavior OF binary_decimal_test_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT binary_decimal_test
    PORT(
         clk : IN  std_logic;
         reset : IN  std_logic;
         complete : IN  std_logic;
         latched_quotient : IN  std_logic_vector(9 downto 0);
         persent : OUT  std_logic_vector(11 downto 0)
        );
    END COMPONENT;
    

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

     --Outputs
   signal persent : std_logic_vector(11 downto 0);

   -- Clock period definitions
   constant clk_period : time := 40 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: binary_decimal_test PORT MAP (
          clk => clk,
          reset => reset,
          complete => complete,
          latched_quotient => latched_quotient,
          persent => persent
        );

   -- 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;
            latched_quotient <= CONV_STD_LOGIC_VECTOR(i, 10);
            complete <= '1';
            wait until clk'event and clk='1';
            wait for 1 ns;
            complete <= '0';
            TRANS_WAIT_LOOP : for j in 0 to 10 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;


このVHDLコードをISE12.3、Spartan3E-500でインプリメントしたところ、60スライス、91LUTでした。
binary_decimal_101027.png
  1. 2010年10月27日 10:59 |
  2. IP
  3. | トラックバック:0
  4. | コメント:4

コメント

こんばんは
おもしろそうなテーマですね。
私ならどうするか考えてみました。
こんな感じですかね。。
パイプライン式でLatencyは3です。

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
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
  1. 2010/10/27(水) 23:37:17 |
  2. URL |
  3. S #-
  4. [ 編集 ]

すみません、
RTLのペーストを2回してしまったようです。
  1. 2010/10/27(水) 23:40:33 |
  2. URL |
  3. S #-
  4. [ 編集 ]

Sさん、こんにちは。
コンパクトなコードありがとうございました。後でシミュレーションしてみます。
  1. 2010/10/28(木) 12:05:45 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

こんばんは。
こういうアルゴリズムもあるようですね。
<http://www.fpgaz.com/wiki/doku.php?id=fpgaz:fpga:bin2bcd>
感動ものです。
  1. 2010/10/29(金) 20:22:13 |
  2. URL |
  3. S #-
  4. [ 編集 ]

コメントの投稿


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

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