FC2カウンター FPGAの部屋 2010年12月17日
FC2ブログ

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

FPGAの部屋

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

VHDLによる乗算について(ISE12.3のXSTを使用)

VHDLで乗算記号*を使ったときに、どのようになるのかが、よくわからなかったので試してみた。その覚書です。特にunsigned とsignedを掛けたときにどうなるのか?std_logic_vector同士をそのまま掛けたらsignedとして扱ってくれるのか?よくわからなかった。

さて早速試してみたい。まずはテストベンチから示す。これは変更することがないので、最初に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY mult_test_tb IS
END mult_test_tb;
 
ARCHITECTURE behavior OF mult_test_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT mult_test
    PORT(
         clk : IN  std_logic;
         reset : IN  std_logic;
         ina : IN  std_logic_vector(8 downto 0);
         inb : IN  std_logic_vector(8 downto 0);
         mult_out : OUT  std_logic_vector(17 downto 0)
        );
    END COMPONENT;
    

   --Inputs
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
   signal ina : std_logic_vector(8 downto 0) := (others => '0');
   signal inb : std_logic_vector(8 downto 0) := (others => '0');

     --Outputs
   signal mult_out : std_logic_vector(17 downto 0);

   -- Clock period definitions
   constant clk_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: mult_test PORT MAP (
          clk => clk,
          reset => reset,
          ina => ina,
          inb => inb,
          mult_out => mult_out
        );

   -- 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 
        ina <= "000000010";
        inb <= "000000011";
        
        wait for 450 ns;
        
        ina <= "000000011";
        inb <= "111111111";

      wait;
   end process;

END;


最初に2と3を掛ける。次にsignedだったら3と-1を掛けている。
最初は、ただ単にinaとinbを掛ける。

-- mult test

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

entity mult_test is
    port (
        clk : in std_logic;
        reset : in std_logic;
        ina : in std_logic_vector(8 downto 0);
        inb : in std_logic_vector(8 downto 0);
        mult_out : out std_logic_vector(17 downto 0)
    );
end mult_test;

architecture RTL of mult_test is
begin
    process(clk)
    begin
        if clk'event and clk='1' then
            if reset='1' then
                mult_out <= (others => '0');
            else
                mult_out <= ina * inb;
            end if;
        end if;
    end process;
end RTL;


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

2*3=6(110)は良いとして、3*(-1)は、unsignedとして演算されているようだ。これは、ライブラリに”use ieee.std_logic_unsigned.all”をしているので当然かも知れない? ”use ieee.std_logic_signed.all”に書き換えたときのシミュレーション結果を下に示す。
mult_2_101217.png

2*3=6(110)は当然同じだが、3*(-1)は2の補数表示で-3になっている。
次にxc6slx45t-3fgg484でインプリメントしてみた。Spartan-6のLX45Tだ。
最初に、ライブラリが”use ieee.std_logic_unsigned.all”の方から、DSP48に掛け算が割り当てられている。DSP48の入力ピンを下に示す。
mult_3_101217.png

ina, inbとも9ビット目まで入力ピンが入っていて、その他はGNDになっている。

次に、ライブラリが”use ieee.std_logic_signed.all”のとき。
やはり、DSP48に掛け算が割り当てられている。DSP48の入力ピンを下に示す。
mult_4_101217.png

ina, inbとも9ビット目までは、unsignedの時と同じだが、10ビット目以降は、GNDではなく、それぞれの9ビット目のピンに接続されている。符号拡張が行われている。

ちなみに出来れば、inaはunsignedで、inbはsignedだと一番都合が良いのだが。。。それでやってみた。
ライブラリが”use ieee.std_logic_signed.all”のときに、掛け算の気球つ部分を以下の式に取り替えた。

mult_out <= unsigned(ina) * signed(inb);


最初に、シミュレーションをしてみた。
mult_5_101217.png

完全に値がおかしい。
インプリメントすると下のエラーが出た。

ERROR:HDLCompiler:410 - "\HDL\FndISEWork\DWM2008_07\Graphic_board2\test\mult_test\Synth123\../mult_test.vhd" Line 32: Expression has 19 elements ; expected 18


19ビットにしないとダメみたいだ。ということはunsignedの方に1ビット付け足すのかな?
今まで9ビット長だったinaをすべて8ビット長にして確かめてみたところ(inbは9ビット長)、シミュレーションは正常になった。
mult_6_101217.png

インプリメントした結果のDSP48のピン割り当てを下に示す。
mult_7_101217.png

unsignedのinaは8ビット目までDSP48のピンに割り当てられていて、それ以上はGNDに接続されている。signedのinbは9ビット目まで割り当てられていて、それ以上はすべてinbの9ビット目に接続されている(符号拡張)。
これで目的は果たすことができそうだ。

更にintegerで書いてみた。

    process(clk)
        variable i, j, k : integer := 0;
    begin
        if clk'event and clk='1' then
            if reset='1' then
                mult_out <= (others => '0');
            else
                i := CONV_INTEGER(unsigned(ina));
                j := CONV_INTEGER(signed(inb));
                k := i * j;
                mult_out <= CONV_STD_LOGIC_VECTOR(k, 18);
            end if;
        end if;
    end process;


シミュレーションもインプリメントも”mult_out <= unsigned(ina) * signed(inb);”と同じで正常だった。

(2010/12/21:追加)
片方が定数の場合は、下の式ではエラーだった。

mult <= unsigned(ina) * signed("111110000");


std_logic_vectorのsignalを宣言して、それに代入してからsignedでキャストする。

signal temp : std_logic_vector(8 downto 0);
begin
    temp <= "111110000";
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                mult <= (others => '0');
            else
                mult <= unsigned(ina) * signed(temp);
            end if;
        end if;
    end process;

  1. 2010年12月17日 15:58 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:4