FC2カウンター FPGAの部屋 VHDLの書き方

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

FPGAの部屋

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

ある constant の値で、他の constant の値を切り替える5(VHDL編4、XPSプロジェクト、完成)

ある constant の値で、他の constant の値を切り替える4(VHDL編3)”の続き。

今回は、前回の結果を使って、XPSプロジェクトのAdd IPダイアログで解像度を選択して、その解像度のビデオのパラメータをconstant値に設定することを目指す。pure function でそれを行ったのが、”ある constant の値で、他の constant の値を切り替える3(VHDL編2、XPSプロジェクト)”である。今回は、package を使った前回のVHDLコードを使用する。

MPDファイルの RESOLUTION の項を下のように記述した。

PARAMETER RESOLUTION = 1, DT = INTEGER, RANGE = (0:4), VALUES = (0=VGA, 1=SVGA, 2=XGA, 3=SXGA, 4=HD)


このように記述することにより、ダイアログでは、VGA, SVGA... と表示されるが、値としては integer値を VHDL ファイルに渡すことが出来る。

entity を video_timing にしたので、video_timing IP をXPSプロジェクトに追加した。
const2const_11_140313.png

const2const_12_140313.png

video_timing IP のダイアログを出してみた。VGA... などの解像度を選ぶことが出来る。XGAを選択した。
const2const_13_140313.png

ISE14.7でインプリメントまで成功した。
const2const_14_140313.png

ISE14.7をシミュレーションモードにした。ISimを起動してコンパイルを行った。
const2const_15_140313.png

ISimが立ち上がり、XGAの解像度の 1024x768 を表示したので、成功だ。
const2const_16_140313.png

これで、XPSプロジェクトで解像度を選択して、その解像度のパラメータを設定することが出来たので、これからはこれを整備して使用することにする。Verilog HDLでは、ビデオ用の parameter を include することにする。

MPDファイル、PAOファイル、MUIファイルを下に貼っておく。

video_timing_v2_1_0.mpd から下に示す。

BEGIN video_timing

## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION STYLE = HDL
OPTION DESC = video_timing
OPTION LONG_DESC = video_timing test IP
OPTION HDL = VHDL
OPTION RUN_NGCBUILD = FALSE

## Bus Interfaces

## Generics for VHDL or Parameters for Verilog
PARAMETER RESOLUTION = 1, DT = INTEGER, RANGE = (0:4), VALUES = (0=VGA, 1=SVGA, 2=XGA, 3=SXGA, 4=HD)

## Ports
PORT oH_ACTIVE_VIDEO = "", DIR = O, VEC=[10:0]
PORT oV_ACTIVE_VIDEO = "", DIR = O, VEC=[10:0]
END


次に、video_timing_v2_1_0.pao を下に貼っておく。注意点としては、必ず package のVHDLファイルを最初に登録しておかないと、ISimでのシミュレーションでエラーが発生する。

lib video_timing_v1_00_a video_timing_pkg.vhd VHDL
lib video_timing_v1_00_a constant_test3.vhd VHDL


最後に、MUIファイルを貼っておく。

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--
###############################################################################
## DISCLAIMER OF LIABILITY
##
## This file contains proprietary and confidential information of
## Xilinx, Inc. ("Xilinx"), that is distributed under a license
## from Xilinx, and may be used, copied and/or disclosed only
## pursuant to the terms of a valid license agreement with Xilinx.
##
## XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION
## ("MATERIALS") "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
## EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING WITHOUT
## LIMITATION, ANY WARRANTY WITH RESPECT TO NONINFRINGEMENT,
## MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Xilinx
## does not warrant that functions included in the Materials will
## meet the requirements of Licensee, or that the operation of the
## Materials will be uninterrupted or error-free, or that defects
## in the Materials will be corrected. Furthermore, Xilinx does
## not warrant or make any representations regarding use, or the
## results of the use, of the Materials in terms of correctness,
## accuracy, reliability or otherwise.
##
## Xilinx products are not designed or intended to be fail-safe,
## or for use in any application requiring fail-safe performance,
## such as life-support or safety devices or systems, Class III
## medical devices, nuclear facilities, applications related to
## the deployment of airbags, or any other applications that could
## lead to death, personal injury or severe property or
## environmental damage (individually and collectively, "critical
## applications"). Customer assumes the sole risk and liability
## of any use of Xilinx products in critical applications,
## subject only to applicable laws and regulations governing
## limitations on product liability.
##
## Copyright 2009 Xilinx, Inc.
## All rights reserved.
##
## This disclaimer and copyright notice must be retained as part
## of this file at all times.
##
###############################################################################
-->

<!DOCTYPE doc SYSTEM "../../ipdialog.dtd" [
    <!-- -->
    <!ENTITY RESOLUTION '
    <widget id="RESOLUTION">
        <key>RESOLUTION</key>
        <label>RESOLUTION</label>
        <tip></tip>
    </widget>
    '>
]>

<doc>
    <view id="Video Timing">
        <display>Video Timing</display>
        <group id="Video Timing">
            <display>Video Timing</display>
            <item>&RESOLUTION;</item>
        </group>
    </view>
    
</doc>

  1. 2014年03月13日 04:41 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

ある constant の値で、他の constant の値を切り替える4(VHDL編3)

ある constant の値で、他の constant の値を切り替える3(VHDL編2、XPSプロジェクト)”の続き。

前回のやり方で、XPSプロジェクトにカスタムIPを入れるときのAdd IPのダイアログで、解像度を選ぶことが出来るのだが、pure function をビデオのパラメータ分、書くのが面倒で、長い。本文より長くなってしまうこともあるかもしれないので、package にすることを考えた。package にするならば、エレガントな”ある constant の値で、他の constant の値を切り替える1(VHDL編)”を使って、tRESOLUTION を宣言している type宣言部分をinteger としてみた。その、video_timing_pkg.vhd を下に示す。まだテスト用で、同期信号やフロントポーチ、バックポーチなどは設定していない。

package video_timing_pkg is
    subtype RESLUTION_TYPE is integer range 0 to 4;
    type VIDEO_RECORD is record
        H_ACTIVE_VIDEO : integer range 640 to 1920;
        V_ACTIVE_VIDEO: integer range 480 to 1080;
    end record VIDEO_RECORD;
    type VIDEO_RECORD_A is array (RESLUTION_TYPE) of VIDEO_RECORD;
    constant CONST_VIDEO_R : VIDEO_RECORD_A := (
        0 => (H_ACTIVE_VIDEO =>  640, V_ACTIVE_VIDEO =>  480), -- VGA
        1 => (H_ACTIVE_VIDEO =>  800, V_ACTIVE_VIDEO =>  600), -- SVGA
        2 => (H_ACTIVE_VIDEO => 1024, V_ACTIVE_VIDEO =>  768), -- XGA
        3 => (H_ACTIVE_VIDEO => 1280, V_ACTIVE_VIDEO => 1024), -- SXGA
        4 => (H_ACTIVE_VIDEO => 1920, V_ACTIVE_VIDEO => 1080)  -- HD
    );
end package video_timing_pkg;


次に、本体の constant_test3.vhd を下に示す。
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

use work.video_timing_pkg.all;

entity video_timing is
    generic (
        resolution : RESLUTION_TYPE := 1    -- SVGA
    );
    port (
        oH_ACTIVE_VIDEO : out std_logic_vector(10 downto 0);
        oV_ACTIVE_VIDEO : out std_logic_vector(10 downto 0)
    );
begin
end entity video_timing;

architecture RTL of video_timing is
    -- NOTE: Use elab-time constant via generic.
    constant cACTIVE_VIDEO : VIDEO_RECORD := CONST_VIDEO_R(resolution);
    constant H_ACTIVE_VIDEO : integer := cACTIVE_VIDEO.H_ACTIVE_VIDEO;
begin
    -- NOTE: Use run-time parameter via port.
    oH_ACTIVE_VIDEO <= std_logic_vector(TO_UNSIGNED(cACTIVE_VIDEO.H_ACTIVE_VIDEO, 11));
    oV_ACTIVE_VIDEO <= std_logic_vector(TO_UNSIGNED(cACTIVE_VIDEO.V_ACTIVE_VIDEO, 11));
end architecture RTL;


最後に、テストベンチの video_timing_tb.v を下に示す。

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;
 
use work.video_timing_pkg.all;

ENTITY video_timing_tb IS
END video_timing_tb;
 
ARCHITECTURE behavior OF video_timing_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT video_timing
    generic (
      resolution : RESLUTION_TYPE := 1  -- SVGA
    );
 
    PORT(
         oH_ACTIVE_VIDEO : OUT  std_logic_vector(10 downto 0);
         oV_ACTIVE_VIDEO : OUT  std_logic_vector(10 downto 0)
        );
    END COMPONENT;
    

     --Outputs
   signal oH_ACTIVE_VIDEO : std_logic_vector(10 downto 0);
   signal oV_ACTIVE_VIDEO : std_logic_vector(10 downto 0);
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: video_timing generic map (
          resolution => 2   -- XGA
    ) PORT MAP (
          oH_ACTIVE_VIDEO => oH_ACTIVE_VIDEO,
          oV_ACTIVE_VIDEO => oV_ACTIVE_VIDEO
    );

   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      -- insert stimulus here 

      wait;
   end process;

END;


ISE14.7でZynq-7010用にインプリメントしてみたが、問題なかった。
const2const_9_140312.png

シミュレーション波形もXGA解像度になっていて、問題ない。
const2const_10_140312.png
  1. 2014年03月12日 05:30 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

ある constant の値で、他の constant の値を切り替える2(VHDL編)

ある constant の値で、他の constant の値を切り替える1(VHDL編)”の続き。

引き続き、VHDLの達人 hiyuh さんに教えていただいた ある constant値で、他の constant の値を切り替えるの第2段。こちらのほうがエレガントではないそうだ。私もそう思うが、ある理由でこっちを使いたいと思っている。ある constant値が string の場合だ。

constant_test2.vhd を下に示す。達人のVHDLコードを堪能して欲しい。ちなみに、私が加筆させて頂いているが、基本的な流れはそのままだ。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

entity constant_test2 is
    generic (
        RESOLUTION : string := "VGA"
    );
    port (
        oH_ACTIVE_VIDEO : out std_logic_vector(10 downto 0);
        oV_ACTIVE_VIDEO : out std_logic_vector(10 downto 0)
    );
begin
end entity constant_test2;

architecture RTL of constant_test2 is
    pure function fH_ACTIVE_VIDEO (
        iDUMMY : boolean
    ) return integer is
    begin
           if (RESOLUTION =  "VGA") then return  640;
        elsif (RESOLUTION = "SVGA") then return  800;
        elsif (RESOLUTION =  "XGA") then return 1024;
        elsif (RESOLUTION = "SXGA") then return 1280;
        elsif (RESOLUTION =   "HD") then return 1920;
        else                             return 1920;
        end if;
    end function fH_ACTIVE_VIDEO;
    constant H_ACTIVE_VIDEO : integer := fH_ACTIVE_VIDEO(true);

    pure function fV_ACTIVE_VIDEO (
        iDUMMY : boolean
    ) return integer is
    begin
           if (RESOLUTION =  "VGA") then return  480;
        elsif (RESOLUTION = "SVGA") then return  600;
        elsif (RESOLUTION =  "XGA") then return 768;
        elsif (RESOLUTION = "SXGA") then return 1024;
        elsif (RESOLUTION =   "HD") then return 1080;
        else                             return 1080;
        end if;
    end function fV_ACTIVE_VIDEO;
    constant V_ACTIVE_VIDEO : integer := fV_ACTIVE_VIDEO(true);

begin
    oH_ACTIVE_VIDEO <= std_logic_vector(TO_UNSIGNED(H_ACTIVE_VIDEO, 11));
    oV_ACTIVE_VIDEO <= std_logic_vector(TO_UNSIGNED(V_ACTIVE_VIDEO, 11));
end architecture RTL;


ISE14.7によるインプリメントが成功した。問題無さそう。
const2const_3_140309.png

テストベンチを作ってシミュレーションをしてみた。RESOLUTION は SVGA に設定した。
const2const_4_140309.png

下にテストベンチ constant_test2_tb.vhd を示す。

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 constant_test2_tb IS
END constant_test2_tb;
 
ARCHITECTURE behavior OF constant_test2_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT constant_test2 GENERIC(
        RESOLUTION : string := "VGA"
     );
    PORT(
         oH_ACTIVE_VIDEO : OUT  std_logic_vector(10 downto 0);
         oV_ACTIVE_VIDEO : OUT  std_logic_vector(10 downto 0)
    );
    END COMPONENT;
    

     --Outputs
   signal oH_ACTIVE_VIDEO : std_logic_vector(10 downto 0);
   signal oV_ACTIVE_VIDEO : std_logic_vector(10 downto 0);
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: constant_test2 GENERIC MAP(
      RESOLUTION => "SVGA"
   ) PORT MAP (
          oH_ACTIVE_VIDEO => oH_ACTIVE_VIDEO,
          oV_ACTIVE_VIDEO => oV_ACTIVE_VIDEO
   );

   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      -- insert stimulus here 

      wait;
   end process;

END;

  1. 2014年03月09日 05:12 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

ある constant の値で、他の constant の値を切り替える1(VHDL編)

関連するブログ。”ある parameter の値で、他の parameter の値を切り替える(Verilog編)

Verilog HDLは、前回やり方が分かったが、VHDLのやり方が分からなかった。ツィッターでつぶやいたら、VHDLの達人の hiyuh さんが教えてくれた。いつもありがとうございます~。その内のエレガント方のやり方から紹介させて頂こうと思います。

VHDLコードの説明は無いですが、コードを読んでもらえばわかると思います。constant_test.vhd を下に示します。

package ee_pkg is
    type tRESOLUTION is (
         VGA,
        SVGA,
         XGA,
        SXGA,
          HD
    );
    subtype tH_ACTIVE_VIDEO is integer range 640 to 1920;
    type tH_ACTIVE_VIDEO_R is array (tRESOLUTION) of tH_ACTIVE_VIDEO;
    constant cH_ACTIVE_VIDEO_R : tH_ACTIVE_VIDEO_R := (
         VGA =>  640,
        SVGA =>  800,
         XGA => 1024,
        SXGA => 1280,
          HD => 1920
    );
    subtype tV_ACTIVE_VIDEO is integer range 480 to 1080;
    type tV_ACTIVE_VIDEO_R is array (tRESOLUTION) of tV_ACTIVE_VIDEO;
    constant cV_ACTIVE_VIDEO_R : tV_ACTIVE_VIDEO_R := (
         VGA =>  480,
        SVGA =>  600,
         XGA => 768,
        SXGA => 1024,
          HD => 1080        
    );
end package ee_pkg;

use work.ee_pkg.all;

entity ee is
    generic (
        RESOLUTION : tRESOLUTION := XGA
    );
    port (
        oH_ACTIVE_VIDEO : out integer;
        oV_ACTIVE_VIDEO : out integer
    );
begin
end entity ee;

architecture a of ee is
    -- NOTE: Use elab-time constant via generic.
    constant cH_ACTIVE_VIDEO : integer := cH_ACTIVE_VIDEO_R(RESOLUTION);
    constant cV_ACTIVE_VIDEO : integer := cV_ACTIVE_VIDEO_R(RESOLUTION);
begin
    -- NOTE: Use run-time parameter via port.
    oH_ACTIVE_VIDEO <= cH_ACTIVE_VIDEO;
    oV_ACTIVE_VIDEO <= cV_ACTIVE_VIDEO;
end architecture a;


ISE14.7を使用して、Zynq-7010でインプリメント出来るかどうか、確かめてみたところ問題なくインプリメント出来ました。
const2const_1_140308.png

シミュレーションもしてみました。シミュレーション波形を下に示しめす。
const2const_2_140308.png

XGA解像度の1行は1024ピクセル、つまり、2進数で表すと、”10000000000”で、XGA解像度の行数は768行で、2進数で表すと”1100000000”になります。正常に設定できているようです。

テストベンチも下に示します。

package ee_pkg is
    type tRESOLUTION is (
         VGA,
        SVGA,
         XGA,
        SXGA,
          HD
    );
    subtype tH_ACTIVE_VIDEO is integer range 640 to 1920;
    type tH_ACTIVE_VIDEO_R is array (tRESOLUTION) of tH_ACTIVE_VIDEO;
    constant cH_ACTIVE_VIDEO_R : tH_ACTIVE_VIDEO_R := (
         VGA =>  640,
        SVGA =>  800,
         XGA => 1024,
        SXGA => 1280,
          HD => 1920
    );
    subtype tV_ACTIVE_VIDEO is integer range 480 to 1080;
    type tV_ACTIVE_VIDEO_R is array (tRESOLUTION) of tV_ACTIVE_VIDEO;
    constant cV_ACTIVE_VIDEO_R : tV_ACTIVE_VIDEO_R := (
         VGA =>  480,
        SVGA =>  600,
         XGA => 768,
        SXGA => 1024,
          HD => 1080        
    );
end package ee_pkg;

use work.ee_pkg.all;

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 constant_test_tb IS
END constant_test_tb;
 
ARCHITECTURE behavior OF constant_test_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT ee
        generic (
            RESOLUTION : tRESOLUTION
        );
        port (
            oH_ACTIVE_VIDEO : out integer;
            oV_ACTIVE_VIDEO : out integer
        );
    END COMPONENT;
    

     --Outputs
   signal oH_ACTIVE_VIDEO : integer;
   signal oV_ACTIVE_VIDEO : integer;
   -- No clocks detected in port list. Replace <clock> below with 
   -- appropriate port name 
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: ee generic map(
        RESOLUTION => XGA
    ) PORT MAP (
          oH_ACTIVE_VIDEO => oH_ACTIVE_VIDEO,
          oV_ACTIVE_VIDEO => oV_ACTIVE_VIDEO
   );

   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      -- insert stimulus here 

      wait;
   end process;

END;


これで、VHDLでもVGAと入れれば適切な画像パラメータを設定することが出来るはずだ。

(2014/03/09:追加)
hiyuh さんが record(忘れてました。。。)を使ったVHDLコードを教えてくれたので、貼っておきます。

package ee_pkg is
    type tRESOLUTION is (
         VGA,
        SVGA,
         XGA,
        SXGA,
          HD
    );
    type tACTIVE_VIDEO is record
        H : integer range 640 to 1920;
        V : integer range 480 to 1080;
    end record tACTIVE_VIDEO;
    type tACTIVE_VIDEO_R is array (tRESOLUTION) of tACTIVE_VIDEO;
    constant cACTIVE_VIDEO_R : tACTIVE_VIDEO_R := (
         VGA => (H =>  640, V =>  480),
        SVGA => (H =>  800, V =>  600),
         XGA => (H => 1024, V =>  768),
        SXGA => (H => 1280, V => 1024),
          HD => (H => 1920, V => 1080)
    );
end package ee_pkg;

use work.ee_pkg.all;

entity ee is
    generic (
        RESOLUTION : tRESOLUTION := XGA
    );
    port (
        iRESOLUTION   : in  tRESOLUTION;
        oACTIVE_VIDEO : out tACTIVE_VIDEO
    );
begin
end entity ee;

architecture a of ee is
    -- NOTE: Use elab-time constant via generic.
    constant cACTIVE_VIDEO : tACTIVE_VIDEO := cACTIVE_VIDEO_R(RESOLUTION);
begin
    -- NOTE: Use run-time parameter via port.
    oACTIVE_VIDEO <= cACTIVE_VIDEO_R(iRESOLUTION);
end architecture a;

  1. 2014年03月08日 21:31 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

VHDLのmath_realパッケージを使用した sin() と cos() の計算

sin() と cos() の演算を VHDL の math_real パッケージを使用してやってみたので、忘れないようにブログに書いておく。

sin() と cos() の VHDL での表現方法は、符号1ビット、整数部1ビット、小数部8ビットとする。2π/16 の 0 ~ 7 番目までの値を、math_realパッケージを使って real で求めるが、XSTでは、realを扱えないので、固定小数点に変換する。

下にサンプル回路を示す。これは、cos_sel, sin_sel に番号を入力することで、cos(), sin() の求める値を、それぞれ表示する。

-- COS(), SIN() Test (cos_sin_test.vhd)
-- COS(), SIN() 符号1ビット、整数部1ビット、小数部8ビット
-- output は 256倍にしてある

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use ieee.math_real.all;

entity cos_sin_test is
    port(
        cos_sel : in std_logic_vector(2 downto 0);
        sin_sel : in std_logic_vector(2 downto 0);
        cos_output : out std_logic_vector(9 downto 0);
        sin_output : out std_logic_vector(9 downto 0)
    );
end cos_sin_test;

architecture RTL of cos_sin_test is
-- 符号1ビット、整数部1ビット、小数部8ビット
constant cos0_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*0.0/16.0) * 256.0)),10));
constant cos1_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*1.0/16.0) * 256.0)),10));
constant cos2_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*2.0/16.0) * 256.0)),10));
constant cos3_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*3.0/16.0) * 256.0)),10));
constant cos4_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*4.0/16.0) * 256.0)),10));
constant cos5_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*5.0/16.0) * 256.0)),10));
constant cos6_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*6.0/16.0) * 256.0)),10));
constant cos7_16 : std_logic_vector := std_logic_vector(to_signed((integer(cos((2.0*MATH_PI)*7.0/16.0) * 256.0)),10));
constant sin0_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*0.0/16.0) * 256.0)),10));
constant sin1_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*1.0/16.0) * 256.0)),10));
constant sin2_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*2.0/16.0) * 256.0)),10));
constant sin3_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*3.0/16.0) * 256.0)),10));
constant sin4_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*4.0/16.0) * 256.0)),10));
constant sin5_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*5.0/16.0) * 256.0)),10));
constant sin6_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*6.0/16.0) * 256.0)),10));
constant sin7_16 : std_logic_vector := std_logic_vector(to_signed((integer(sin((2.0*MATH_PI)*7.0/16.0) * 256.0)),10));
begin
    process(cos_sel) begin
        case cos_sel is
            when "000" =>    cos_output <= cos0_16;
            when "001" =>    cos_output <= cos1_16;
            when "010" =>    cos_output <= cos2_16;
            when "011" =>    cos_output <= cos3_16;
            when "100" =>    cos_output <= cos4_16;
            when "101" =>    cos_output <= cos5_16;
            when "110" =>    cos_output <= cos6_16;
            when others =>    cos_output <= cos7_16;
        end case;
    end process;
    
    process(sin_sel) begin
        case sin_sel is
            when "000" =>    sin_output <= sin0_16;
            when "001" =>    sin_output <= sin1_16;
            when "010" =>    sin_output <= sin2_16;
            when "011" =>    sin_output <= sin3_16;
            when "100" =>    sin_output <= sin4_16;
            when "101" =>    sin_output <= sin5_16;
            when "110" =>    sin_output <= sin6_16;
            when others =>    sin_output <= sin7_16;
        end case;
    end process;
    
end RTL;


テストベンチを書いてシミュレーションしてみた。テストベンチを下に示す。

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   11:06:54 07/12/2013
// Design Name:   cos_sin_test
// Module Name:   D:/HDL/FndISEWork/Kintex-7/TED_K7/test/cos_sin_test/cos_sin_test_tb.v
// Project Name:  cos_sin_test
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: cos_sin_test
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module cos_sin_test_tb;

    // Inputs
    reg [2:0] cos_sel;
    reg [2:0] sin_sel;

    // Outputs
    wire [9:0] cos_output;
    wire [9:0] sin_output;

    // Instantiate the Unit Under Test (UUT)
    cos_sin_test uut (
        .cos_sel(cos_sel), 
        .sin_sel(sin_sel), 
        .cos_output(cos_output), 
        .sin_output(sin_output)
    );

    initial begin
        $monitor("%h %b %b", cos_sel, cos_output, sin_output);
        
        // Initialize Inputs
        cos_sel = 0;
        sin_sel = 0;

        // Wait 100 ns for global reset to finish
        #100;
        cos_sel = 1;
        sin_sel = 1;
      
        #100;
        cos_sel = 2;
        sin_sel = 2;
      
        #100;
        cos_sel = 3;
        sin_sel = 3;
      
        #100;
        cos_sel = 4;
        sin_sel = 4;
      
        #100;
        cos_sel = 5;
        sin_sel = 5;
      
        #100;
        cos_sel = 6;
        sin_sel = 6;
      
        #100;
        cos_sel = 7;
        sin_sel = 7;
      
        #100;
        // Add stimulus here
    end
    
    initial    $monitor("%h %b %b", cos_sel, cos_output, sin_output);

endmodule


Project Navigator 14.6でプロジェクトを作成して、ISimでシミュレーションを行った。
VHDL_math_real_1_130712.png

出てきた値をExcelで解析してみた。浮動小数点数で計算した cos(), sin() と固定小数点の cos(), sin() では、どのくらいの差があるかを計算で求めた。
VHDL_math_real_2_130712.png

インプリメントも出来た。ピンを配置していないので、BitGenはエラーだったが、インプリメントは成功した。IOを除けば、LUT8個のみを使用している。
VHDL_math_real_3_130712.png

hiyuh さんに教えて頂いたパラメタライズなVHDLコード例を貼っておく。なお、仕様の違いから私が一部修正させて頂いた。
hiyuh さん、教えて頂いてありがとうございました。今後とも宜しく、お願いします。

-- COS(), SIN() Test (cos_sin_test.vhd)
-- COS(), SIN() 符号1ビット、整数部1ビット、小数部8ビット
-- output は 256倍にしてある
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- use ieee.std_logic_misc.all; -- NOTE: std_logic_misc is a legacy POS from Synopsys.
use ieee.math_real.all;
 
entity cos_sin_test is
        -- FIXME: In VHDL-2002, predefined integer should be in [+(2**31)-1, -(2**31)+1] .
        --        To restrict upper bound of SW and OW is worth to consider.
        generic (
                SW : integer range 1 to integer'high :=  3;
                OW : integer range 2 to integer'high := 10
        );
    port(
        -- NOTE: Do not hard code any bit width for future use.
        cos_sel    : in  std_logic_vector(SW-1 downto 0);
        sin_sel    : in  std_logic_vector(SW-1 downto 0);
        cos_output : out std_logic_vector(OW-1 downto 0);
        sin_output : out std_logic_vector(OW-1 downto 0)
    );
begin -- NOTE: Do not be lazy for typing "begin".
end entity cos_sin_test; -- NOTE: Do not be lazy for typing "entity".
 
architecture RTL of cos_sin_test is
-- NOTE: Calculate them into constant LUTs using SW and OW.
        type tLUT is array (0 to 2**SW-1) of std_logic_vector(OW-1 downto 0);
        pure function fCOS_LUT (
                iDUMMY : boolean -- NOTE: Dummy argument for stupid simulator/synthesizer.
        ) return tLUT is
                variable vCOS     : real;
                variable vCOS_LUT : tLUT;
        begin
                F_COS_LUT : for vSEL in tLUT'range loop
                        -- NOTE: Use round for better accuracy.
                        vCOS := round(cos(2.0 * MATH_PI * real(vSEL) / real(2**(SW+1))) * real(2**(OW-2)));
                        -- NOTE: Consider cos(...) = 1.0.
                        -- FIXME: Enlarge OW scheme if you don't like this clamp which produces a bit of
                        --        distortion at specific arguments.
                        vCOS_LUT(vSEL) := std_logic_vector(to_signed(integer(vCOS), OW));
                end loop F_COS_LUT;
                return vCOS_LUT;
        end function fCOS_LUT;
        pure function fSIN_LUT (
                iDUMMY : boolean -- NOTE: Dummy argument for stupid simulator/synthesizer.
        ) return tLUT is
                variable vSIN     : real;
                variable vSIN_LUT : tLUT;
        begin
                F_SIN_LUT : for vSEL in tLUT'range loop
                        -- NOTE: Use round for better accuracy.
                        vSIN := round(sin(2.0 * MATH_PI * real(vSEL) / real(2**(SW+1))) * real(2**(OW-2)));
                        -- NOTE: Consider sin(...) = 1.0.
                        -- FIXME: Enlarge OW scheme if you don't like this clamp which produces a bit of
                        --        distortion at specific arguments.
                        vSIN_LUT(vSEL) := std_logic_vector(to_signed(integer(vSIN), OW));
                end loop F_SIN_LUT;
                return vSIN_LUT;
        end function fSIN_LUT;
        constant cCOS_LUT : tLUT := fCOS_LUT(true);
        constant cSIN_LUT : tLUT := fSIN_LUT(true);
begin
  cos_output <= cCOS_LUT(to_integer(unsigned(cos_sel)));
  sin_output <= cSIN_LUT(to_integer(unsigned(sin_sel)));
end architecture RTL; -- NOTE: Do not be lazy for typing "architecture".

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

std_logic_arith から numeric_std へ2(実践編)

std_logic_arith から numeric_std へ(VHDL)”で、std_logic_arith パッケージから numeric_std パッケージへの移行をしているが、たくさんエラーが出て大変な状況になっている。直しているのは、MT9D111のAXI4インターフェース回路のトップモジュールで、VHDLで書かれている。以前キャラクタをAXI4バス経由でDDR3 SDRAMのフレームバッファに書き込む回路モジュール、char_write_axi_master.vhd を書き換えている。

先ずは、すべての signal はstd_logic かstd_logic_vector で宣言してある。

1.std_logic_arith パッケージでは、if文でのsignalの定数との比較は、下のように書いたが

if write_count=0 and M_AXI_WREADY='1' then -- 終了


numeric_std パッケージでは、こう書いた。

if unsigned(write_count)=0 and M_AXI_WREADY='1' then -- 終了


numeric_std パッケージでは、unsigned と natural の "=" の演算が定義されている。

function "=" (L: UNSIGNED; R: NATURAL) return BOOLEAN;


std_logic_vector の write_count を unsigned に変換して、"=" の右辺の 0 は、naturalに変換して比較する。厳密に型を守って書くと、下の書き方になると思う。

if unsigned(write_count)=natural(0) and M_AXI_WREADY='1' then -- 終了



2.std_logic_arith パッケージでは、下のように書いたが

write_count <= write_count - 1;


numeric_std パッケージでは、こう書いた。

write_count <= std_logic_vector(unsigned(write_count) - 1);


これは、numeric_std パッケージの "-" の演算子が下のように定義されているからだ。

function "-" (L: UNSIGNED;R: NATURAL) return UNSIGNED;


厳密に型を守って書くと、下の書き方になると思う。

write_count <= std_logic_vector(unsigned(write_count) - natural(1));



3.ビット幅を変更する場合は、numeric_std パッケージでは、resize()を使うことができる。resize() はUNSIGNED, SINGED ともにビット幅を変更することが出来る。
使い方はXilinxのアンサーにも書いてある。”11.2 XST - 「ERROR:HDLCompiler:410 - ".vhd" Line xx: Expression has x elements; expected y」というエラー メッセージが表示される”を参照のこと。2つの数を足し算すると、2倍になる可能性があるので、1ピットだけビット幅が増える可能性がある。その時に、足し算する前の数は8ビットだが、足した結果が9ビットの場合に、足し算する前の数を8ビットから、resize() で9ビットにしてから足し算を行なっている。

FPGA BBSで知ったのだがVHDL Math Tricks of the Trade(PDF注意)を貼っておく。

numeric_std パッケージを使う時は、std_logic_vector を使うよりは、unsigned かsigned を使ったほうが良いと思う。
  1. 2012年12月31日 06:23 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0

std_logic_arith から numeric_std へ(VHDL)

VHDLで今までは、下のようにパッケージを呼び出して CONV_INTEGER や CONV_STD_LOGIC_VECTOR を呼び出して変換を行なってきた。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;


遅まきながら、ISEのテンプレートもnumeric_std になったことだし、これからは numeric_std パッケージを使っていこうと思う。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


CONV_INTEGER や CONV_STD_LOGIC_VECTOR に代わるものは何か?と検索すると、Xilinxのアンサー”VHDL で STD_LOGIC_VECTOR を整数に変換する方法”が引っかかった。それによると、CONV_INTEGER は TO_INTEGER に置き換わるそうだ。アンサーは UNSIGNED の時の返り値が INTEGER になっているが、Xilinx\14.4\ISE_DS\ISE\vhdl\src\ieee\numeric_std.vhd では、NATURAL だった。下に示す。

function TO_INTEGER (ARG: UNSIGNED) return NATURAL;
function TO_INTEGER (ARG: SIGNED) return INTEGER;


CONV_STD_LOGIC_VECTOR に代わるものとしては、TO_UNSIGNED と TO_SIGNED があるようだ。

function TO_UNSIGNED (ARG, SIZE: NATURAL) return UNSIGNED;
function TO_SIGNED (ARG: INTEGER; SIZE: NATURAL) return SIGNED;


STD_LOGIC_VECTOR に変換する際には、STD_LOGIC_VECTOR(ARG: UNSIGNED), STD_LOGIC_VECTOR(ARG: SIGNED) とすれば良い。(参考、”unsinedとstd_logic_vector”FPGA BBS)
numeric_std.vhd を見ていると面白い。色々な関数がある。演算子のオーバーロードを見ると、

function "+" (L: UNSIGNED; R: NATURAL) return UNSIGNED;
function "+" (L: NATURAL; R: UNSIGNED) return UNSIGNED;


がある。val + 8 とか大丈夫のようだ。但し、UNSIGNEDなので、すべてSTD_LOGIC_VECTORで定義してある場合は、STD_LOGIC_VECTOR(UNSIGNED(val) + 8) だと思う。
同様にSIGNED も演算子のオーバーロードがある。

function "+" (L: INTEGER; R: SIGNED) return SIGNED;
function "+" (L: SIGNED; R: INTEGER) return SIGNED;


numeric_std.vhd を見ているととっても興味深く面白い。
rem も演算子にあるんだな? mod とどう違うんだろう?

(追加)
ツイッターで教えてもらったのだが、remはremainder,modはmoduloだそうだ。

教えて!goo マイナスの割り算の公式”のNo.3ベストアンサー20pt と”VHDL 基礎”の”関係演算子、加法演算子、乗法演算子、シフト演算子、その他演算子”のmod, rem の項で勉強させてもらった。つまり数直線上で2つの演算子の符号が違っている時に、どちらから元の値に戻るかが違うようだ。
(A mod B) = C とすると |C|< |B|、かつ B と C は同じ符号を取る。
(A rem B) = C とすると |C| < |B|、かつ A と C は同じ符号を取る。
Re: VHDL - Unterschied REM & MOD ?”を参考に例を示す。

7 mod 3 = 1     :3x2 +1 = 7
(-7) mod 3 = 2    :3x(-3) +2 = -7
7 mod (-3) = -2   :(-3)x(-3) -2 = 7
(-7) mod (-3) = -1  :(-3)x2 -1 = -7

7 rem 3 = 1     :3x2 +1 = 7
(-7) rem 3 = -1   :3x(-2) -1 = -7
7 rem (-3) = 1    :(-3)x(-2) +1 = 7
(-7) rem (-3) = -1  :(-3)x2 -1 = -7

  1. 2012年12月25日 05:50 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:0
»